Yesterday proved I need to take a step back. So let me actually take my time and write a proper ‘Hello World’ program. I’m going to do this in VS Code, since it’s just nicer to type on a 21st century editor (no offense, ZDE, you were totally awesome for the early 80s).
First thing I need to figure out is where does the stack start? I was originally confused at putting the top of the stack at 00 (where there’s a bunch of BDOS vectors), but I think that really translates to 100H, the top of the TPA, which we set with the ORG pseudo-instruction.
In the following example, I’m using both the write character call, 2, and the write string call, 9. Write string is handy – it handles the looping for you, you just have to put the address of the beginning of the string in the DE register. The only downside is the string is terminated with ‘$’ so the string can’t contain that character. There’s a good overview of all the BDOS calls here.
A few other learnings:
- ZDE has both hard and soft tabs. I think if it detects hard tabs in the file, it switches to that mode. Likewise, you should set VS Code to use hard tabs, 8 spaces.
- I thought some other assembler had a label limit of 5 characters, but it’s more like 16 on Z80ASM. I’m trying to limit to 6 just for formatting (any longer and I need another tab)
- Make sure to set your editor to use CR & LF. I don’t think the assembler had a problem with LF only, but you need both for proper formatting in ZDE, which is handy if you want to make a quick edit ‘on the box’.
;HELLO WORLD FOR Z80 ASSEMBLER
;Z80ASM BY SLR SYSTEMS
;SETUP
BDOS EQU 5 ;CALL FOR BDOS FUNCTIONS
WCHR EQU 2 ;WRITE CHARACTER, IN REG C
WSTR EQU 9 ;WRITE STRING, IN REG C
RCHR EQU 1 ;READ CHAR, IN REG C
RBOOT EQU 0 ;RETURN TO CP/M
TPA EQU 100H ;TRANSIENT PROGRAM AREA, START HERE
CR EQU 0DH ;CARRAIGE RETURN
LF EQU 0AH ;LINE FEED
CTRLZ EQU 1AH ;CTRL Z
ORG TPA
START: LD SP,STACK ;SETUP STACK POINTER
BANG: LD E,"#"
CALL CHOUT
CALL NEWLN
LD HL,HELO
;LOADS THE ADDR OF BEGIN OF MESG IN HL
HELLO: LD E,(HL) ;LOAD E W/ FIRST CHAR FROM STRING
LD A,E
CP 255
JP Z,STRNG
INC HL
CALL CHOUT
JP HELLO
STRNG: CALL NEWLN
LD DE,MESG
CALL STROUT
JP EXIT
EXIT: JP RBOOT ;RETURN TO CCP
;STROUT - OUTPUTS A STRING WHOS ADDRESS IS IN DE REGISTER
STROUT: PUSH BC ;SAVE REGISTERS
PUSH DE
PUSH HL
LD C,WSTR
CALL BDOS
POP HL
POP DE
POP BC
RET
;CHOUT - OUTPUT A CHARACTER THATS IN E REGISTER
CHOUT: PUSH BC ;SAVE REGISTERS
PUSH DE
PUSH HL
LD C,WCHR ;PUT WCHR IN C FOR BDOS CALL
CALL BDOS ;CALL BDOS
POP HL
POP DE
POP BC
RET
;NEWLN - DOES WHAT IT SAYS
NEWLN: LD E,CR ;NOT SURE IF WE NEED CR & LF?
CALL CHOUT ;YEP, WE SEEM TO
LD E,LF
CALL CHOUT
RET
HELO: DB "HELLO WORLD!",255
MESG: DB "THIS IS A TEST OF A STRING OUT$"
DS 64 ;HOLD 64 BYTES FOR STACK
STACK DB 0 ;TOP OF STACK
END
Code language: PHP (php)