Tutorial: Hello, world! in Z80 Assembly Language

I'm feeling kind of nostalgic today so I thought I'd write Hello, world! in Z80 assembly for the ZX Spectrum! The last time I wrote any Z80 assembly was when I was 14 so around 36 years ago! I may be a little rusty!
Here it is:
org $8000
ld bc, TEXT
LOOP
ld a, (bc)
cp 0
jr z, EXIT
rst $10
inc bc
jr LOOP
EXIT
ret
TEXT
defb "Hello, world!"
defb 13, 0
How this works line by line:
org $8000 - this line puts the program into memory location $8000
ld bc,TEXT - ld stands for load. We load register bc with the memory location of what comes after the label TEXT
LOOP - the beginning of our printing loop. We will be printing each letter at a time.
ld a,(bc) - now we load register a with the content of register bc. As register a is a single register and can only take a single byte at a time, then the content of bc loaded into register a will be the letter H (the first letter in Hello, world!)
cp 0 - stands for compare 0. We check if register a = 0. It doesn't. It currently equals H.
jr z, EXIT - jr z stands for jump if zero. Therefore if cp 0 does equal 0 then jump to the EXIT label.
rst $10 - rst stands for restart, but it's easier to think of it as "call" as we are now going to call the inbuilt routine at memory location $10. This routine prints the content of register a to the screen. We will now have the letter H printed to the screen!
inc bc - inc means increase. Currently bc points to the address in memory where Hello World! is stored. At this moment in the loop it is pointing to the memory location for the letter H. We need it to point to the next letter, e, so we tell it to increase by one. Register bc will now point to the address for letter e.
jr LOOP - jump to LOOP. We now start the loop again only this time with the letter e about to be printed.
EXIT - the label to begin the routine that will stop the program.
ret - stands for return. Return will go back to the point where the routine was called. As no other routine called this routine, then return will end this routine completely and return to the BASIC interpreter.
TEXT - the label that stores the Hello, world! string.
defb "Hello World!" - defb stands for define bytes, and is simply for holding variables and stuff. In this instance it holds the string "Hello, world!"
defb 13,0 - This is the important line that will cause the printing LOOP to end. The loop will print all the characters of Hello, world! and then come to the number 13. This is a carriage return instruction. This instructs the print routine at $10 to move one line down the screen. You could have another defb after this with another message like "This is my first assembly routine" and the print loop would print that on the next line. However, in this example, we follow the carriage return with 0. The print loop runs into the zero and jumps straight to EXIT and closes the program.
To run the program you would first need to type it into a program called an assembler, assemble it and run it with (and this is where my memory gets a bit fuzzy!) the BASIC command RANDOMIZE USR 32768
Why 32768? That's decimal for $8000. RANDOMIZE USR stands for randomise user sub routine, which just means run the code at memory location 32768.
You will then see Hello World! on your screen. Something like this:
10 PRINT "Hello, world!"
but not half as fun!
edit: I made a slight error but luckily u/spectrumero from Reddit was on hand to fix it:
; add this at the top of the routine after org $8000
hello_world:
ld a, 2 ; channel number
call 0x1601 ; set output channel for rst 16
What this does: 
Comments
Post a Comment