While I am nearing completion of a CPU test suite, there are some findings I would like to share here, as they changed some of my previous assumptions. Besides, they are important aspects for future programming, so I need to remember these.
Carry/borrow flag. First thing is how the ‘181 ALU handles the carry flag when performing subtraction. I assumed silently, that during subtracting carry would be set in case of a borrow, i.e. when a<b in case of a-b operation. Meanwhile, the CPU was setting the carry flag when there was no borrow and clearing it otherwise. Initially I thought there was some kind of microcode bug but after a while I discovered that there are two typical interpretations of the carry flag when subtracting. One computes it as described (borrow sets a carry flag) and the other is used when subtraction is actually computed as a+(-b) which is a+not(b)+1 in two’s complement arithmetic (and the carry flag is set according to this summation in such cases). The ‘181 uses the latter formula (as does the 6502), sets the carry flag when there is no borrow, and clears it when borrow occurs, whereas x86 uses the former. One needs to remember this oddity when coding.
Stack direction. At some point I realized also that my stack organization was inadequate. I made a decision some time ago that the stack would grow towards increasing memory addresses (in other words, the SP would be increased by PUSH operations and decreased by POPs). It seemed a more natural way of organizing a dynamic structure in memory. However, I realized that this makes accessing the top of the stack more difficult. Suppose you have just PUSHed – the PC now points to the first memory location after the top of the stack. This made all my instructions like LD A, (SP) or ADD A, (SP) completely useless (and as far as I remember my intention when including them to the instruction set was to quickly access the top of the stack). A solution to this issue is to reverse the stack and make it grow towards decreasing memory addresses. This way the two bytes after SP are the top of the stack (i.e. the SP points to the stack’s usable top). This required just a simple change to the microcode – the new version I will publish after all tests are completed will reflect this.
Microcode tweaks. I also made one alteration to the microcode word layout. Previously I had two independent 1-bit signals for SP manipulation, namely INCSP (SP++) and DECSP (SP–). It was obvious that they should never be used at the same time. So I changed these two bits to:
|CNTSP||1||enable, disable||SP count enable signal|
|CNTSPDIR||1||down, up||SP count direction|
Now, SP is forwarded or backed when CNTSP is active and CNTSPDIR determines the count direction (downwards/upwards). Whenever CNTSP is not active, the CNTSPDIR field may be used for some other purpose. With just three microcode bits left, this may soon turn out critical. The new layout frees one bit (well, half a bit in fact as this is only true when there is no need to advance or decrease the stack pointer).