5

I seem to be losing the battle against my stupidity.

This site explains the system calls under various versions of CP/M.

However, when I try to use call 2 (C_WRITE, console output), nothing much happens.

I have the following code.

ORG 100h
LD E,'a'
LD C,2
CALL 5
CALL 0

I recite this here from memory. If there are typos, rest assured they were not in the original since the file did compile and I had a COM file to start.

I am thinking the lines mean the following:

  1. Make sure this gets loaded at address 100h (0h to FFh being the zero page).
  2. Load ASCII 'a' into E register for system call 2.
  3. Load integer 2 into C register for system call 2.
  4. Make system call (JMP to system call is at address 5 in zero page).
  5. End program (Exit command is at address 0 in zero page).

The program starts and exits with no problems. If I remove the last command, it hangs the computer (which I guess is also expected and shows that CALL 0 works).

However, it does not print the ASCII character. (But it does print an extra new line, but the system might have done that.)

How can I get my CP/M program to do what the system call is supposed to do? What am I doing wrong?

UPDATE: The problem was that all assemblers I tried expected a certain format of the source file. This file worked with Microsoft's macro assembler:

        .Z80
START:  LD      E,'a'
        LD      C,2
        CALL    5
        JP      0

I think (I am guessing) that asm.com (DR's assembler) and m80.com (Microsoft's macro assembler) are expecting Intel 8080 mnemonics and have to be told when they have to expect z80 mnemonics, which are apparently different.

I'll accept the answer below anyway because it is also correct since it suggests simply writing the image itself without worrying about asm.com.

Andrew J. Brehm
  • 4,448
  • 8
  • 45
  • 70
  • You're correct that CP/M itself will print an extra new line. Take out everything but the `CALL 0` and see for yourself. – Mark Ransom Sep 11 '12 at 21:02
  • Incidentally --- and I'm aware this is a bit of a necrocomment, but hey, CP/M, it's appropriate --- you don't have to JP 0 to exit your program. If you take care to save your original stack pointer and not overwrite any of the CCP's storage you can just RET back to the shell. That's much more user-friendly as the CCP doesn't need to be reloaded. – David Given Feb 22 '13 at 11:09
  • Thanks. That's a good tip. I am not done with this yet. – Andrew J. Brehm Feb 23 '13 at 00:20

1 Answers1

3

Obvious possibility: is your assembler taking 'a' to be a hexadecimal rather than an ASCII character? 0xa is ASCII for new line. Maybe try 'g' or inspect a hex dump of your assembler output?

Other than that your code looks fine, though an RST 0 would save a few bytes.

EDIT:

I hand assembled your code to:

1e 61
0e 02 
cd 05 00
cd 00 00

I saved that to disk as mytest.com. I then launched this CP/M emulator (warning: that's a direct file download link; the emulator appears to be titled Joan Riff's "Z80MU PROFESSIONAL" Z80 and CP/M 2.2 Emulator and is itself more than twenty years old so doesn't seem to have a web page) for DOS inside DOSBox and ran mytest.com. It output the letter 'a'. So either your toolchain or your CP/M is at fault.

A picture because it really did happen:

enter image description here

Tommy
  • 99,986
  • 12
  • 185
  • 204
  • I tried giving it a 64 for an at-sign. It still doesn't print anything. But I'll look into the possibility. It's the mac.com assembler that comes with CP/M 3.x. – Andrew J. Brehm Sep 04 '12 at 07:45
  • To follow the same line of thought, if you make two calls, ostensibly to print two things, does the output change at all? – Tommy Sep 04 '12 at 21:26
  • I haven't looked at this last night, but that's a good idea. I'll try tonight. Ta. – Andrew J. Brehm Sep 05 '12 at 07:16
  • With two call 5 (and a new character in E) it does exactly the same – Andrew J. Brehm Sep 07 '12 at 09:00
  • One more question — have you tried calling the BIOS function CONOUT directly rather than going through BDOS? – Tommy Sep 11 '12 at 19:23
  • I have no idea how to do that. I only found documentation for BDOS functions. Also, my goal is pretty much to use CP/M calls, not to make a character appear on the screen as such. – Andrew J. Brehm Sep 11 '12 at 19:54
  • BIOS calls are CP/M calls. Based on curiosity prompted by your question I spent some of Sunday putting starting a CP/M emulator and hence can tell you definitely that both WordStar and Turbo Pascal use nothing but the BIOS's CONOUT (at least as far as they run on my slapdash attempt at z80 emulation), eschewing BDOS entirely. That said, sticking with BDOS have you tried call 6 rather than call 2? – Tommy Sep 11 '12 at 20:11
  • That's direct console I/O, right? I tried that. Same (non-)result. – Andrew J. Brehm Sep 11 '12 at 20:19
  • I've just tried hand assembling your code and running it through the first CP/M emulator I could find that I would be able to run on my machine (through a DOS emulator, but whatever). It output the 'a' correctly. So I'm not sure what to say. Is your assembler outputting the same 10 bytes and have you tried alternative emulators? – Tommy Sep 11 '12 at 20:48
  • I tried it with a different emulator now (altairz80 running CP/M 2.2) and asm.com never returns from assembling it. – Andrew J. Brehm Sep 11 '12 at 21:41
  • I tried to assemble it with Microsoft's M80 but the resulting com file just results in an "ADDRESS CANNOT OPEN SOURCE ADDRESS 0100". – Andrew J. Brehm Sep 11 '12 at 21:42
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/16568/discussion-between-tommy-and-andrew-j-brehm) – Tommy Sep 11 '12 at 21:48