;==============================================================================
|
;==============================================================================
|
; Test code for the A-Z80 CPU that prints "Hello, World!"
|
; Test code for the A-Z80 CPU that prints "Hello, World!"
|
; Also used to test responses to interrupts.
|
; Also used to test responses to interrupts.
|
;==============================================================================
|
;==============================================================================
|
org 0
|
org 0
|
start:
|
start:
|
jmp boot
|
jmp boot
|
|
|
; BDOS entry point for various functions
|
; BDOS entry point for various functions
|
; We implement subfunctions:
|
; We implement subfunctions:
|
; C=2 Print a character given in E
|
; C=2 Print a character given in E
|
; C=9 Print a string pointed to by DE; string ends with '$'
|
; C=9 Print a string pointed to by DE; string ends with '$'
|
org 5
|
org 5
|
ld a,c
|
ld a,c
|
cp a,2
|
cp a,2
|
jz bdos_ascii
|
jz bdos_ascii
|
cp a,9
|
cp a,9
|
jz bdos_msg
|
jz bdos_msg
|
ret
|
ret
|
|
|
bdos_ascii:
|
bdos_ascii:
|
ld bc,10*256 ; Port to check for busy
|
ld bc,10*256 ; Port to check for busy
|
in a,(c) ; Poll until the port is not busy
|
in a,(c) ; Poll until the port is not busy
|
bit 0,a
|
bit 0,a
|
jnz bdos_ascii
|
jnz bdos_ascii
|
ld bc,8*256 ; Port to write a character out
|
ld bc,8*256 ; Port to write a character out
|
out (c),e
|
out (c),e
|
ret
|
ret
|
|
|
bdos_msg:
|
bdos_msg:
|
push de
|
push de
|
pop hl
|
pop hl
|
lp0:
|
lp0:
|
ld e,(hl)
|
ld e,(hl)
|
ld a,e
|
ld a,e
|
cp a,'$'
|
cp a,'$'
|
ret z
|
ret z
|
call bdos_ascii
|
call bdos_ascii
|
inc hl
|
inc hl
|
jmp lp0
|
jmp lp0
|
|
|
;---------------------------------------------------------------------
|
;---------------------------------------------------------------------
|
; RST38 (also INT M0) handler
|
; RST38 (also INT M0) handler
|
;---------------------------------------------------------------------
|
;---------------------------------------------------------------------
|
org 038h
|
org 038h
|
push de
|
push de
|
ld de,int_msg
|
ld de,int_msg
|
int_common:
|
int_common:
|
push af
|
push af
|
push bc
|
push bc
|
push hl
|
push hl
|
ld c,9
|
ld c,9
|
call 5
|
call 5
|
pop hl
|
pop hl
|
pop bc
|
pop bc
|
pop af
|
pop af
|
pop de
|
pop de
|
ei
|
ei
|
reti
|
reti
|
int_msg:
|
int_msg:
|
db "_INT_",'$'
|
db "_INT_",'$'
|
|
|
;---------------------------------------------------------------------
|
;---------------------------------------------------------------------
|
; NMI handler
|
; NMI handler
|
;---------------------------------------------------------------------
|
;---------------------------------------------------------------------
|
org 066h
|
org 066h
|
push af
|
push af
|
push bc
|
push bc
|
push de
|
push de
|
push hl
|
push hl
|
ld de,nmi_msg
|
ld de,nmi_msg
|
ld c,9
|
ld c,9
|
call 5
|
call 5
|
pop hl
|
pop hl
|
pop de
|
pop de
|
pop bc
|
pop bc
|
pop af
|
pop af
|
retn
|
retn
|
nmi_msg:
|
nmi_msg:
|
db "_NMI_",'$'
|
db "_NMI_",'$'
|
|
|
;---------------------------------------------------------------------
|
;---------------------------------------------------------------------
|
; IM2 vector address and the handler (to push 0x80 by the IORQ)
|
; IM2 vector address and the handler (to push 0x80 by the IORQ)
|
;---------------------------------------------------------------------
|
;---------------------------------------------------------------------
|
org 080h
|
org 080h
|
dw im2_handler
|
dw im2_handler
|
im2_handler:
|
im2_handler:
|
push de
|
push de
|
ld de,int_im2_msg
|
ld de,int_im2_msg
|
jmp int_common
|
jmp int_common
|
int_im2_msg:
|
int_im2_msg:
|
db "_IM2_",'$'
|
db "_IM2_",'$'
|
boot:
|
boot:
|
; Set the stack pointer
|
; Set the stack pointer
|
ld sp, 16384 ; 16 Kb of RAM
|
ld sp, 16384 ; 16 Kb of RAM
|
; Set up for interrupt testing: see Z80\cpu\toplevel\test_top.sv
|
; Set up for interrupt testing: see Z80\cpu\toplevel\test_top.sv
|
; IMPORTANT: To test IM0, Verilog test code needs to put 0xFF on the bus
|
; IMPORTANT: To test IM0, Verilog test code needs to put 0xFF on the bus
|
; To test IM2, the test code needs to put a vector of 0x80 !!
|
; To test IM2, the test code needs to put a vector of 0x80 !!
|
; This is done in tb_iorq.sv
|
; This is done in tb_iorq.sv
|
im 2
|
im 2
|
ld a,0
|
ld a,0
|
ld i,a
|
ld i,a
|
ei
|
ei
|
;halt
|
;halt
|
; Jump into the executable at 100h
|
; Jump into the executable at 100h
|
jmp 100h
|
jmp 100h
|
|
|
;==============================================================================
|
;==============================================================================
|
;
|
;
|
; Prints "Hello, World!"
|
; Prints "Hello, World!"
|
;
|
;
|
;==============================================================================
|
;==============================================================================
|
org 100h
|
org 100h
|
ld hl,0
|
ld hl,0
|
ld (counter),hl
|
ld (counter),hl
|
exec:
|
exec:
|
ld de,hello
|
ld de,hello
|
ld c,9
|
ld c,9
|
call 5
|
call 5
|
|
|
; Print the counter and the stack pointer to make sure it does not change
|
; Print the counter and the stack pointer to make sure it does not change
|
ld hl, (counter)
|
ld hl, (counter)
|
inc hl
|
inc hl
|
ld (counter),hl
|
ld (counter),hl
|
|
|
ld hl, text
|
ld hl, text
|
ld a,(counter+1)
|
ld a,(counter+1)
|
call tohex
|
call tohex
|
ld hl, text+2
|
ld hl, text+2
|
ld a,(counter)
|
ld a,(counter)
|
call tohex
|
call tohex
|
|
|
ld (stack),sp
|
ld (stack),sp
|
|
|
|
; Several options on which values we want to dump, uncomment only one:
|
ld hl, text+5
|
ld hl, text+5
|
ld a,(stack+1)
|
; ld a,(stack+1) ; Dump stack pointer (useful to check SP)
|
|
ld a, i ; Show IR register
|
call tohex
|
call tohex
|
ld hl, text+7
|
ld hl, text+7
|
ld a,(stack)
|
; ld a,(stack) ; Dump stack pointer (useful to check SP)
|
|
ld a, r ; Show IR register
|
call tohex
|
call tohex
|
|
|
; Two versions of the code: either keep printing the text indefinitely (which
|
; Two versions of the code: either keep printing the text indefinitely (which
|
; can be used for interrupt testing), or print it only once and die
|
; can be used for interrupt testing), or print it only once and die
|
die:
|
die:
|
jr exec
|
jr exec
|
; jr die
|
; jr die
|
|
|
tohex:
|
tohex:
|
; HL = Address to store a hex value
|
; HL = Address to store a hex value
|
; A = Hex value 00-FF
|
; A = Hex value 00-FF
|
push af
|
push af
|
and a,0fh
|
and a,0fh
|
cmp a,10
|
cmp a,10
|
jc skip1
|
jc skip1
|
add a, 'A'-'9'-1
|
add a, 'A'-'9'-1
|
skip1:
|
skip1:
|
add a, '0'
|
add a, '0'
|
inc hl
|
inc hl
|
ld (hl),a
|
ld (hl),a
|
dec hl
|
dec hl
|
pop af
|
pop af
|
rra
|
rra
|
rra
|
rra
|
rra
|
rra
|
rra
|
rra
|
and a,0fh
|
and a,0fh
|
cmp a,10
|
cmp a,10
|
jc skip2
|
jc skip2
|
add a, 'A'-'9'-1
|
add a, 'A'-'9'-1
|
skip2:
|
skip2:
|
add a, '0'
|
add a, '0'
|
ld (hl),a
|
ld (hl),a
|
ret
|
ret
|
|
|
; Print a counter before Hello, World so we can see if the
|
; Print a counter before Hello, World so we can see if the
|
; processor rebooted during one of the interrupts. Also, print the content
|
; processor rebooted during one of the interrupts. Also, print the content
|
; of the SP register which should stay fixed and "uninterrupted"
|
; of the SP register which should stay fixed and "uninterrupted"
|
counter: dw 0
|
counter: dw 0
|
stack: dw 0
|
stack: dw 0
|
|
|
hello:
|
hello:
|
db 13,10
|
db 13,10
|
text:
|
text:
|
db '0000 0000 Hello, World!',13,10,'$'
|
db '---- ---- Hello, World!$'
|
|
|
end
|
end
|
|
|