Showing posts with label Verilog. Show all posts
Showing posts with label Verilog. Show all posts

Monday, June 3, 2024

Testing the Instruction Pointer board

My project for April and May was to extend my PicoBlaze-based test framework to test the Instruction Pointer board I built in 2012. I also wanted to update the desktop computer in my electronics lab.

I'd completed the Verilog implementation of the i4004 CPU at about the same time I assembled the IP board, so the obvious way to test it was to strip out the parts of the Verilog that implemented the instruction pointer, and let the IP board perform that function. It seemed to work, but later, when I attempted to run the i4004 Clock program on the hybrid setup, it wasn't stable. Sometimes it would run, and sometimes it wouldn't. I wasn't sure why, but I didn't have a way to capture the failure for analysis.

Monday, February 26, 2024

Internal data bus pre-charging

I "discovered" an interesting feature in the i4004 internal data bus management this weekend. Maybe the rest of you already discovered this, but it's new to me.

With the Scrachpad Register board working with my test program, I decided to mate it with the Instruction Pointer board I built in 2012. One of my goals was to see if the CLK1 and CLK2 circuits would ring, or if the rise and fall times are slow enough to avoid problems. To my great relief, I see no significant undershoot or overshoot on these circuits, and no ringing at all. Whew!

However, my logic analyzer showed some suspicious timing on the internal data bus. At first it wasn't clear to me what was happening, so I probed around a bit with my oscilloscope. As I was making notes of my observations I realized what was happening, and this also explained a bit of circuitry in the original chip I didn't previously understand.

Monday, January 3, 2022

OpenCores project download failures

It appears the MCS-4 project download link on the OpenCores site points to a tarball created in 2019. I've emailed the OpenCores site maintainers to alert them, but I don't know how long it will take them to correct the problem.

In the meantime, I've created my own tarball of these sources and placed it on Google Drive:

Download link: mcs-4_20220103.tar.gz
File size: 1456944 bytes
MD5 checksum: e2ee2aa03b7dfefd5f10d3e2a6323889

Thursday, December 2, 2021

Big Verilog source update on OpenCores.org

November 15th, 2021, marked the 50th anniversary of the release of the MCS-4 chipset. I figure this is as good a time as ever to update my MCS-4 project on OpenCores.

 Here's a summary of the changes:

  • Created subdirectories under rtl/verilog for each of the four initial MCS-4 chips. 
  • Moved the i4004 CPU-specific Verilog module files into the i4004 subdirectory.
  • Updated the i4004 CPU Verilog modules with a few bugfixes.
  • Published Verilog modules for the i4001 ROM, i4002 RAM, and i4003 Shift Register chips.

These are the Verilog sources I used in my Busicom 141-PF re-creation using a gutted Canon P170-DH calculator, so I'm pretty sure they work correctly.

Let me know if you find these files useful, or if you find what you think is a bug.

 

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License

Wednesday, July 29, 2020

Running the Busicom software in a Spartan-6

Eight years ago I decided I wanted to learn about programmable logic: PLAs, CPLDs, and FPGAs.

About the same time, I became aware that a group of engineers and computer history buffs had gotten Intel to release the schematics for first commercially-available microprocessor: the Intel 4004 CPU. They'd also retrieved the software that drove the first commercial product that used the i4004: the Busicom 141-PF.

I decided to re-create the i4004 CPU in an FPGA.

It turns out that's a lot like learning to swim by attempting to cross the English channel. But I've never been known to shy away from a challenge.

Sunday, July 19, 2020

More latching mux timing problems

As I mentioned in the previous post, my timing problems seemed to be related to the timing between the output of a mux and the latch intended to capture the output of the mux. Here's a simpler example.

This is the mux in the instruction pointer that determines whether the Effective Address Counter or the Refresh Counter is used to select the active DRAM row. Counting from the top left, the first two signals are the mux selector inputs: the subcycle X12 and X32 signals. The middle pair are the Refresh Counter outputs, and the right-most pair are the Effective Address Counter outputs.

During subcycles X12 and X22, a DRAM row is read and written back unmodified to refresh the row. Thus the Refresh Counter outputs are selected to drive the DRAM row decoder at the beginning of subcycle X12. For the rest of the instruction cycle the Effective Address counter needs to drive the DRAM row decoder, so it is selected at the beginning of subcycle X32.

Rather than have the selected counter actively drive the decoder continuously, this is a latching mux: when the selector signals are inactive, the previously-selected counter outputs are latched.

Friday, July 17, 2020

Latch timing failure

I think I found the problem in the i4004 CPU instruction pointer incrementer. And it doesn't bode well for the latch-based implementation.

Here's the problem. The instruction pointer DRAM is configured as four rows of 12 bits, each row representing one of the four instruction pointers. The normal cycle is:
  1. Pre-charge the DRAM column sense lines.
  2. Read all 12 bits of the active IP into a 12-bit register.
  3. Gate the low-order 4 bits onto the data bus.
  4. Add 1 to the low 4 bits, saving the carry out.
  5. Update the low 4 bits of the register.
  6. Gate the middle 4 bits onto the data bus.
  7. Add the carry to the middle 4 bits, saving the carry out.
  8. Update the middle 4 bits of the register.
  9. Gate the high 4 bits onto the data bus.
  10. Add the carry to the high 4 bits.
  11. Update the high 4 bits of the register.
  12. Write the 12-bit register back to the active IP.
Here's what Step 5 looks like in behavioral simulation. On the bottom we have the least significant bit output of the adder. The short (400ns) pulse in the middle is the write enable for the low 4 bits of the 12-bit register. Above that is the LSB of the 12-bit register itself.

Next let's look at the post-map simulation with the same arrangement of signals. The LSB of the adder becomes a 1 much later than in the behavioral simulation, and goes back to a 0 much sooner. How much sooner?

Here's the same post-map simulation, zoomed in at the falling edge of the write-enable. The adder output falls 25ps (that's picoseconds, or 0.000000000025 seconds) before the gate enable goes inactive, but that's long enough for the latch to capture a zero rather than a one. Bummer.

The problem appears to be in the way I've coded the 12-bit temporary register. This register (really charges on MOSFET inverter gates in a real i4004 CPU) is written from three non-overlapping sources. Because of the way the circuitry is implemented, any of these three can set the register content without conflict.

In an FPGA, this is implemented using a mux to select an input source and a storage element to retain the value. Since I coded the input selection logic as implemented in the real i4004 CPU, the mux selectors and the latch gate are driven by the same signals. In this case, though, the mux output is changing 25 picoseconds before the latch gate has gone inactive, and the latch captures the wrong value. This is why most modern logic uses clocked flip-flops rather than latches.

The challenge I face is to separate the mux selectors from the latch gates such that the mux outputs are stable before and after the latch is enabled. This is turning out to be non-trivial.

Thursday, July 16, 2020

Xilinx ISE iSim simulation modes

I've been doing some research into the various levels of simulation available using the Xilinx ISE toolchain and simulator. All of my simulation to this point had been at the behavioral level. I knew it was possible to simulate ASICs that had been designed using Verilog at the component level, but I'd never had need to look into this as behavioral simulation had been sufficient.

My research showed that using the Xilinx ISE toolchains, a design can be simulated in any of five stages along the way from HDL to loadable bit file:

Wednesday, July 15, 2020

Fixing combinational loops

As part of the conversion from edge-clocked flip-flops to transparent data latches I re-coded my i4004 counter module. This resulted in several warnings about combinational loops, but those warnings were buried in a sea of warnings about my use of data latches. It seemed to work well enough when implemented for the Spartan-3E, and I assumed it would work well enough on the Spartan-6.

I was wrong.

Monday, June 29, 2020

More bugs in the i4004 CPU emulation

I knew there was at least one lingering bug in the emulated i4004 CPU because I didn't see the contents of the OPA "register" output on the data bus during the X1 subcycle. But apparently the problems are bigger than that.

In my all-in test of the Busicom 141‑PF reconstruction, I noted several problems. To try and isolate the problem to one of the four emulated MCS-4 chips I decided I needed to test each of the emulated chips separately, starting with the i4001 ROM.

Wire, Tri, and Wor

Earlier today I cleaned up the VFD driver and the keypad remapping code so it was consistent with the rest of this project's code, and updated the top module for my P170-DH rebuild. Behavioral simulations ran fine, and synthesis and implementation gave only the expected warnings, so I decided to load it into the hardware and see how it ran.

At first I was pretty happy. The VFD displayed a single zero in the right-most digit, with the decimal point illuminated to just the right of the zero. The VFD driver reads the WR register, which is stored in RAM 0 register 1, via a dual-port interface to the RAM. Since an i4002 RAM clears itself to zeros while the reset input is asserted, this is what it should display. Unfortunately, that was the last part that worked as expected.

Saturday, June 27, 2020

First-Word Fall-Through FIFOs

Basic AXI Handshake protocol
Sometimes an engineer will see a technique on a website or in a document and think, "Wow! That's a good way to do that!" Such is what happened when I came across the AXI style handshake described in this Wikipedia article. I'd been looking for a good way for the M-32TL translator and printer modules to synchronize, and this seemed like a simple and well-tested mechanism.

This led me to consider the interface on the other side of the translator module, which is intended to talk to a FIFO. When I'd originally coded the translator I used a standard FIFO generated using ISE Coregen, figuring that was the best way to make sure the FIFO worked properly and was implemented efficiently. After discovering the AXI handshake I decided to re-implement it to use a First-Word Fall-Through FIFO because that allowed me to use the AXI handshake on both sides. Again I used Coregen.

If I wanted to run simulations using Icarus Verilog, though, I needed an alternative to a Coregen-constructed FIFO. Then I noticed that the Coregen FIFO used 27 slices for a 64 by 4-bit, common-clock FIFO. And I started looking at other FIFO implementations.

Friday, June 26, 2020

Translating EP102 codes to M-32TL codes

After recoding my EP102 printer emulation to send a stream of print drum sector numbers into the print buffer FIFO, I needed to develop some sort of translator to take those sector numbers and convert them to M-32TL print wheel sector numbers that the M-32TL printer driver could swallow.

This turned out to be harder than I expected.

Monday, June 15, 2020

Reworking the EP102 emulation

A few months ago I designed, coded, and started testing a Verilog module to emulate the EP102 printer found in the Busicom 141-PF calculator. I wrote a bit about it in the post EP-102 to M-32TL Glue logic

The EP102 is a drum printer capable of printing one of 13 characters in each of 17 columns.  When a row of characters is properly aligned for printing, the printer sends a "sector" signal to the computer. To allow the printer to identify which row is aligned for printing, a second "index" signal is sent when the first row is aligned. To print a given character, the computer waits until it sees the sector signal indicating that character is aligned for printing, then sends a signal to the printer that causes a mechanical hammer to press the paper against the drum. It thus takes one full rotation of the drum to print all the columns of that line.

My first task was to code a module that generates the print drum index and sector signals for the calculator, while tracking the active sector number. Since the sector number ranges from 0 to 12, it's represented by a 4-bit value.

Tuesday, May 26, 2020

The i4003 Shift Register

Intel 4003 shift register
The last of the original MCS-4 chips I need to emulate for the Busicom 141-PF re-creation is the i4003 shift register. I expected this to be simple: it's a 10-bit shift register with a clock input, a serial input, a serial output, 10 parallel outputs, and a parallel output enable input. How complex could this be?

In my mind I was picturing one Verilog always block for the shift register and a continuous assignment statement for the output enables. Four lines of code plus the module definition.

As it turns, the i4003 shift register is a more complicated chip than I expected.

Friday, May 22, 2020

i4001 data bus output timing

The next thing I wanted to try was to run the MCS-4 Digital Clock using the Instruction Pointer board I built in 2012.


In theory, all I should need to do is pull the Verilog IP module out of the clock project and replace it with the interface to the IP board. When I tried it, though, it didn't work.

Tuesday, May 19, 2020

XST conditional synthesis with Verilog generate

One of the purposes of creating my MCS-4 Digital Clock was to come up with something that would run on my hybrid debugging setup and give a clear indication of proper operation. This setup is the Digilent Spartan-3E Starter reference board connected to an expansion card that serves as a carrier for my i4004 CPU boards. This allows me to run the as-yet unimplemented parts of the i4004 CPU in the Spartan-3E FPGA.

Wednesday, May 13, 2020

An MCS-4 Digital Clock

Who needs yet another digital clock? Haven't we all done this before?


I did something like this in PIC-16 assembly language when I first connected my Microchip PICDEM-2 reference board to an LCD in 1999. (Anyone need a UV EPROM eraser?) I did it again in Verilog when I bought this Digilent Spartan-3E Starter board in 2009. But this digital clock is special: it's written in Intel MCS-4 Assembly language, and it's running on my emulation of an Intel 4004 CPU.

Monday, May 11, 2020

i4001 ROM emulation refactoring

This weekend I worked on the i4001 emulation, bringing the quick hack I did years ago closer to the operation of the actual chip. While doing this I've been wrestling with two conflicting objectives: making the emulation conform as closely as possible to the real i4001, while also using the hardware resources available in the Spartan-6 FPGA efficiently.


Tuesday, May 5, 2020

Another bug? I FIN you not

The FIN instruction is supposed to fetch the contents of the ROM location specified by the scratchpad R0R1 register pair, and store those contents into another scratchpad register pair. Obviously this didn't work properly or I wouldn't be writing about it.