295 lines
4.1 KiB
NASM
295 lines
4.1 KiB
NASM
|
; [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
|