CP/M Zero Page

This is a continuation of my series of articles on CP/M. It follows my first CP/M article. If you have not read the first article, I recommend that you read it first.

In the previous article I mentioned the zero page which is located at the bottom of the memory (and at the bottom of the transient program area) and 256 bytes in length. At address 81h the zero page contains the command line parameters given to a program when started from the CP/M command processor, called the command tail. At address 80h the zero page contains a byte value indicating the length of the string starting at address 81h.

A program can access the command tail and probably shouldn't modify it although my example program here does.

You can copy and paste the program from here.

What the program does is output an ASCII character representing the length of the command tail and the command tail.

In order to do that it first has to determine the length of the command tail which it does by loading the byte at address tlengh = 81h into register E which is the argument register for the write system call. Then it calls write to output the corresponding ASCII character for the number it read.

Next the program loads the byte at address 81h into register C which together with register B forms the 16 bit register BC. For some reason register B holds the higher byte of register BC and hence requires to be zeroed so that register BC will contain the same number as its component register C.

Then the program loads the address of the command tail into the HL register and adds the length of the command tail, as contained in register BC. It then writes a dollar sign $ to that address because for CP/M BDOS calls a string is terminated with a dollar sign for some reason.

Finally the program outputs the string at address ctail = 81h which is now terminated with a dollar sign.

Note that the command tail here consists of the alphabet twice, i.e. two times 26 characters. Drive I is my emulated hard disk.

The output is first ASCII "5" which is byte 53. I don't know why it isn't 52 (which is two times 26) but I guess CP/M counts the space between the program name and the first character of the parameters as part of the command tail.

The rest of the output is the 52 characters I types as parameters. I don't know why they are in upper-case. I think it is because CP/M uses only upper-case for file names and the parameters are meant to represent file names and switches which in CP/M apparently shouldn't be case-sensitive.

Other characters are represented as passed.

Note that the irregularities in the output are due to the fact that the ASCII character for the length of the command tail is either non-printable (in that case only a space is shown between it and the string) or happens to be a newline or tab (in which case a newline or tab is printed before the string) simply because it is less than 33 for the strings here.

Instructions, registers and assembler directives used so far


tells the macro assembler that the code is for the z80 (as opposed to the Intel 8080 or 8085)
LD DE,immediate
loads an immediate (a number) into 16 bit register DE
a 16 bit register
LD C,immediate
loads an immediate into 8 bit register C
an 8 bit register
CALL address
continues execution at address given and then returns to next line
JP address
continues execution at address given
tells the macro assembler than the assembler code ends here


string EQU integer
tells the macro assembler that string should be replaced with integer when assembling
a 16 bit register which can be used as address register for loading
loads a byte from the address stored in 16 bit register HL into C
an 8 bit register
adds the contents of BC to the contents of HL
a 16 bit register made from 8 bit registers B (high byte) and C (low byte)
loads the contents of register A into the address located in HL

To be continued...

 © Andrew Brehm 2016