PDA

View Full Version : Assembler with Z80 mnemonics



Alphasite
December 4th, 2017, 11:30 AM
I'm trying to rebuild the setup I had to build my CP/M 2.2 and Plus systems. I've got most of the source recovered. I need to write a new SYSGEN for 2.2 and COPYSYS for Plus, as well as write a new copy/format/verify utility for floppies.

I'm trying to recompile some of the source for my 2.2 system and have run into an issue. I used Z80 mnemonics. I have a utility to format non-native floppies. There aren't any .Z80 directives (or any for that matter). When I try to use M80 I get tons of errors, so I don't think I used M80 to build it. As far as I can remember the only assemblers I had other than M80 was ASM, MAC, and RMAC and those all use 8080 mnemonics.

It's been 30 years since I assembled any of this. Does anyone have any ideas what I might have done?

Chuck(G)
December 4th, 2017, 12:31 PM
Dunno--I developed commercial firmware using M80 (http://www.s100computers.com/Software%20Folder/Assembler%20Collection/Microsoft%20M80%20Manual.pdf) with Z80 mnemonics back in the day, so you'll have to be more precise when you say "tons of errors'. IMOHO, M80 (with L80 and LIB80) was pretty good for the day.

If you want an MS-DOS assembler for Z80, take a look at the one from Avocet.

Alphasite
December 4th, 2017, 12:51 PM
Dunno--I developed commercial firmware using M80 (http://www.s100computers.com/Software%20Folder/Assembler%20Collection/Microsoft%20M80%20Manual.pdf) with Z80 mnemonics back in the day, so you'll have to be more precise when you say "tons of errors'. IMOHO, M80 (with L80 and LIB80) was pretty good for the day.

If you want an MS-DOS assembler for Z80, take a look at the one from Avocet.

I like M80 and used it for building my CP/M Plus sources.

For the 2.2 source I'm trying to assemble it's marked about 50% of the lines as errors, mostly "O" (bad opcode or syntax), "Q" ("Questionable" error), and "U" (undefined symbol).

I don't see any hidden control characters in the files and I haven't transferred them in and out to another system that would have messed with the formatting.

The ones marked "O" I've looked at and they are all valid Z80 mnemonics. These files haven't even been edited in the past 30 years.

That's why I'm guessing I may have used something else at some point that I've forgotten since as I said I switched to M80 when I updated the 2.2 sources for Plus.

Chuck(G)
December 4th, 2017, 02:44 PM
Got a sample? I'll give it a try.

WSM
December 4th, 2017, 10:19 PM
Did you possibly use the /Z switch on the M80 command line in the past? According to the M80 manual, that's an alternative to the .Z80 directive. I haven't used the command line switch but have extensively used M80 and the .Z80 directive without any issues.

retrogear
December 5th, 2017, 03:37 PM
Don't labels have to be followed by a colon? I remember that being a big difference.

Larry G

Alphasite
December 5th, 2017, 08:25 PM
Did you possibly use the /Z switch on the M80 command line in the past? According to the M80 manual, that's an alternative to the .Z80 directive. I haven't used the command line switch but have extensively used M80 and the .Z80 directive without any issues.

I didn't remember using the /Z switch but Chuck tested it and it worked except for a couple of errors in labels, so the code I recovered must not have been the final copy.

The other source code I have with Z80 mnemonics used the .Z80 directive, but this one didn't so I thought I must have had something else I used.

It's been 30 years since I last touched the code so there's lots that I've forgotten.

This was all written for the TRS-80 Model 4.

For example, I can't remember how I built my CP/M 2.2 code to make the file to write with SYSGEN. I have the CBOOT and CBIOS sources but I don't remember putting them together at all. I have one version that has a memory disk and I even found a disk that was still bootable. It has an alternate CCP that a friend wrote so I need to go through the CP/M manuals to get the locations for the CCP in the file that SYSGEN writes as I'd like to have another one that's stock CCP.

I have another version where I used the alternate bank to move some of the code out of main memory to increase the TPA which in turn allowed me to add more terminal emulation control codes and an extra emulation mode (ADM-11 and VT52). That source code does detail the tracks and sectors to place things for booting but whatever I used to write it is gone.

I still have the CP/M Plus BIOS and boot code along with the SUB files to build it. I've lost the COPYSYS to write the system tracks, though. I still have bootable disks and built a new CPM3.SYS to test and it worked. I also have the sources for the utility to change the system settings in Z80 assembler, BDS C, and Mix C (I wrote a version in C as I was teaching myself the language at the time).

I've got the source for the format/copy/verify utility but it doesn't work so that source must also have been a work in process and not the final copy. Right now as a workaround I can use Montezuma Micro to format disks as I was able to add the format to MM's DISK.FDF file.

I also have a bootable copy of TurboDOS that I made using a modified version of my CP/M 2.2 BIOS. Unfortunately that modified BIOS source is gone but I should be able to disassemble it when I get time.

This has been fun but also frustrating when I realize how much I've forgotten.

Alphasite
December 5th, 2017, 08:25 PM
Don't labels have to be followed by a colon? I remember that being a big difference.

Larry G

Yes, I believe you are correct.

Alphasite
December 5th, 2017, 08:37 PM
I did find my old copy of the book "CP/M Programmer's Encyclopedia". That will help.

Chuck(G)
December 5th, 2017, 09:14 PM
Did you possibly use the /Z switch on the M80 command line in the past? According to the M80 manual, that's an alternative to the .Z80 directive. I haven't used the command line switch but have extensively used M80 and the .Z80 directive without any issues.

I ran Alphasite's code sample through M80, and it was the /Z switch that was omitted. The only other error was due to the fact that M80 pays attention to only the first 6 characters of a label--so "MYLABEL" and "MYLABEL0" are treated as the same symbol.

FWIW, I ran m80 on an MS-DOS CP/M emulator running under dosemu on a 64-bit Linux box. So, an emulation inside an emulation.

WSM
December 6th, 2017, 12:29 AM
The only other error was due to the fact that M80 pays attention to only the first 6 characters of a label--so "MYLABEL" and "MYLABEL0" are treated as the same symbol.
I agree that is what the manual states and that early versions of M80 exhibited that behaviour. My experience with M80 V3.44 is that it pays attention to at least 8 characters in a label. HOWEVER, M80 / L80 only pay attention to 6 characters of external labels. As an example, the following Z180 bit definitions work fine for me and have been used in several of my modules assembled using M80 V3.44 in the Altair Z80 simulator V3.8-1 under SIMH. The correct values appear within the code and also in the symbol table at the end of the listing.

ITC.ITE0 EQU 01h
ITC.ITE1 EQU 02h
ITC.ITE2 EQU 04h

SteveH
December 6th, 2017, 01:36 AM
If you want an MS-DOS assembler for Z80, take a look at the one from Avocet.

Thought I'd give the Avocet Z80 assembler a go, but the links to it I've tried are all dead. Does anyone have a working link?

Thanks

Chuck(G)
December 6th, 2017, 05:33 AM
@WSM, thanks for the information. I grabbed a copy of M80 at random (I probably have dozens of copies of the file)--and it turned out to be 3.36. The six-character limit got me wondering, though. Didn't Microsoft F80 and MBASIC also have a "six-character-unique" limitation? I vaguely remember that, as an implementer of another 8085 BASIC compiler, we were a bit smug in our limit of 32 unique character labels. In some COBOL contexts, very long symbols seemed to be standard practice. I wonder if MS used the same symbol table routines in all of them.

@SteveH, I probably have a fairly old copy of the Avocet assembler kicking around, but am not aware of its status, vis-a-vis copyright restrictions, so I hesitate to pass it out. I did use it back in the day for my last one or two projects and it was adequate.

Nowadays, there must be dozens of cross-assemblers for Z80 code.

ziloo
December 6th, 2017, 06:11 AM
There is a Z80 Macro Assembler from 2500 A.D. that you can find here:

http://www.vintagecomputer.net/fjkraan/comp/mirror/z80cpu.eu/archive/rlee/L/LOOSECPM/300/U3/


I hope it works for you...


ziloo :mrgreen:

ziloo
December 6th, 2017, 06:32 AM
There is also a commercial product from Oshonsoft that
includes an IDE and it has received very good reviews.


ziloo :mrgreen:

Bitly
December 6th, 2017, 06:59 AM
Thought I'd give the Avocet Z80 assembler a go, but the links to it I've tried are all dead. Does anyone have a working link?

Thanks

There's a demo (still) available: https://web.archive.org/web/20130414105218/http://www.avocetsystems.com:80/company/download/adx-z80demo.zip

CW

Chuck(G)
December 6th, 2017, 07:57 AM
If you're going after cross-assemblers, remember that Zilog offers a free IDE (https://www.zilog.com/index.php?option=com_zcm&task=view&soft_id=19&Itemid=74) that covers a range of 8-bit products, including Z80 derivatives, such as the eZ80, Z180,...

Also,Thomas Scherer's Z80 page (https://www.zilog.com/index.php?option=com_zcm&task=view&soft_id=19&Itemid=74) lists quite a selection of cross assemblers for Z80.

WSM
December 6th, 2017, 08:09 AM
@Chuck(G) I haven't used F80 or COBOL-80 any more than to prove they work with the simplest programs. Although I primarily used M80 back in the day and still today, I also used both MBASIC and BASCOM. A quick test with MBASIC4 and MBASIC5 show that they both support at least eight character variable names.

I believe the real issue may have been with .REL files and L80. The bit-stream oriented record format used three bits to define the length of a symbol (i.e. Entry symbol, COMMON name or Program name). A quick look at a .REL file makes me believe the length field was one-indexed which would only allow for a maximum of seven characters. Besides L80, any change to the .REL format would have forced changes to at least LIB-80, M80, F80, BASCOM and COBOL-80. Likewise it would have created incompatibilities with any pre-existing .REL files and libraries.

Mini-rant: In the late 1970's I purchased a copy of BASCOM for something like $299 or $399. Besides the compiler and library, the package also included M80, L80, CREF80 and LIB. Later when Microsoft released an updated version, their upgrade policy for existing users was pretty simple ... purchase a new copy for full list price. Given that kind of support (i.e. money grab), my original purchase was the one and only time I purchased a Microsoft CP/M product.

Bill

Chuck(G)
December 6th, 2017, 08:35 AM
Well, to be fair, MS was not a big player in the 8-bit world. It wasn't until the sweetheart deal that came along with IBM that they grew like Topsy. Their stuff could be quirky, but what wasn't in the 1970s? I seem to recall that, at one time, MS's big seller was the Z80 card for the Apple II.

BrianS
December 16th, 2017, 03:20 AM
F80 and M80 have a limit of 6 character external labels. Many FORTRAN compilers of the day used a 64-bit value to store the Label name an "Tag". The $8M TI-ASC that I used had the same limitation, 64 bits for the external label, 6 character name and 2 characters for "type".

Versions of F80 prior to 3.44 have a problem sharing common blocks with M80. "As I recall" F80 sets the first bit of of the common block label name, but M80 does not. Version 3.44 fixed the problem. First and only time that I called the Microsoft support line to report the problem, after doing memory dumps of the object code generated by each.

Chuck(G)
December 16th, 2017, 08:34 AM
I recall that USA Basic FORTRAN explicitly limited variable names to 6 characters, as did older versions of FORTRAN II. So the 6 character limit wasn't unreasonable.

smp
December 17th, 2017, 11:20 AM
There is also a commercial product from Oshonsoft that
includes an IDE and it has received very good reviews.

ziloo :mrgreen:

I was about to make my own post on this, and I saw it is already here. I have this Oshonsoft Z80 IDE, and I've used it successfully. Very inexpensive, and it works fine.

smp

Alphasite
December 18th, 2017, 09:25 PM
I've made some progress. I converted the default COPYSYS.ASM to Z80 mnemonics, adjusted the values for the disk geometry, and changed it so if an image was specified to use instead of a source disk it used BDOS calls to read the image into memory instead of the BIOS since using BIOS reads didn't seem to work. I'm not sure why DRI did it that way for the image load but used BDOS calls to copy CPM3.SYS.

I'm able to build my bootstrap program and CPMLDR. I've got an old image I used originally that consists of the bootstrap padded out to 256 bytes followed by CPMLDR and with the new COPYSYS that image writes correctly and I can make bootable disks.

With the new builds I get the images padded out with 0s through the start of the bootstrap (4300H which is where the ROM on a Model 4 loads it) and CPMLDR (loads at 8000H). This obviously makes big files and I can't just concatenate them to make a new image file.

I don't recall having another program to read the two generated files and strip out the 0s at the start and I can't find any sources that I would have written (but then again they may have been lost along with the original disk format/verify/copy source and copysys source).

I also have the old image I generated ~30 years ago that doesn't have any of the padding at the start.

I don't see any switches for LINK or L80 to suppress the 0s. Does anyone know of a way to suppress them?

Chuck(G)
December 18th, 2017, 09:38 PM
I'm not quite sure that I understand the question, but I'm going to assume that the CPMLDR is defined by a an ORG and DS pseudo op or label in your bootstrap code?

If so, instead of using a label, try defining the CPMLDR reference as an EQU.

Also note the .PHASE and .DEPHASE directives that say "assemble the code right here, but resolve addresses as if it was somewhere else".

I hope I understand what you're trying to do.

WSM
December 19th, 2017, 06:27 AM
BIOS vs. BDOS reads: The reason DRI used the two different read techniques is that an image read option is using the BIOS to sequentially read an absolute area of the disk that the BDOS does not access (i.e. starting at track 0, sector 0) whereas the file read option uses BDOS calls to access a named image file on a source disk which can be anywhere on the disk and possibly even fragmented.

If I read your post correctly, you converted the image read option logic from BDOS calls to BIOS calls. I would suspect that could cause problems since I can't think of a way to reliably read track 0, sector 0 to create a disk image using only BDOS calls.

One thing to watch out for when converting source to M80/L80 is the use of ASEG, CSEG and DSEG. For programs like COPYSYS that don't use other .REL files or libraries and start with an "ORG 0100h" (i.e. TPA), I usually simply add the M80 "ASEG" directive at the beginning. For the L80 command & parameter I then use "L80 name.REL,name.COM/N/E".

Per Chuck's post, if you want to create a file that only consists of code that executes at an address other than 0100h but is not paddded with leading 0's, you can try the following:

ASEG
ORG 0100h
.PHASE 4300h ; or 8000h
<code>
.DEPHASE
END

In order to prevent confusion, you might want to also change my L80 example to "L80 name.rel,name.IMG/N/E".

Alphasite
December 19th, 2017, 07:23 AM
I'm not quite sure that I understand the question, but I'm going to assume that the CPMLDR is defined by a an ORG and DS pseudo op or label in your bootstrap code?

If so, instead of using a label, try defining the CPMLDR reference as an EQU.

Also note the .PHASE and .DEPHASE directives that say "assemble the code right here, but resolve addresses as if it was somewhere else".

I hope I understand what you're trying to do.

I figured out the switch I was using late last night. For the bootstrap it was [L4300] and for CPMLDR it was [L8000].

Before adding that switch using either LINK or L80 I was getting a CBOOT.COM that's 86 sectors long. Sectors 0 through 83 were all 0s. The bootstrap was in sectors 84 and 85.

My CPMLDR.COM had the same issue only more sectors of all 0s.

With the L switch I'm now files that I should be able to use. I'll be able to test it later to verify.

Alphasite
December 19th, 2017, 07:31 AM
BIOS vs. BDOS reads: The reason DRI used the two different read techniques is that an image read option is using the BIOS to sequentially read an absolute area of the disk that the BDOS does not access (i.e. starting at track 0, sector 0) whereas the file read option uses BDOS calls to access a named image file on a source disk which can be anywhere on the disk and possibly even fragmented.

If I read your post correctly, you converted the image read option logic from BDOS calls to BIOS calls. I would suspect that could cause problems since I can't think of a way to reliably read track 0, sector 0 to create a disk image using only BDOS calls.


I converted the image read from BIOS to BDOS. The code was reading the image from the specified file and not from the disk (it does use BIOS calls to read and write the sectors when copying the system tracks from one disk to the other). The code used BDOS calls to open the file specified in the FCB but then used BIOS calls instead of BDOS calls to read the sectors. I switched that to use BDOS calls instead.

When I converted it I did add ASEG.

Chuck(G)
December 19th, 2017, 07:52 AM
Not at all uncommon, is the idea of boot tracks of a floppy to using different modulation/sector size/interleave than the rest of the disk was used to provide fast booting (and warm-boot) or a "universal" boot (i.e. if your system handles both FM and MFM floppies, it makes a bit of sense to write the boot track as FM, even if it's to put out a message that the rest of the MFM disk can't be read.) So very often, the warm- and cold-boot code would use its own routines.

When using physical sector sizes larger than 128 bytes, it makes sense to read the boot code "in place" rather than running through the extra overhead of a deblocking routine--and if provided by the hardware, to use a multi-sector read, rather than a single-sector one.

Alphasite
December 19th, 2017, 08:37 AM
Not at all uncommon, is the idea of boot tracks of a floppy to using different modulation/sector size/interleave than the rest of the disk was used to provide fast booting (and warm-boot) or a "universal" boot (i.e. if your system handles both FM and MFM floppies, it makes a bit of sense to write the boot track as FM, even if it's to put out a message that the rest of the MFM disk can't be read.) So very often, the warm- and cold-boot code would use its own routines.

When using physical sector sizes larger than 128 bytes, it makes sense to read the boot code "in place" rather than running through the extra overhead of a deblocking routine--and if provided by the hardware, to use a multi-sector read, rather than a single-sector one.

I understand that, this issue applies to reading a file vs physical sectors.

I took a look back at the original source and going through the edits I realized that the original issue was they were using the BIOS SETDMA call (via BDOS call 50) instead of the BDOS call to do it (26) and I just forgot what I had changed at 2:00 AM since I had replaced that section with code I knew worked.

So they were opening the file with the BDOS call, setting the DMA address with the BIOS call, then using BDOS reads to read the record form the file. Unless I'm forgetting the BIOS call to set DMA only applies to BIOS reads and writes and BIOS reads and writes are physical (track and sector) while BDOS reads and writes are for records from files.

They were also incrementing the DMA address by the sector size but didn't use BDOS call 44 to set the number of records to read to match so it was only reading the default 128-byte records. This wouldn't have mattered if the sector size was 128 but in their source they were using 256-byte sectors.

So looking back to fix this all I would have had to do is change the one call to set the DMA from the BIOS call to the BDOS call and then either change the increment of the DMA address to 128 or set the number of records to read at a time to 8 (I'm using 1K sectors). I think it makes more sense to just keep it with the default of 128-byte records since that's more generic.

I can upload the original source if you want to see. I've modified the version I've translated to Z80 mnemonics so that code isn't there now.

Chuck(G)
December 19th, 2017, 08:58 AM
Well,not really--the BIOS read/write calls have to return 128-byte sectors. Unless there's some magic going on in the BDOS, the BIOS "SETDMA" call results in the same outcome as the BIOS call--it's only a "DMA" operation if the host media has 128-byte physical sectors. Otherwise it goes through a BIOS-implemented blocker/deblocker and the notion of "DMA" is lost. It probably would have been better for DRI to abandon the "SET DMA" terminology and use "SET BUFFER ADDRESS" or "SET TRANSFER ADDRESS" instead.

For that matter, calling the unit transferred a "sector" is equally misleading, unless prefixed by "physical" or "logical". The same goes for "track", since CP/M's BIOS interface doesn't implement the idea of a "head" or "side"--the BIOS code has to do all of the transformation into a "track", whatever that really is.

All in all, it would have been better to use "block" addresses and define a "block" as 128 bytes, leaving it to the BIOS to do the arithmetic and mapping. We certainly did that in DX85 and the transition to a hard disk from the OS standpoint was almost effortless.

As CP/M 2.x didn't implement multi-sector I/O, I can understand the sector-by-sector read operations.

Alphasite
December 19th, 2017, 09:37 AM
This is CP/M Plus. The BIOS reads and writes physical sectors and the BDOS does the blocking/deblocking, so a BIOS read will read 1K bytes at a time while the BDOS will read 128 bytes (unless BDOS call 44 is used to set multiple sector reads).

The issue with the DMA calls was they were using the BIOS DMA call for BDOS reads and writes instead of the BDOS DMA call. I'm now curious as to what the DMA address for the BDOS operations would be if you didn't set it. It looks like it's in the BDOS data area at 82H so I'll check there later. Since it wasn't putting the file in memory where it thought it was (1000H) it was writing garbage to the system tracks.

You're right that the terms can be ambiguous unless it's specified as "physical" or "logical" and I've seen physical disk formatters that display the current track up from 0 to 79 for DS 40-track drives and others that will display tracks 0-39 and sides 0 and 1 (I used the latter). The DRI documentation didn't help clear up the confusion. For instance, in the documentation I've seen the BDOS call 44 I mentioned says the functions is "BDOS FUNCTION 44: SET MULTI-SECTOR COUNT" and says register E should contain "Number of Sectors". It then goes on to say "The Set Multi-Sector Count function provides logical record blocking under CP/M 3." What they should have called it is "SET MULTI-RECORD COUNT" and listed E as containing "Number of Records".

Chuck(G)
December 19th, 2017, 10:32 AM
...not to mention schemes that involve "zoned" recording, where the number of sectors per track varies.

CP/M never managed to shake off its beginnings as a simple floppy-based system with IBM 3740-compatible disks. So you wind up with all sorts of work-arounds based on the original. After awhile, the weight of being old gets to be untenable. One wonders how well CP/M would have fared with terabyte disk volumes.

Alphasite
December 19th, 2017, 02:20 PM
I tested my new image and it didn’t work. A quick glance through the image file looks like what’s on my current booting disks so I’ll need to dig a bit. It shouldn’t be anything major.

After I get that fixed then I need to get the disk utility working followed by going through and documenting the console emulations. I have ADM11 and VT52 modes (switchable). There are some limitations in the emulations but they work well enough to run WordStar.

Alphasite
January 2nd, 2018, 05:48 PM
Over the Christmas break I got COPYSYS working as well as a new disk utility.

The issue with COPYSYS was due to a bug in my LDRBIOS and original COPYSYS. This bug has been around for over 30 years. I just didn't notice it before since my original COPYSYS was something I wrote as I didn't have the original source. Since the same bug was in both things worked and it wasn't something I had to deal with once I had it working.

It's now corrected.

Now to add hard drive support. I couldn't afford a hard drive 30+ years ago. Now I have one so why not? The emulator I'm using to debug has support as well.