RosettaCodeData/Task/Execute-Computer-Zero/Z80-Assembly/execute-computer-zero.z80

196 lines
3.4 KiB
Z80 Assembly

org &1000
PrintChar equ &BB5A
;reg usage:
;DE = VM'S Program Counter
;IXL = VM's Accumulator
main:
ld ixl,0
ld de,Computer_Zero_RAM_2_plus_2
call Computer_Zero_VM
ld a,ixl
call ShowHex ;output to Amstrad CPC's screen
call NewLine
ld ixl,0
ld de,Computer_Zero_RAM_7x8
call Computer_Zero_VM
ld a,ixl
jp ShowHex ;output and return to basic.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;these two functions are related to displaying the output
; and have nothing to do with the virtual machine itself.
ShowHex:
push af
and %11110000
rrca
rrca
rrca
rrca
call PrintHexChar
pop af
and %00001111
;call PrintHexChar
;execution flows into it naturally.
PrintHexChar:
;converts hex to ascii
or a ;Clear Carry Flag
daa
add a,&F0
adc a,&40
jp PrintChar
NewLine:
push af
ld a,13
call PrintChar
ld a,10
call PrintChar
pop af
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Computer_Zero_VM:
ld a,(de) ;opcode fetch
call UnpackOpcode ;stores opcode in B, operand in C
push de
ld de,Opcode_Table
ld a,b
rlca ;index times 2 for word data
ld e,a
ld a,(de)
ld L,a
inc de
ld a,(de)
ld h,a ;LD HL,(DE)
pop de
jp (hl)
;register state after this jump:
;DE = program counter
;HL = address of instruction implementation
;C = operand of the instruction we're about to execute
;IXL = accumulator
overhead:
ld a,e
inc a
and %00011111
;ensures we stay within the 32 byte address space.
ld e,a
jp Computer_Zero_VM
UnpackOpcode:
push af
and %11100000
rlca
rlca
rlca
ld b,a ;opcode in B
pop af
and %00011111
ld c,a ;operand in C
dummy:
ret
align 256 ;ensures the following table is page-aligned
;this lets us index it much faster.
Opcode_Table:
dw vmNOP
dw vmLDA
dw vmSTA
dw vmADD
dw vmSUB
dw vmBRZ
dw vmJMP
dw vmSTP
vmNOP:
jp overhead ;do nothing
vmLDA:
push de
ld e,c ;offset DE by the operand
ld a,(de) ;load from that address
ld ixl,a ;and store it in the accumulator
pop de
jp overhead
vmSTA:
push de
ld e,c ;offset DE by the operand
ld a,ixl ;get the accumulator
ld (de),a ;store it into (DE)
pop de
jp overhead
vmADD:
push de
ld e,c ;offset DE by the operand
ld a,(de) ;load from that address
add ixl ;and add that value to the accumulator
ld ixl,a ;then set the new accumulator
pop de
jp overhead
vmSUB:
push de
ld e,c ;offset DE by the operand
ld a,(de)
ld b,a
ld a,ixl
sub b
ld ixl,a
pop de
noBRZ:
jp overhead
vmBRZ:
ld a,ixl
or a
jr nz, noBRZ
vmJMP:
ld e,c
jp Computer_Zero_VM
vmSTP:
ret ;return to main
align 256
Computer_Zero_RAM_2_plus_2:
db %00100011,%01100100
db %11100000,%00000010
db %00000010,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
align 256
Computer_Zero_RAM_7x8:
db %00101100,%01101010
db %01001100,%00101011
db %10001101,%01001011
db %10101000,%11000000
db %00101100,%11100000
db %00001000,%00000111
db %00000000,%00000001
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000
db %00000000,%00000000