Sunday, May 3, 2020

Debugging the i4004 emulation

I had fantasies of just quickly hacking up the i4001 ROM and i4002 RAM emulations and loading the full Busicom 141-PF into my P170-DH board to see if it would run, but I've been an engineer for way too long to do that. Instead I've been plodding along, coding and testing each step of the way.

I'm not quite finished with the peripheral chips, but I felt good enough about their current state to finally start a simulation of a i4004 CPU connected to a i4001 ROM and a i4002 RAM in the Xilinx iSim simulator. For a test program I used the sample code that is loaded by default into Lagos Kintli's i4004 analyzer.

The first problem I noticed was that the data bus is High-Z during the X1 and X3 subcycles of execution, while the data sheets indicate that the CPU should be driving the bus during these phases.

This screenshot of the iSim waveform output shows my i4004 emulation fetching 0xD6 (an LDM 6 instruction) from ROM address 0x00D. The solid yellow marker is positioned between the end of subcycle M2 and the start of subcycle X1. The documentation says that during subcycle X1 the CPU should be driving the bus with the OPA value (0x6). Instead, the bus is floating:


Here's the section of code being executed:
00D: D6     LDM  6       ;Load data into accumulator
00E: 14 13  JCN  Z,13    ;Jump conditional: should not jump
010: 1C 13  JCN  NZ,13   ;Jump conditional: should jump
012: 66     INC  R6      ;Increment register
013: F0     CLB          ;Clear both (accumulator and carry)
014: 1C 19  JCN  NZ,19   ;Jump conditional: should not jump
016: 14 19  JCN  Z,19    ;Jump conditional: should jump
018: 66     INC  R6      ;Increment register
019:
The next problem is that conditional jumps appear to be broken: it always jumps. Immediately after loading 0x6 into the accumulator the Z flag should be clear; the JCN on the Z flag at 0x00E should not jump to location 0x013, but it does. The CLB instruction at 0x013 should set the Z flag; the JCN at 0x014 should not jump, but it does. This pattern is also true for conditional jumps on the C (carry) flag.

Bummer. I guess I'll have to dig into the Verilog i4004 code again. The last time I looked at it was in November 2012.

I've already found an error in the coding of the Condition Flip-Flop triggering code, but now it looks like there may also be a problem in the Arithmetic & Logical Unit (ALU) as the ACC_0 signal goes to an X (unknown) state sometimes.

I've come across this little bit of i4004 trivia buried in the user manual for the Intel 4040 CPU. It documents the content of the data bus during subcycles X2 and X3, which were not specified in the i4004 manuals. I'm thinking it might come in handy.




Amusingly, this is not the first time I've worked on an emulated CPU that had this type of problem. I was in college in the early 1980s, at the dawn of the microprocessor era. The faculty decided it would be better if they taught the assembly language for the Z80 rather than for the Univac 1100 mainframe, but we had exactly one Z80 computer for more than one hundred students taking that class that semester. The year before, another student had written a crude 8080 interpreter that ran on the Univac, and a professor wrote a Z80 cross-assembler. Somehow it fell on me, a 3rd-year undergraduate student at the time, to convert the 8080 interpreter to support the full Z80 instruction set and enhance it with features like a programmable interrupt timer so it could be used by operating systems students. In doing so, I made an error which resulted in the Bit Test instruction setting the Z flag to the opposite of what it should be: Z was set if the bit tested was 1, and clear if the bit tested was 0. Oops.

I found out about this when a friend in the operating systems class tried to use the Bit Test instruction and realized the following jump did the opposite of what it should. I quickly corrected the error, only to discover that one of the professors teaching the assembly language class had already found the error. However, instead of informing me of the problem so I could fix it, he told all three sections of his class (75 students) to code their programs backward. I learned of this colossal fuck-up when all of his students started complaining that their programs had suddenly stopped working. I ended up having to maintain two different versions of the interpreter for the rest of the semester, one for his classes and another for everyone else. Let's just say I had never thought highly of that professor, and this did nothing to raise my opinion of him.

1 comment:

  1. Update: There were two bugs that caused this problem. The first was in the generation of signal N0419, which drives the Condition Flip-Flop. The other was in the Condition F/F itself, which caused it to always indicate true (signal ~CN always low). Both of these bugs resulted from errors translating the i4004 schematic to Verilog HDL.

    With these two bugs fixed the emulation now executes the JCN tests properly. I'm still looking at the bus state during subcycles X1/X2/X3. In the meantime, onward with the test program!

    ReplyDelete