; [in] a: value to calculate ; [out] e: 100s place ; [out] c: 10s place ; [out] d: 1s place CalculateBCD: ld e, 0 ; count (100s place) ld b, 100 .sub_led_100: ld h, a ; save for 10s calc sub b jr c, .reset ; count++ ld c, a ld a, e inc a ld e, a ld a, c jr .sub_led_100 .reset: ld b, 10 ld c, 0 ; count (10s place) ld a, h .sub_led_10: sub b jr c, .mod ; count++ ld d, a ld a, c inc a ld c, a ld a, d jr .sub_led_10 .mod: ; a contains overflow; difference is remainder ($ff-remainder-9) ld b, a ld a, $ff sub b ld b, a ld a, 9 sub b ; 1s place ld d, a ret ; [in] a: Value to LED-ify ; [in] hl: Start address of LED tile ; [in] c: LED count UpdateLeds: ld b, a ; cached A dec hl ; pre-decrement, will be added back first way around the loop ld de, $00FF ; offset from HL (inc e will overflow to 0 for first offset) ; shift left for anything less than a count of 8 so we have MSB in the right spot for left shift ld a, 8 sub c jr z, .check .shift: sla b dec a jr nz, .shift .check: inc hl ; determine if we've checked all bits inc e ld a, e cp c jr z, .exit ; shift left, carry contains whether the bit was set sla b jr c, .set .clear: ld [hl], LED_OFF jr .check .set: ld [hl], LED_ON jr .check .exit: ret Tick: ; We don't want any interrupts mid-tick di ; Reset the control signals xor a ld hl, ctrl ld [hl+], a ld [hl], a ; Reset bus; in case we have no control signals ld [bus], a ; Operate based on current op stage ld a, [opc] ld c, a ; Stage 0 and 1 are the same for all operations cp $0 jr z, .stage_0 cp $1 jr z, .stage_1 ; Stage 2, 3, and 4 differ jr .stage_2_3_4 ; Stage 0 same for all instructions: CO | MI .stage_0: ld hl, ctrl set CTRL_MI, [hl] inc hl set CTRL_CO, [hl] jr .update_leds ; Stage 1 same for all instructions: RO | II | CE .stage_1: ld hl, ctrl set CTRL_RO, [hl] set CTRL_II, [hl] inc hl set CTRL_CE, [hl] jr .update_leds .stage_2_3_4: ld a, [ir] and $f0 ld b, c ; NOP cp $00 jr z, .update_leds ; LDA cp $10 call z, op_lda ; ADD cp $20 call z, op_add ; SUB cp $30 call z, op_sub ; STA cp $40 call z, op_sta ; LDI cp $50 call z, op_ldi ; JP cp $60 call z, op_jmp ; JC cp $70 call z, op_jc ; JZ cp $80 call z, op_jz ; OUT cp $e0 call z, op_out ; HLT cp $f0 call z, op_hlt .update_leds: ; These LEDs are latched by the clock so we want to display only pre-control signal evaluation ld a, [opc] ld c, 3 ld hl, opc_led_2 call UpdateLeds ld a, [pc] ld c, 4 ld hl, pc_led_3 call UpdateLeds ld a, [mar] ld c, 4 ld hl, mar_led_3 call UpdateLeds ld a, [ir] ld c, 8 ld hl, ir_led_7 call UpdateLeds ld a, [a_reg] ld c, 8 ld hl, a_led_7 call UpdateLeds ld a, [b_reg] ld c, 8 ld hl, b_led_7 call UpdateLeds ld a, [alu] ld c, 8 ld hl, alu_led_7 call UpdateLeds ld a, [ctrl] ld c, 8 ld hl, ctrl_led_ht call UpdateLeds ld a, [ctrl+1] ld c, 8 ld hl, ctrl_led_eo call UpdateLeds ld a, [flags] ld c, 2 ld hl, flag_led_c call UpdateLeds ; Update output display ld a, [out_reg] call CalculateBCD ; 100s place ld hl, display ld [hl], e ; 10s place inc hl ld [hl], c ; 1s place inc hl ld [hl], d ; Update mem display ld a, [mar] ld hl, ram add l ld l, a ld a, [hl] ld [mem], a ; Update the control signals for next time. Order matters. call ctrl_ht call ctrl_ro call ctrl_io call ctrl_ao call ctrl_su call ctrl_fi call ctrl_eo call ctrl_co call ctrl_mi call ctrl_ri call ctrl_ii call ctrl_ai call ctrl_bi call ctrl_oi call ctrl_ce call ctrl_jp ; The memory LEDs are also instantaneous (they display whatever is in memory at the address in the MAR) ld a, [mem] ld c, 8 ld hl, mem_led_7 call UpdateLeds ; The bus LEDs are instantaneous (no latching), so we should always display latest ld a, [bus] ld c, 8 ld hl, bus_led_7 call UpdateLeds ; Go to next op stage ld a, [opc] inc a ld [opc], a cp 5 jr nz, .exit xor a ld [opc], a .exit: ei ret