Few annoying bugs I was unable to track down and fix so far. Note that none of them affect the calculations due to workarounds or fixes applies.
1. Ghost digits on 7-seg leds
These appear on any CPU frequency higher that 50kHz or so, but only in the calculator display path, not when displaying the internal debug content of macro and microprogram counters. The display strobing goes from higher digits to lower (this is necessary because only this way the leading zero surpression can work) and it appears the segments "race ahead" of the digit strobes.
This bug renders 7 seg display unusable for normal calculator operations. The workaround is to use VGA only to display entry and results, which is no great loss as 4 digit 7-seg can only display half of the digits at a time, one has to press BTN0 to switch to upper half, making it very impractical to begin with.
2. Not all digits of internal registers displayed on VGA debug screen
TMS0800 registers are either 11 BCD digits long (A, B, C), or 11 bits long (AF, BF). There is a timing problem in VGA debug component or its driver which "prints" only:
9 last digits at 12.5MHz
10 last digits at 6.25MHz
At lower frequencies (57.6kHz and 1kHz) all digits are printed on the screen. None of this impacts operation of the calculator core, except makes first 1-2 digits (containing sign etc.) invisible in debug mode.
3. Stray code execution
There is no unconditional jump in TMS0800 - those are modeled by "knowing" the state of CF flag and executing "jump on condition set/reset" instructions accordingly. However due to probably another unknown bug, in Sinclair mode at the end of ROM (part of AntiLog evaluation routine) CF is sometimes not the expected "1". This has been "fixed" with a hack explained in the code, but the real fix should be in some underlying issue (perhaps microcode implementation):
-- HACKHACK: Why is this "random instruction" being passed in to intitialize the ROM???
-- Last instruction in Sinclair ROM as 0x13F is "BINE ALOGDIV" - however in some cases
-- CF is 0 which means it will not be executed and execution will continue at 0x140, which
-- will bring it back to the right place, instead of executing bad opcodes, or NOPs which
-- would wrap up to reset location 0. This is indication of another bug but for now this
fill_value => BIE_ALOGDIV,
sinclair_mode => true, -- hint to show correct disassembled listing (Sinclair mode)
asm_filename => "./sourceCode_sinclair.asm",
lst_filename => "./tms0800/output/sourceCode_sinclair.lst"
address => pc,
data => instruction_sinclair
4. Numeric digit keyboard off by one
Each TMS0800 instruction "pulls" the next right keyboard scan line down. That is the reason why the sequence of instructions is arranged exactly like the keys on the keyboard:
0 0111 0001 0071 10 00000 0000 BKO CLEAR ; Clear key pressed?
0 0111 0010 0072 10 00101 0101 BKO EQLKEY ; Equal key pressed?
0 0111 0011 0073 10 00100 1101 BKO PLSKEY ; Plus key pressed?
0 0111 0100 0074 10 00011 1101 BKO MINKEY ; Minus key pressed?
0 0111 0101 0075 10 00100 1100 BKO MLTKEY ; Mult key pressed?
0 0111 0110 0076 10 00100 1011 BKO DIVKEY ; Divide key pressed?
0 0111 0111 0077 10 00110 0011 BKO CEKEY ; CE key pressed?
0 0111 1000 0078 10 00101 1101 BKO DPTKEY ; Decimal point key pressed?
0 0111 1001 0079 10 00111 1110 BKO ZERKEY ; Zero key pressed?
0 0111 1010 007A 11 10011 1111 EXAB ALL ; Process digit key...
0 0111 1011 007B 11 11010 0010 AKCN LSD1 ; Count key position into A
After the EXAB, the scan should wrap around and start with key "1", which if detected would increment register A in the end accumulating the count until a key was found (so it would return with 8 if key down contact was sensed when 8th line from left was pulled down etc.). However, due to some timing bug sometimes the count starts off by one, so pressing "3" registers as "2" etc. The "fix" is a hack in microcode to double check in AKCN that right scan line is down before proceeding:
118 => -- AKCN
uc_if(cond_e11, upc_next, uc_label(121)),
121 => -- if kn was down, means we have a correct count in last mantissa, so bail, otherwise continue
uc_if(cond_kn, upc_next, uc_label(CONTINUE)),
122 => -- if scanned all, bail with CF = 1 to indicate no key
uc_if(cond_digit10, uc_label(CONTINUECS), uc_label(FORK)),
-- HACKHACK: make sure we are at last digit before continuing!
uc_if(cond_digit10, uc_label(CONTINUE), upc_next),