• Please review our updated Terms and Rules here

Passing parameters/arguments

Doug, thanks. I have tried both those iterations, and the assembler keeps saying that 'OLDSP' is an undefined symbol. ERROR: Symbol 'OLDSP' is undefined..... And I'm not sure what to EQU it to.....
 
Ah, then you need to define storage for OLDSP - it is a variable. something like "OLDSP: DW 0". That needs to be in a place outside of executable code, e.g. after an unconditional jump or return. I'm guessing DUMP.ASM had OLDSP defined but it just got lost in the conversion.
 
Old saying, "if you are the smartest person in the room, you are in the wrong room". So, I guess this is the room I need to be in..... Because, I'm am sure learned lot's of new stuff...... Anyway, that seems to have worked. And it uncovered another variable that needed to be defined. It did assemble without any errors at least. Now I need to test fire it on the CP/M machine to make sure I translated things properly, before I start modifying it. And I attached a copy of what 'might be' the Z-80 version of DUMP. Thanks again.
 

Attachments

  • PRINT.txt
    4.3 KB · Views: 7
Just reading this, and CP/M describes writing the command line to the current DMA address that I saw - which defaults to 0080 -

If the DMA address is set elsewhere, does Function 10 write the command line to 0080 or to the new DMA address?

Thanks
David
 
There is no way to get the current DMA address so I should hope the command line goes to 0080H or it will never be found. Probably best to process the command tail as soon as possible just to be on the safe side.
 
Function 10 does NOT use the current/default DMA address. The caller passes an address of a buffer to use. Even the CCP does not call function 10 with 0080h - it copies data to 0080h before jumping to the program. Note that function 10 does not use the same format of buffer as the CCP puts into 0080h, either. There are 2 meta bytes before the input data in function 10 - first is passed in as the MAX bytes (size of buffer), second is the actual number of bytes that were input (on return).
 
You may want to locate / download XIZI.LBR and then use XIZ.COM instead of hand converting Intel to Zilog mnemonics. XZI.COM will translate the other way.

As to Intel versus Zilog mnemonics ... everyone has their own opinion. Having used S/360 assembler a lot before I also started using CP/M-2 when it was released, I found the Zilog mnemonics easier to understand and remember. However, it did take awhile to get used to "LD (" instead of "ST"ore and I resisted the temptation to use a macro for that.
 
Well, I seem to be going nowhere fast in my debugging efforts. And I suspect it is my lack on the inter play between programs and how they call or jump to BDOS, etc. When I run the PRINT program the very first time after powering things on, with no filename included, I seem to get the 'Bdos Err On [: Select' error message. But typing enter gets me back to a command prompt.

Then, if I run the PRINT program again, either with, or without a filename included, I get the SIGNON message (FILE TO PRINTER VERSION 1.0) and the OPNMSG (No Data File Specified) and then the system hangs.

I see there are thre references to the FINIS routine in the code, but they are all JP or JP C statements. But at the end of the FINIS routine is a RET statement. What am I missing, because I think a RET is used in conjunction with a CALL statement. Maybe I should just try to do a clean JP back to the CP/M warm start entry and not try to save the stack pointer/ I'm not sure what saving the stack pointer is really buying me.

Seems the more I re-learn about machine code, the more things I find I do not know.... I'm a re-born newbie! Anyway, thanks for any help......
 

Attachments

  • PRINT.txt
    5.6 KB · Views: 5
The RET returns control to the CCP and thus it works. Rather amazing in a way. If you have a larger program which overwrites the CCP, a JMP 0 would cause a soft reboot and the reload of the CCP. It is probably better to use function 0 to make the code easier to port. While Function 0 simply does JMP 0 in CP/M 2.2, later versions don't always support warm boot at address 0.
 
Last edited:
I see that DUMP.ASM may not have been the best example. It does no checking whether a filename was included on the commandline. The SETUP routine really should be checking 005DH (FCBFN) to see if it is blank. If it is blank, it should error out (or return 255). As far as why it does not work when you specify a file, maybe we need to see your commandline and also what type of system you are running on. It sounds like the file you specify is not being found.

Note that the RET in the FINIS routine is preceded by restoring the original stack pointer (from the CCP). That is why it works. Or should work. The reason this was done was that, on systems with real floppy disks, the JMP 0 was rather slow - CP/M was reloaded from the floppy. There was a performance advantage to saving the CCP stack and doing a direct return. There is no particular advantage to making a BDOS call to function 0, JMP 0 is defined by CP/M and must always work if a system is CP/M-compliant.

If this is a non-standard CP/M system, you may not be able to return directly to the CCP. So, trying a JMP 0 would be a good test.
 
Note, on a normal system the CCP would initialize the area at 005CH to
Code:
0,'           ',0...
and so the attempt to open (when no file specified) should always return "not found" (unless you have a file on the default disk who's name was all blanks - highly unlikely). The fact that you got "Bdos Err On [: Select'" message means that you have garbage in 005CH (invalid drive designation). Whatever you're using as the CCP does not seem to be setting up that area correctly.
 
Well, as it turns out, once I stripped out saving the stack pointer and then restoring it before a RET, and just used a JP 0, it would put me back at the CP/M prompt. However it still gives the SIGNON message (FILE TO PRINTER VERSION 1.0) and the OPNMSG (No Data File Specified) even if I do specify a file. So there is still an issue with actually identifying and reading the file that was specified.

This is what is in the CP/M 2.2 code I am running:
; File control block setup by the CCP.
;
FCB: DEFB 0,' ',0,0,0,0,0,' ',0,0,0,0,0

IOBYTE EQU 3 ;i/o definition byte.
TDRIVE EQU 4 ;current drive name and user number.
ENTRY EQU 5 ;entry point for the cp/m bdos.
TFCB EQU 5CH ;default file control block.
TBUFF EQU 80H ;i/o buffer and command line storage.
TBASE EQU 100H ;transiant program storage area.

Attached is the first 256 bytes in memory when CP/M is running. The program does a compare to FF once the call to BDOS is returned from a OPENF. I suspect the return code is FF which would indicate there is no file present. That is a tad confusing......
 

Attachments

  • Block0.txt
    864 bytes · Views: 4
I'm not sure what you're doing with the "FCB:" definition. The CCP is going to put the filename into the FCB at 005CH. If you define your own FCB in your program, then you'll need to copy from 005CH into it before it will be valid. The format of any FCB is: first byte is drive code, bytes 1-12 are the filename and type (8+3), next are some bytes that control accessing file data, typically you don't need to worry about those - although you might need to ensure byte 13 is zero before OPEN. Your page-0 dump shows 005CH properly cleared, as if no file was specified on the commandline. Depending on when that dump was taken (in relation to running PRINT), it may or may not indicate that the CCP failed to recognize and setup the filename. Unless you think you have a corrupted copy of CP/M, I think we need to look at your program. I'll see if I can get M80 to compile it, since I normally don't mess with Zilog mnemonics, and see if I can reproduce your issue.
 
I did some more looking, and trying to assemble/run your PRINT.txt. There are many errors in it, most related to Zilog mnemonics. For example, "CP 00H" is not valid, you need "CP A,00H". Also, there are places where you want to load DE with an address, but you have "LD D,xxxx" which only loads D, not DE. You also have one instruction "LD A,IBP" which needs to be "LD A,(IBP)". These are good examples of why I dislike Zilog mnemonics (eveything is a "LD" - but not all "LD"s are the same). In addition, the STACK AREA was setup wrong, and you were actually overwriting OLDSP and IBP with your running stack - which is why you were crashing when trying to return to the CCP. You need to have the "DS 64" and the "STKTOP:" right next to each other. Remember, the stack grows *downward*. When I fixed all those, it worked better (the output was not like DUMP.COM, though, so some things may still be off).
 
Found one more error, you have "INC H" when it needs to be "INC HL". After that, it behaves like DUMP.COM.

I should also note, this is using the PRINT.txt that you last posted here. I'm not sure what other changes you have made to your copy.
 
I've learned a lot reading this thread also.

I've been writing similar code in the past week, and so modified it to try on a real CP/M machine rather than the emulator I've been working on, which didn't go so well, but the code that products the memory dump works so I just stripped out the rest of the code and had it do that to take a look at 0080 myself after program execution.

The program is a bit like dump.com but without the file- it just dumps out memory and is a part of the monitor I'm writing.

Anyway, since I was also confused about what should appear in the arguments buffer as I had assumed it was like the BDOS function, and would show the filename and not just the arguments, along with two bytes of counters preceeding it. Well, I was pretty wrong in my assumptions, so had a look myself by dumping the zero page after application commencement.

Since a pictures worth a thousand words, and other may read this thread in the future ( I've gotten a lot from old threads here ) - I'll post a pic of what the zero page looks like after program execution on my PCW.

CLI arguments (Medium).jpg

Looking at this, does the CCP automatically not only store the arguments at 0080, but also store the first two white-space separated arguments with disk information in the default FCB? It certainly looks like it does. I can't recall reading that it does that anywhere, but it definitely seems to be the case, and would affect how any subsequent parameters needed to be stored for switches or options after the CCP hands over to the application.

Or is it just the PCW I'm using doing things a little strange ( running CP/M plus )

Thanks
David
 
The CCP behavior when initializing page-0 for running a program is well documented, I believe. But, as with most of CP/M, you have to read the right documents. Having been using this for decades, I can't say whether it is easy to pick up or not. Reading through all this can be quite a strain. But, having the documentation nearby as you try to use CP/M is essential. I think it's harder these days not having a physical, paper, manual. I find it easier to flip through pages than to try and find something in a PDF - especially one that is not searchable.

To your question, yes the documented behavior for all CP/Ms is to initialize 0080 from the commandline after the command name, and also initialize 005CH and 006CH if there appear to be filenames in the first arguments. Really all the CCP is looking for is a string of 1 or more *likely* filename characters. Whether or not it is actually a filename is irrelevant. For example, if you have something called ANSWER.COM, the command "answer y n" will parse two FCBs for the "y" and the "n", but ANSWER.COM may never use those as files. CP/M Plus has additional areas around 0050H that it initializes.
 
To your question, yes the documented behavior for all CP/Ms is to initialize 0080 from the commandline after the command name, and also initialize 005CH and 006CH if there appear to be filenames in the first arguments. Really all the CCP is looking for is a string of 1 or more *likely* filename characters. Whether or not it is actually a filename is irrelevant.
Thanks Doug,

Now I can see what CP/M is doing, it makes a lot more sense. I've been experimenting with it a bit, and notice that the pattern seems to be as follows;

1) Is there a drive specifier? If so, set the drive specifier in the FCB, and proceed. Otherwise make this byte 0.
2) Copy the characters to the FCB, without checking or validating outside of the reserved codes, and process * . and other reserved characters
3) If the string exceeds 11 characters with/without a full stop, just copy until 11 characters are copied.
4) If 3) didn't find whitespace next (eg, 12 character filename ) then just create a blank (spaces) filename in FCB 2 otherwise repeat from 1).

So it seems the Amstrad CCP doesn't do a lot of sanitisation outside of processing of wildcards.

The list I posted in my other thread < > . , ; : = ? * [ ] - ref: CPM the Software Bus Programmers Companion seems accurate then for filename sanitisation under BDOS/CCP.
. is ignored, except for padding out to the extension, otherwise is treated like the rest.
* is expanded if in the right location to ?'s
? is carried through without changing.
Everything else is treated as "End of the filename" in the string.

So in my case ( application is memdump.com ) I type;

memdump >file1.txt

I will find the first FCB entry blank, and the second contains File1.txt

If I do something like

memdump file1>file2

I find file1 and file2 respectively in the FCBs.

This was an interesting thing to observe. I agree, I have found it difficult to find things in the manual, but once I know of them, have no trouble finding them with a search. Hence I went to Abebooks and got a CPM programming book. :)

Thanks again,
David
 
The filename parsing is a little bit more complex, just keep in mind the "8+3" format of the name. If the string does not contain a period, then only 8 chars parsed. If there is a period, then 3 more characters are parsed into FCB+9. For example, "abcdefghijklmn" parses to "ABCDEFGH " and "abcdefghijklmn.wxyz" parses to "ABCDEFGHWXY" (or the file ABCDEFGH.WXY)
 
The filename parsing is a little bit more complex, just keep in mind the "8+3" format of the name. If the string does not contain a period, then only 8 chars parsed. If there is a period, then 3 more characters are parsed into FCB+9. For example, "abcdefghijklmn" parses to "ABCDEFGH " and "abcdefghijklmn.wxyz" parses to "ABCDEFGHWXY" (or the file ABCDEFGH.WXY)
It does.

One difference I noted when looking at your emulation - your version will accept abcdefghj.jklm opqrstuvw.xyz and give two filenames, while the Amstrad CPM+ only provides one. Otherwise both your java version and the Amstrad seem to do the same.

I eventually found another buy in the code of the emulator I'm writing. I've been using MCS51 too long, and forgot the C in CCF was Complement and not Clear... :( Slowly I'm finding the final few bugs in it.

Your emulator is proving very helpful, thank you. :)
 
Back
Top