Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Windows port of John Elliott's ZXCC

380 views
Skip to first unread message

Tom Burnett

unread,
Apr 3, 2015, 8:21:24 PM4/3/15
to
Sorry for the length of this post...

I have ported John Elliott's ZXCC to Windows.

In addition, I've generalized it making it a bit less Hitech C oriented.

In a few days it should be on GitHub for anyone who is interested.

My test script so far that runs with no problems is a follows:

time
erase tlb.com hello.com helloaz.com helloz.com pi.com pi.rel test.rel test.com hello.as hello.obj hello.com temp*
mbasic test
m80 helloz,helloz=helloz
l80 helloz,helloz/n/e
zxcc helloz
bascom test,test=test
ld80 test,obslib/s,test/n/e
zxcc test
f80 pi,pi=pi
ld80 pi,pi/n/e
zxcc pi
azcc helloaz
azas helloaz
azln helloaz.o libc.lib
zxcc helloaz
bdscc hellobds
bdsclink hellobds
zxcc hellobds
htc hello.c
zxcc hello
time

Runtime for the entire script is 1.58(!) seconds on a now-ancient 5 year old
Intel I7-960 processor. And, please notice, two of the three Microsoft
links (both requiring large library searches obslib.rel and forlib.rel) are
done with the notoriously slow ld80 disk-based linker. I still need to
add tests for DRI's and SLR's development programs.

Output (slightly edited where noted for brevity concerning repetitive lines):

K:\zxcc2\zxcc-0.5.7\bin>time
The current time is: 16:46:44.87
Enter the new time:
K:\zxcc2\zxcc-0.5.7\bin>erase tlb.com hello.com helloaz.com helloz.com pi.com pi
.rel test.rel test.com hello.as hello.obj hello.com temp*

K:\zxcc2\zxcc-0.5.7\bin>mbasic test
BASIC-80 Rev. 5.21
[CP/M Version]
Copyright 1977-1981 (C) by Microsoft
Created: 28-Jul-81
39480 Bytes free
1 1
2 4
<count and square to 100 deleted>

K:\zxcc2\zxcc-0.5.7\bin>m80 helloz,helloz=helloz

No Fatal error(s)

K:\zxcc2\zxcc-0.5.7\bin>l80 helloz,helloz/n/e

Link-80 3.44 09-Dec-81 Copyright (c) 1981 Microsoft

Data 0100 013E < 62>

53756 Bytes Free
[0000 013E 1]

K:\zxcc2\zxcc-0.5.7\bin>zxcc helloz

Hello, world from Z-80 assembly.

K:\zxcc2\zxcc-0.5.7\bin>bascom test,test=test

00000 Fatal Error(s)
31717 Bytes Free

K:\zxcc2\zxcc-0.5.7\bin>ld80 test,obslib/s,test/n/e

Link-80 Disk Vers. 3.55 10-Sep-82 Copyright (c) 1981 Microsoft

Data 4000 6406 < 9222>

BASLIB RQUEST
42626 Bytes Free
[4015 6406 100]


K:\zxcc2\zxcc-0.5.7\bin>zxcc test
1 1
2 4
<count and square to 100 deleted - same program as interpreter above>

K:\zxcc2\zxcc-0.5.7\bin>f80 pi,pi=pi
$MAIN

K:\zxcc2\zxcc-0.5.7\bin>ld80 pi,pi/n/e

Link-80 Disk Vers. 3.55 10-Sep-82 Copyright (c) 1981 Microsoft

Data 0103 22A4 < 8609>

44375 Bytes Free
[0208 22A4 34]


K:\zxcc2\zxcc-0.5.7\bin>zxcc pi


BOUNDS ON PI - DOUBLE PRECISION BINOMIAL THEOREM VERSION

N SIDES SIDE LENGTH PI - LOWER BOUND PI- UPPER BOUND
3 8. .765367 3.061467458921 4.959315235374
4 16. .390181 3.121445152258 3.878006734963
<iteration to 20 deleted>

K:\zxcc2\zxcc-0.5.7\bin>azcc helloaz
C Vers. 1.06D 8080 (C) 1982 1983 1984 by Manx Software Systems

K:\zxcc2\zxcc-0.5.7\bin>azas helloaz
8080 Assembler Vers. 1.06D

K:\zxcc2\zxcc-0.5.7\bin>azln helloaz.o libc.lib
C Linker Vers. 1.06D
Base: 0100 Code: 1af7 Data: 01ef Udata: 0250 Total: 001f3a

K:\zxcc2\zxcc-0.5.7\bin>zxcc helloaz
Hello, world from Aztec C.

K:\zxcc2\zxcc-0.5.7\bin>bdscc hellobds
BD Software C Compiler v1.60 (part I)
43K elbowroom
BD Software C Compiler v1.60 (part II)
40K to spare
K:\zxcc2\zxcc-0.5.7\bin>bdsclink hellobds
BD Software C Linker v1.60
Last code address: 0E54
Externals start at 0E55, occupy 0006 bytes, last byte at 0E5A
Top of memory: FE05
Stack space: EFAB
Writing output...
51K link space remaining
K:\zxcc2\zxcc-0.5.7\bin>zxcc hellobds

Hello, world from BDS C.

K:\zxcc2\zxcc-0.5.7\bin>htc hello.c
HI-TECH C COMPILER (CP/M-80) V3.09
Copyright (C) 1984-87 HI-TECH SOFTWARE

K:\zxcc2\zxcc-0.5.7\bin>zxcc hello
Hello, world from HiTech C.

K:\zxcc2\zxcc-0.5.7\bin>time
The current time is: 16:46:46.42
Enter the new time:

------------------

For anyone not familiar with ZXCC, it's a pure software C emulator for
Unix/Linux by John Elliott (i.e. it has no real DRI or other CP/M BDOS
code) that uses directories in the native file system as disk drives.
So there is no disk image for files. This means you can run CP/M programs
native from the command line just the same as any other Windows program
e.g. an M80 (Microsoft's Macro-80) assembly, link and test run of a
program under development ("file") is:
m80 file,file=file
l80 file,file/n/e
zxcc file
(cpm.exe is also created at build time with a simple copy and is identical
to zxcc.exe - type the one your most comfortable with)

In this example, m80.exe and l80.exe are created as part of the build script
of zxcc-windows. They have to be in your path somewhere and they just
run. zxcc is used to run a *.com CP/M program where an *.exe has not been
created, usually the program under development or some less commonly used
program. Note that almost any (no hardware, disk drive or terminal emulation
dependent) program can just be copied into c:\cpm_com and zxcc/cpm will
find it and run it with "zxcc program <args...>". Again, so I don't get
complaints right now, there is no terminal emulation in zxcc-windows yet.
The first release is intended for non-terminal development programs that
are usually TTY I/O based. This will probably change in the not-too-distant
future. If you like the extra features, zxcc-windows should port easily
back to Linux by the use of John Elliott's cpmio library with relatively
little effort and full source code of zxcc-windows is included in the package.
Right now, simple Windows TTY I/O is used with the exception of kbhit()
for console status.

The following programs are created during the build process with the
CP/M binary embedded in the *.exe file. Obviously, the file must be in
your PATH and any support programs in c:\cpm_com\microsoft, c:cpm_com\aztec_c,
etc. Both source and binary form are included for all programs for those
that only want to use the package. However, adding new *.exe files is not
difficult along with a support files directory if needed. It does require
recompilation. To eliminate that necessity, I probably should read the
data referencing program prefixes, names and support directories from an
ini or cfg file, but that's for a later release.

Programs provided as *.exe native Windows files:
Microsoft - M80, F80, mbasic, obasic, bascom, l80, ld80, m80new
(Werner Cirsovius' enhanced M80 - the assembly and name are mine),
cref, lib80 - support files (e.g. baslib.rel obslib.rel, forlib.rel, brun.com,
bcload, etc. are in c:\cpm_com\microsoft

DRI - mac, rmac, link, lib - link.com and lib.com are prefaced with "dri"
as MingW can have problems with programs named "link" or "lib" adding
code when it's not wanted or needed. - support files e.g. *.lib macros
are in c:\cpm_com\dri

Aztec C - All programs - names are prefaced with "az" - support files e.g.
stdio.h, libc.h, libc.lib are in c:\cpm_com\aztec_c

BDS C - All programs - names are prefaced with "bds" - support files
e.g. cc2.com bdscio.h deff*.crl are in c:\cpm_com\bds_c

SLR Systems - All programs - names are prefaced with "slr" - support
files are in c:\cpm_com\slr

Hitech C - All programs - names are prefaced with "ht" - e.g linq.com
(avoid link.com), p1.com, cgen.com, zas.com, etc. are in
c:\cpm_com\hitech_c.
Note - the compiler works both as individual programs prefaced with
"ht" e.g. htzas.exe or with the integrated c.com (htc.com in zxcc-windows).
"htc hello.c" will automate the entire multipass compilation, assembly
and link leave hello.com ready to run with zxcc.

Microshell V2 - called "msh" - support programs e.g. sh.ovl are in
c:cpm_com\other. "exit" to quit.

ZCPR1 - "zcpr" - no support directory, it just runs. "exit" to quit.

DRICCP - "driccp" - no support directory, it just runs. "exit" to quit.

The reason for the automated search for support files by company/product
is so multiple programs that use the same filenames (e.g. stdio.h, libc.lib
and the like) can all peacefully coexist and not interfere with each
other.

Any others needed as native *.exe files? I'm a BASIC, 8080/Z80 assembly
and C person, so these programs are what I use most.

It runs several programs that fail on both Mr. Dantas' and Mr. Takeda's
emulators. They use a very simplistic FCB handlng code that does an
fopen for each access e.g. create (OK, so I used an 'e' for create, it's
actually F_MAKE in DRI-ese - creat in Unix-ese), open, close, seek,
read/write random, read/write sequential or whatever. The bad news is
many programs (especially DRI - Kildall knew what his BDOS would and
wouldn't do) play games with FCB data. So it must be saved and used
on-the-fly if programs don't follow the strict letter of the law. Also,
to run DRI's link.com, lots of non-documented stuff is done to make it
run faster. John Elliott worked all this out. See his comments in the
source code (his and mine-to-be) for details.

I'm working with Marcelo Dantas on his by doing his testing for him to
see if his can't improve the FCB handling to bring more programs on board.
I've never been in contact with Mr. Takeda and it's entirely possible this
kind of low-level detail is beyond the scope of what his intentions are.
I dunno.

I'll let comp.os.cpm know when it's posted. I'm new to GitHub, so there
may be a bit of a learning curve there to climb.

No guarantees, of course, and some things may be impossible in pure C with
no BDOS, but I'll certainly take a look at it if your pet program
doesn't run.

Give me a few days to make sure DRI and SLR programs work OK and clean up all my tracer statements.

Again, sorry for the length of this post.

Tom

Tom Burnett

unread,
Apr 5, 2015, 2:46:32 PM4/5/15
to
>
> Tom

As always, when you announce it's coming and, of course, you're SURE it's already bulletproof, you have problems you didn't expect.

DRI's mac assembler actually closes the *.sym file twice. Apparently, it's no problem for a real BDOS, but if you close a non-open file on Windows (Linux, too!) you'll get an error - specifically errno = 9. This caused mac.com to bail early before the *.hex file was properly closed. I've verified the double close with Marcelo Dantas' RunCPM program and I'd submit a bug report to DRI to get it fixed, but I suspect the response time might be a little long. ;-) Besides, if the real BDOS doesn't mind it, then is it really a bug? Anyway, I've worked around it. Aztec C and Hitech C needed specific workarounds to function also.

I still have SLR to go. The DRI CCP is not working either yet, but that's less important, I think. Zcpr 1.6 and Microshell both appear to work fine if you want to use a CP/M CCP.

It will be on Microsoft codeplex site as soon as it runs my test script successfully and I upload the source code.

Tom


Udo Munk

unread,
Apr 5, 2015, 4:26:50 PM4/5/15
to
On Sunday, April 5, 2015 at 8:46:32 PM UTC+2, Tom Burnett wrote:

> DRI's mac assembler actually closes the *.sym file twice. Apparently, it's no problem for
> a real BDOS, but if you close a non-open file on Windows (Linux, too!) you'll get an error -
> specifically errno = 9. This caused mac.com to bail early before the *.hex file was properly
> closed. I've verified the double close with Marcelo Dantas' RunCPM program and I'd submit
> a bug report to DRI to get it fixed, but I suspect the response time might be a little long. ;-)

See patches.txt at the z80pack repository, excerpt:

The DRI macro assembler RMAC included on all MP/M disks up to release
1.14 has problems under MP/M to properly write a symbol table file.
Replace with rmac.com, this version comes from MP/M distribution disks
and does work under MP/M.

That problem was fixed by DRI, because they had the same problem under MP/M then.
You could try to convert the MP/M .prl assemblers to .com files and see if that works.

Udo Munk

unread,
Apr 5, 2015, 4:36:40 PM4/5/15
to
On Sunday, April 5, 2015 at 10:26:50 PM UTC+2, Udo Munk wrote:

> You could try to convert the MP/M .prl assemblers to .com files and see if that works.

Correcting my self, the MP/M disks include rmac.com and not a .prl version, also
version 1.4 same as the buggy one. Probably was just patched with DDT...

Tom Burnett

unread,
Apr 5, 2015, 4:59:24 PM4/5/15
to
Thank you. I'll try the *.com mac and rmac programs specifically from MP/M. If they work without my patch in place, they will be the basis for the mac.exe and rmac.exe programs produced by my build script.

As I mentioned, Aztec C and Hitech C had their problems also requiring a bit of workaround code. But all that code is what it is. It has to run unchanged I think.

Tom

Tom Burnett

unread,
Apr 5, 2015, 5:38:25 PM4/5/15
to
I didn't realize mac.com is not included with MP/M. Obviously, I never used MP/M back in the day. Anyway, rmac.com from MP/M II runs fine with no patch so that should take of the issue. Mac.com will need the patch to ignore a second close when the file isn't open after the first close. It's all transparent to the user and mac.exe will now assemble the original DRI CP/M 2.2 BDOS source code without problems. I think I'll put that in my test script just because it's a cool thing to do. ;-)

Thanks again,
Tom

Udo Munk

unread,
Apr 5, 2015, 5:52:55 PM4/5/15
to
On Sunday, April 5, 2015 at 11:38:25 PM UTC+2, Tom Burnett wrote:

> I didn't realize mac.com is not included with MP/M. Obviously, I never used MP/M back in
> the day. Anyway, rmac.com from MP/M II runs fine with no patch so that should take of the
> issue. Mac.com will need the patch to ignore a second close when the file isn't open after
> the first close. It's all transparent to the user and mac.exe will now assemble the original
> DRI CP/M 2.2 BDOS source code without problems. I think I'll put that in my test script just
> because it's a cool thing to do. ;-)

Same as CP/M 1 & 2 MP/M came with asm only, mac and rmac were additional products
sold separate from these OS's. CP/M 3 came together with the better development tools,
but this are versions with problems like that, so won't work correct under MP/M or with
this kind of emulation.

I had mac.com as well as rmac.com versions that won't have this bug, rmac.com can be
found in the z80pack repository, a fixed mac.com still might be available somewhere.
If anyone runs into it I would like to know, thanks.

> Thanks again,
> Tom

You're welcome.

Tom Burnett

unread,
Apr 5, 2015, 6:17:21 PM4/5/15
to
I found a corrected mac.com. I just tried it with a rename (so it would bypass my patch based on being named "mac") and it assembles the BDOS source just fine.

The only catch is that it's in disassembled source code. Werner Cirsovius is truly a wizard (as are you). The beautiful irony, of course, is his source code for mac is for Macro-80!

You'll find it here:
http://www.cirsovius.de/CPM/Projekte/Disassembler/Gesammeltes/MAC/MAC-MAC.txt

It assembles with m80/l80 with no problems.

Just to be sure: I ran it with Marcelo Dantas' RunCPM and this is the output and tracers:
I:\cpmtlb4>mac os3bdos
CP/M MACRO ASSEM 2.0
E9EE
CloseFile called
CloseFile fcb data dump
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 4f 53 33 42 44 4f 53 20 50 52 4e 06 00 00 00 .OS3BDOS PRN....
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
017H USE FACTOR
CloseFile called
CloseFile fcb data dump
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 4f 53 33 42 44 4f 53 20 53 59 4d 00 00 00 80 .OS3BDOS SYM....
01 02 03 04 05 00 00 00 00 00 00 00 00 00 00 00 ................
CloseFile called
CloseFile fcb data dump
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 4f 53 33 42 44 4f 53 20 48 45 58 00 00 00 00 .OS3BDOS HEX....
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
END OF ASSEMBLY

I:\cpmtlb4>

Only one call to close the SYM file. Running the other binary does this:
I:\cpmtlb4>mac os3bdos
CP/M MACRO ASSEM 2.0
E9EE
CloseFile called
CloseFile fcb data dump
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 4f 53 33 42 44 4f 53 20 50 52 4e 06 46 54 59 .OS3BDOS PRN.FTY
50 45 00 ff ff ff ff ff ff ff ff ff ff ff ff 73 PE.............s
017H USE FACTOR
CloseFile called
CloseFile fcb data dump
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 4f 53 33 42 44 4f 53 20 53 59 4d 00 00 00 80 .OS3BDOS SYM....
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
CloseFile called
CloseFile fcb data dump
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 4f 53 33 42 44 4f 53 20 53 59 4d 00 00 00 80 .OS3BDOS SYM....
01 02 03 04 05 00 00 00 00 00 00 00 00 00 00 00 ................
CloseFile called
CloseFile fcb data dump
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 4f 53 33 42 44 4f 53 20 48 45 58 00 ff ff 26 .OS3BDOS HEX...&
46 54 59 50 45 00 ff ff ff ff ff ff ff ff ff ff FTYPE...........
END OF ASSEMBLY

I:\cpmtlb4>

Two calls to close the SYM file. No good.

I have no idea if Werner fixed it (I would not put that past him) or if the com file he diassembled already had it fixed. In either case, it's fixed. That will be the mac.exe included in zxcc-windows.

Tom

Udo Munk

unread,
Apr 5, 2015, 6:35:36 PM4/5/15
to
On Monday, April 6, 2015 at 12:17:21 AM UTC+2, Tom Burnett wrote:

> I found a corrected mac.com. I just tried it with a rename (so it would bypass my patch
> based on being named "mac") and it assembles the BDOS source just fine.

Very cool, I thought it might still be somewhere, because way back then we all ran
into this problem and there were fixes for this.

> The only catch is that it's in disassembled source code. Werner Cirsovius is truly a
> wizard (as are you). The beautiful irony, of course, is his source code for mac is for Macro-80!

Yeah, well, somehow we all had m80/l80 available, but rmac/mac/link was another
story ;-)

> You'll find it here:
> http://www.cirsovius.de/CPM/Projekte/Disassembler/Gesammeltes/MAC/MAC-MAC.txt
>
> It assembles with m80/l80 with no problems.

OK, I'll work the fixed version with a link to Werner's site into the z80pack repository,
so that this one is available too.

> I have no idea if Werner fixed it (I would not put that past him) or if the com file he
> diassembled already had it fixed. In either case, it's fixed. That will be the mac.exe
> included in zxcc-windows.

I don't know, but Werner sometimes posts here, maybe he could let us know.
Whatever, nice that your problem is solved.

Udo Munk

unread,
Apr 6, 2015, 12:21:27 PM4/6/15
to
On Monday, April 6, 2015 at 12:35:36 AM UTC+2, Udo Munk wrote:

> OK, I'll work the fixed version with a link to Werner's site into the z80pack repository,
> so that this one is available too.

Done, mac.com build from Werners disassembly is available at the z80pack repository,
notes and link in file patches.txt.

This also is a version 2.0 mac.com, same as the version 2.0 that works under CP/M. I have
assembled a bunch of sources and compared the hex, prn and sym files build by both
versions, everything absolutely identical.

So if anyone needs to run mac/rmac under MP/M or emulations like xxcc, working binaries
are available here: http://www.autometer.de/unix4fun/z80pack/ftp/

Many thanks to Werner, seems the only version around nowadays that includes the
patches for MP/M.

Tom Burnett

unread,
Apr 6, 2015, 3:08:34 PM4/6/15
to
I would think a minor bump to the release number for the MP/M OK release might not be a bad idea. If it signs on as "CP/M MACRO ASSEM 2.1" it would be immediately obvious that this was the patched/fixed version.

Just a thought.

Tom

Udo Munk

unread,
Apr 6, 2015, 3:45:02 PM4/6/15
to
On Monday, April 6, 2015 at 9:08:34 PM UTC+2, Tom Burnett wrote:

> I would think a minor bump to the release number for the MP/M OK release might not be
> a bad idea. If it signs on as "CP/M MACRO ASSEM 2.1" it would be immediately obvious that
> this was the patched/fixed version.
>
> Just a thought.

DRI already was not good with keeping the release numbers straight. If we now change them
decades later that probably will create even more a mess as is. One would need a release
history for every single product to avoid confusion and we don't have a reliable one. So I
prefer to leave it alone as is, but of course anyone could patch the sign on message self
to whatever helps.

In case of rmac and mac it even would be better to remove the faulty 2.0 versions and
substitute them with the working ones, of course they still also work with CP/M 2 & 3.
On the other hand this would destroy a bit of history as it was way back then, and I
don't want to do this.

Any other thoughts?

Tom Burnett

unread,
Apr 6, 2015, 7:23:18 PM4/6/15
to
Not really. I was just thinking it would be useful to easily identify patched versions. Even a "2.X" signon would allow that and everyone would know it wasn't original DRI. Still, I can understand your reluctance to change something almost 40 years old.

The other option is an md5 hash. Yours and mine built from Werner's source code are identical at:
d2468697e0348e903cb16977ee26699c *mac.com

Tom

Udo Munk

unread,
Apr 7, 2015, 7:15:54 AM4/7/15
to
On Tuesday, April 7, 2015 at 1:23:18 AM UTC+2, Tom Burnett wrote:

> Not really. I was just thinking it would be useful to easily identify patched versions.
> Even a "2.X" signon would allow that and everyone would know it wasn't original DRI.
> Still, I can understand your reluctance to change something almost 40 years old.

That were patches from DRI we received in 1980/81, because we found that some
programs didn't work under MP/M. Obviously they just patched programs with ddt
to fix problems, and the release numbers usually weren't changed.

> The other option is an md5 hash. Yours and mine built from Werner's source code are identical at:
> d2468697e0348e903cb16977ee26699c *mac.com

Yep, that is better. Way back then we used some sort of CRC to identify program versions,
because the version numbering from many software vendors was unusable. Several
products, like compilers from Manx included such a crc program and a list with the
numbers for every single file.

Tom Burnett

unread,
Apr 7, 2015, 5:47:19 PM4/7/15
to
Status update:

SLR assembler/linker has turned into more work than everything else combined.

I was having problems with all publicly posted releases of SLR, so I assembled Werner's SLR source. Still no good. He figured out the encryption in the code and, after reading his description, I thought that maybe the Z-80 code wasn't accurate enough. So, after a couple of hours work to replace the Z-80 code with Marat Fayzullin's Z80.c source that I know to be good, still it was a no-go. So, after yet another debugging session, slr180 calls BDOS to set the default drive with 0xFF! Wow. I worked around that so slr180 now works (at least on small files) and now the slrnk linker doesn't work. So more debugging to do.

I'm still working on it...

Tom

marcelo....@gmail.com

unread,
Apr 8, 2015, 8:38:16 AM4/8/15
to
Hi Tom,

When I was rebuilding the UCD Micromumps code I think I successfully used the SLR assembler from here: http://www.s100computers.com/Software%20Folder/Assembler%20Collection/Z80ASMSLR.zip
Documentation here: http://www.s100computers.com/Software%20Folder/Assembler%20Collection/z80asm%20(SLR%20Systems).pdf
This one had no linker though. But maybe it serves as a reference?

Cheers,
Marcelo.

Udo Munk

unread,
Apr 8, 2015, 10:05:06 AM4/8/15
to
On Tuesday, April 7, 2015 at 11:47:19 PM UTC+2, Tom Burnett wrote:

> I was having problems with all publicly posted releases of SLR, so I assembled Werner's
> SLR source. Still no good. He figured out the encryption in the code and, after reading
> his description, I thought that maybe the Z-80 code wasn't accurate enough. So, after a
> couple of hours work to replace the Z-80 code with Marat Fayzullin's Z80.c source that I
> know to be good, still it was a no-go. So, after yet another debugging session, slr180
> calls BDOS to set the default drive with 0xFF! Wow. I worked around that so slr180 now
> works (at least on small files) and now the slrnk linker doesn't work. So more debugging to do.
>
> I'm still working on it...

For z80pack I am using this version:

0D>z80asm

Z80 ASSEMBLER Copyright (C) 1983 by SLR Systems Rel. 1.30 #F10268

%

Just tried, works too under MP/M, so doesn't seem to do weird things with the FCBs etc.

The linker I have used a bit is this one:

0D>slrnk
SuperLinker Copyright (C) 1983-86 by SLR Systems Release 1.31 #SB2067

%

Don't know if it works under MP/M tough.

Tom Burnett

unread,
Apr 8, 2015, 11:30:53 AM4/8/15
to
Thanks both Udo and Marcelo. The problem is Werner's linker. It's broken somehow at least on zxcc-windows.

In zxcc-windows, no write is permitted to any drive other than A:. It reads from a series of directories depending on the program name, but writes are always to the local directory. So it was easier to fix than find.

Here is slr180, slrz80 and slrnk1 on a simple hello, world program with a tracer for a set current drive BDOS call:

K:\zxcc3\bin>slr180 hellslr <--- Werner's - changed to look for *.mac

SLR180 Copyright (C) 1985-86 by SLR Systems Rel. 1.31 #SB3051

select drive: Drive requested is 0
HELLSLR
select drive: Drive requested is 255
End of file Pass 1
select drive: Drive requested is 0
0 Error(s) Detected.
69 Absolute Bytes. 6 Symbols Detected.

select drive: Drive requested is 0

K:\zxcc3\bin>slrz80 hellslr <--- original as downloaded, now works

Z80 ASSEMBLER Copyright (C) 1983 by SLR Systems Rel. 1.30 #F10268

select drive: Drive requested is 0
HELLSLR
select drive: Drive requested is 255
End of file Pass 1
select drive: Drive requested is 0
0 Error(s) Detected.
69 Absolute Bytes. 6 Symbols Detected.
select drive: Drive requested is 0

select drive: Drive requested is 0

K:\zxcc3\bin>slrnk1 hellslr,hellslr/n/e
SuperLinker Copyright (C) 1983-86 by SLR Systems Release 1.31 #AB1234

select drive: Drive requested is 255
0100-FFFF (0045) CE02 Left
select drive: Drive requested is 0

K:\zxcc3\bin>cpm hellslr

Hello, world from SLR180 Z-80 assembly.

K:\zxcc3\bin>

So they all do it. I have no idea what a 255 drive select is when CP/M only goes to drive P:. What I do know is such a request causes libcpmredir to die with a segmentation violation. So, like Henry Ford who said "You can any color you want as long as it's black", my code now says "You can request any drive number you want as long as it's 0 - the current drive - 'cuz it's the only one you can write to, anyway"

The change doesn't break anything else. SLR is now working at least for small files. I need to throw something more challenging at it.

Tom

John Elliott

unread,
Apr 8, 2015, 3:08:03 PM4/8/15
to
Tom Burnett <tbur...@gmail.com> wrote:
> So they all do it. I have no idea what a 255 drive select is when CP/M
> only goes to drive P:. What I do know is such a request causes libcpmredir
> to die with a segmentation violation.

A>sid
CP/M 3 SID - Version 3.0
#a100
0100 mvi c,0e
0102 mvi e,ff
0104 call 5
0107 rst 6
0108 .
#g100

CP/M Error On @: Invalid Drive
BDOS Function = 14
A>

It also fails under CP/M 2, with the error

Bdos Err On @: Select
A>

So while cpmredir shouldn't *crash* when asked to select drive 0FFh, it's
quite within its rights to shut the program down.

Or (under CP/M 3, if the error mode is set appropriately) return an error:

#a100
0100 mvi c,2d
0102 mvi e,fe
0104 call 5
0107 mvi c,0e
0109 mvi e,ff
010B call 5
010E rst 6
010F .
#g100

CP/M Error On @: Invalid Drive
BDOS Function = 14
*010E
#x
-Z-EI A=FF B=040E D=00FF H=04FF S=0100 P=010E RST 06
#

--
John Elliott

Tom Burnett

unread,
Apr 8, 2015, 6:08:32 PM4/8/15
to
John,

It's entirely possible (probable is probably a better word) the "crash" is a direct result of my modifications to cpmredir to get the read PATH by program name/group working the way I wanted. This allows many CP/M development assemblers, compilers and the like to peacefully coexist transparently to the user directly from the Windows command line. So the first five redir_drive_prefix[0 to 4] strings do not work the same way as your original. They are permanently (that is, for the life of the program) set at runtime depending on the program name. Attempts to open for read that fail are retried in order until one succeeds or they all fail. Then the read is done without the running program having a clue where the file really is. I've almost certainly overlooked something to have it just crash. It won't go out until I know what caused it and it's fixed. fcb_drive should just return an error and what, if anything, is done about it is up to the rest of zxcc and/or the running program if the error is returned as is.

It's a port to Windows with some fairly major changes - your original cpmredir (and zxcc for that matter) are not in question.

All that aside - What is the possible purpose of a drive select of 255? And why doesn't it fail on a real BDOS? In theory, the SLR assemblers and linker should never run. They should cause a BDOS Select Error. That's really my question. It's easy to workaround and probably easy to find the problem in my port of cpmredir. If the number is literally used as an index into redir_drive_prefix (and I'll know 2 minutes after this is posted), there's the problem. I'll make sure no illegal reference is done and the function returns no what what the input data.

The program is fairly big and complex. Bugs will happen.

"You put them in one at a time, you get them out one at a time" as told to me when I was young.

Thanks for the info,
Tom

Udo Munk

unread,
Apr 8, 2015, 6:37:19 PM4/8/15
to
On Thursday, April 9, 2015 at 12:08:32 AM UTC+2, Tom Burnett wrote:

> All that aside - What is the possible purpose of a drive select of 255?
> And why doesn't it fail on a real BDOS? In theory, the SLR assemblers
> and linker should never run. They should cause a BDOS Select Error.
> That's really my question.

None, because the a real BDOS/BIOS will return an error for that, and
you'll get the BDOS select error.

So I think I won't really do a select 255 and something else is going
wrong. Could be self modifying code that doesn't execute as expected.

Tom Burnett

unread,
Apr 8, 2015, 6:54:10 PM4/8/15
to
There is some really ugly code in those programs (this from Werner's disassembly). So I think you're right, but it's assembling large programs OK now.

I've put an if statement in the fcb_drive() function of cpmredir that immediately returns an error on anything over 16 anyway.

I'll just bottle up the SLR programs until they run reliably. The BDOS is mine! It does what I want. Period. ;-) Well... mine and John Elliott's. But the result is the same. They are running.

Tom


Tom Burnett

unread,
Apr 8, 2015, 7:21:05 PM4/8/15
to
Just for curiosity, I took my code out that limits the drive select code to zero and just let it call the new fcb_drive() in cpmredir with the bad drive number. The returned failures are completely ignored by the SLR programs and they run fine. That still doesn't explain why the BDOS doesn't fail on real CP/M, however. As Udo suggests, it's probably some tricky/encryption/self modifying code not doing what was intended. However, I've used two different Z80 cores, both the original from Ian Collier and now Marat Fayzullin's. Both do the same thing. The most sinister thing is that they will run with a modified serial number, they just won't write an output file.

Time to move on. It's now running almost all of what my original goal was.

The most fragile thing about it now is it will crash on occasion if it doesn't get proper arguments. Most CP/M programs were awful at parsing arguments that weren't exactly as expected e.g. mac.com with no arguments will produce ".hex" and ".prn" files with no filenames in them. I'll work on that and should be able to provide some help from C before the CP/M program sees anything it doesn't like.

First release should be pretty soon.

Tom

John Elliott

unread,
Apr 8, 2015, 8:08:03 PM4/8/15
to
Tom Burnett <tbur...@gmail.com> wrote:
>
> All that aside - What is the possible purpose of a drive select of 255?
> And why doesn't it fail on a real BDOS?

A drive select of 255 would fail on a real BDOS, so the assembler's
obviously going wrong at an earlier stage. This is where I'd break out the
brute force: add a bevy of printf() to mainloop() to log each instruction
being executed, and what the registers are. Hopefully that will find out
where it's getting the 255 from; if it's a memory location, log accesses to
that location, and so on.

--
John Elliott

Tom Burnett

unread,
Apr 8, 2015, 9:43:20 PM4/8/15
to

> A drive select of 255 would fail on a real BDOS, so the assembler's
> obviously going wrong at an earlier stage. This is where I'd break out the
> brute force: add a bevy of printf() to mainloop() to log each instruction
> being executed, and what the registers are. Hopefully that will find out
> where it's getting the 255 from; if it's a memory location, log accesses to
> that location, and so on.
>
> --
> John Elliott

I did that. It looks absolutely intended. Load E from A when containing 0xFF - then an EXX and when you want it back another EXX and then shortly thereafter the BDOS call that I submit is deliberately intended to stop the show on the spot. And, in a real BDOS, it will.

Looking at Werner's (in effect) source code, it changes the bogus number(s) it calls for the select (a memory location called LogDsk) when you change anything. Maybe some kind of internal CRC to prevent patching? I dunno, but even money says that's the case. Two simple prints to show me which of the two seldsk BDOS calls was the problem gets this with a grep for "select" that I printed looking for which one was causing the issue:
K:\slr\werner_src>grep select trace
select drive called with 00 as argument
select drive called with e7 as argument
select drive called with fd as argument

K:\slr\werner_src>

AND, it's changed enough that it hangs in an infinite loop. I say the user is being screwed with.

It's probably deliberate because it detects tampering, a modified serial number or whatever. It's a turkey. I use (and used back in day) M80/L80 along with (today) George Phillips ZMAC that's almost completely M80 compatible including *.rel output without the memory limitations of any CP/M program including M80. I can make this SLR junk work in spite of the original code.

Life is too short.

Tom

Tom Burnett

unread,
Apr 8, 2015, 10:13:51 PM4/8/15
to


The more I look at it, the less impressed I am. It ain't THAT good of an assembler to warrant this crap.
Example:
;
; Write buffer(s) to disk if serial number is correct
;
WrLock:
push hl
push bc
push de
;
; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
; !!! The next code is dirty tricky. It checks the serial !!!
; !!! number of the assembler and suspends execution if !!!
; !!! no match found against expected one !!!
; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;
ld hl,SN$ / 2 ; Nice, isn't it
ld a,0 ; .. more nice
or a ; .. dtto.
rra ; .. dtto.
adc hl,hl ; .. dtto.
ld b,_SNlen
l6084:
add a,(hl)
inc hl
djnz l6084
ld de,SN_-SN$-_SNlen
add hl,de ; .. dtto.
cp (hl)
;
; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;
pop de
pop bc
pop hl
ret nz ; .. unexpected S/N, so break
push hl

And so forth.

It would take Werner to figure this out. It's over my head in Z80 assembly. I'll stay with C.

Tom

Tom Burnett

unread,
Apr 10, 2015, 1:30:00 PM4/10/15
to
Can I get a favor from Udo, John or someone else?

In CP/M (3.1 preferred), if an F_OPEN is done and the file does not exist, is it created? I know that an F_MAKE is supposed to be called before writes if the file doesn't exist, but I'm running into a fair number of programs that call F_OPEN and then write without ever doing an F_MAKE. Aztec C (more accurately, the assembler and linker) even ignores the error from F_OPEN in ZXCC and then calmly proceeds to write to the file anyway. So it sounds to me as if a real BDOS creates the file on an F_OPEN if it doesn't exist.

I have a generic (not dependent on the program name) workaround working at least for Aztec C and probably for Mix C also, but if I could just add O_CREAT to the open call if the file can't be found in the PATH, life would be simpler.

Thanks,
Tom

miguelv...@gmail.com

unread,
Apr 10, 2015, 1:50:39 PM4/10/15
to
On Friday, April 10, 2015 at 7:30:00 PM UTC+2, Tom Burnett wrote:
> In CP/M (3.1 preferred), if an F_OPEN is done and the file does not exist, is it created?

No.


> Aztec C (more accurately, the assembler and linker) even ignores the error from F_OPEN in ZXCC and then calmly proceeds to write to the file anyway.

Bad behaviour!

Regards.

Tom Burnett

unread,
Apr 10, 2015, 2:01:20 PM4/10/15
to
I know. I didn't write it (BDOS or the target programs), but I have to recreate real BDOS behavior as accurately as possible. Tracers clearly show and open fail and THEN my F_MAKE when a write_sequential is attempted. I intercept the first write_seq call and do an F_MAKE if the file doesn't exist. It works. I'm looking for a better way. My assumption is that all programs won't ignore the F_OPEN error. If writes work after an F_OPEN, it must create it, right? I'm looking for confirmation.

I'm just trying to get as many programs as I can to run. The fewer exceptions based on program name, the better. I think it's probably easier just to use a real BDOS and a disk image. ;-) But Udo, Peter Schorn and others already do that very well.

Tom

Tom Burnett

unread,
Apr 10, 2015, 2:21:57 PM4/10/15
to
On Friday, April 10, 2015 at 10:50:39 AM UTC-7, miguelv...@gmail.com wrote:
Thanks for the information, I think I have a way to work around it.
Tom

Udo Munk

unread,
Apr 10, 2015, 4:04:35 PM4/10/15
to
I also cannot verify this with CP/M 3.1 running on z80pack cpmsim:

2I>
2I>dir exmpl.*
I: EXMPL C : EXMPL COM
2I>cz exmpl
C Vers. 1.06D Z80 (C) 1982 1983 1984 by Manx Software Systems

2I>dir exmpl.*
I: EXMPL C : EXMPL COM : EXMPL ASM
2I>type exmpl.asm
extrn .begin,.chl,.swt
extrn zsave,zret
PUBLIC main_
main_: lxi d,.2
call zsave
LXI H,.1+0
PUSH H
CALL printf_
POP D
LXI H,-72-.2
DAD SP
PUSH H
CALL gets_
POP D
LXI H,-72-.2
DAD SP
PUSH H
LXI H,.1+25
PUSH H
CALL printf_
POP D

Press RETURN to Continue

This version of Aztec C works OK on a CP/M 3.1 system.

Udo Munk

unread,
Apr 10, 2015, 4:08:38 PM4/10/15
to
Also assembler and linker are working:

2I>as exmpl
8080 Assembler Vers. 1.06D

2I>dir exmpl.*
I: EXMPL C : EXMPL COM : EXMPL ASM : EXMPL O
2I>ln exmpl.o -li:c
C Linker Vers. 1.06D
Base: 0100 Code: 1ff0 Data: 01f8 Udata: 0362 Total: 00254e

2I>

Tom Burnett

unread,
Apr 10, 2015, 5:23:19 PM4/10/15
to
The compiler is well behaved. The issue is with the assembler and linker.
I prefer (whenever possible - sometimes it isn't) CP/M emulation that allows direct running of the CP/M program from the Windows command line. So I've ran this code for about 3 years successfully from an older copy of John's ZXCC I ported to Windows:
<Note rv is return from fcb_open() call>
if (rv == 0xFF) {
/* if calling program is azas or azln, and extension matches
* output file names, call fcb_creat first. The original
* programmers should done so, but a complaint at this late
* date to Manx isn't likely to get any action ;-)
* Clearly, an open for an output file extension can be
* interpreted as a write.
*/
if (strcmp(progname, "azas") == 0) {
#ifdef DEBUG
Msg("Aztec assember exception\n");
Msg("azas: filetype is %s\n", typ);
#endif
/* check extension for aztec assembler
* .O = default
* .REL - Microsoft M80 and DRI RMAC assembler
* that the compiler will output with a switch
* Others?
*/
if ((strcmp(typ, "o ") == 0) ||
(strcmp(typ, "O ") == 0) ||
(strcmp(typ, "rel") == 0) ||
(strcmp(typ, "REL") == 0)) {
#ifdef DEBUG
Msg("azas: matching ext found = %s\n", typ);
#endif
ret = fcb_creat(fcb, dma);
#ifdef DEBUG
Msg("azas: = fcb_creat returned %d\n", ret);
#endif
return(ret);
}
}
if (strcmp(progname, "azln") == 0) {
#ifdef DEBUG
Msg("Aztec linker exception\n");
Msg("azln: filetype is %s\n", typ);
#endif
/* check extension for aztec linker
* Just COM (or com) files for output
* Others?
*/
if ((strcmp(typ, "com") == 0) ||
(strcmp(typ, "COM") == 0)) {
#ifdef DEBUG
Msg("azln: matching ext found = %s\n", typ);
#endif
ret = fcb_creat(fcb, dma);


and so forth for azln.

And it works reliably. So when I ran into the same problem with zxcc-windows, I knew what to do. I'm looking for a generic fix that matches the CP/M BDOS. Come to find out, Mix C has the same problem. They all run fine on a real BDOS. I need to emulate (literally) that behavior. Right now, an fcb_open() in zxcc (either version - John's or mine) will not create a file. So a later write fails 'cuz the file doesn't exist. I was willing to make an exception for just azas and azln. Now I need to come up with a generic fix as the issue seems more widespread than just those two. They should call F_MAKE first for a write. Not all of them do unfortunately.

The problem is (as always) a fix for something is breaking something else. I thought I had it ready to go and all was well until rmac gave Phase errors for literally every line. Obviously, rmac not happy with file I/O. It had never failed before that. So I'll come up with something. I think I'm close. Buut then again, those are famous last words of a programmer.

I'm working on it.

Thanks,
Tom

Udo Munk

unread,
Apr 10, 2015, 6:10:29 PM4/10/15
to
On Friday, April 10, 2015 at 11:23:19 PM UTC+2, Tom Burnett wrote:

> And it works reliably. So when I ran into the same problem with
> zxcc-windows, I knew what to do. I'm looking for a generic fix
> that matches the CP/M BDOS. Come to find out, Mix C has the same
> problem. They all run fine on a real BDOS. I need to emulate
> (literally) that behavior. Right now, an fcb_open() in zxcc (either
> version - John's or mine) will not create a file. So a later write
> fails 'cuz the file doesn't exist. I was willing to make an exception
> for just azas and azln. Now I need to come up with a generic fix as
> the issue seems more widespread than just those two. They should call
> F_MAKE first for a write. Not all of them do unfortunately.

OK, then I would implement it like this:

If you get fcb_open() for a not existing file don't create it, CP/M
also won't. But don't throw your internal structure with the fp and
so on away, keep it and set a flag for file open but non existent.

Then if you get an fcb_read() on such a file return EOF.

If you get a fcb_write() on it, create the file and write the stuff and
set your flag to open and existing, so that you know you need to close
it later.

I think that should do for all this programs without programming
exceptions for every not properly written program.

Tom Burnett

unread,
Apr 10, 2015, 6:45:20 PM4/10/15
to
Your suggestion is very close to what I've come with. Essentially, create it when/if a write random or write seq is attempted. Modern OSes are touchy. Without an O_CREAT in an open, it doesn't exist.

Thanks,
Tom

Udo Munk

unread,
Apr 10, 2015, 7:00:01 PM4/10/15
to
On Saturday, April 11, 2015 at 12:45:20 AM UTC+2, Tom Burnett wrote:

> Your suggestion is very close to what I've come with. Essentially,
> create it when/if a write random or write seq is attempted. Modern
> OSes are touchy. Without an O_CREAT in an open, it doesn't exist.

Right, postpone the create, do it later when it becomes necessary.

open() with O_CREAT came with BSD 4.2 in 1983, not really modern,
but a very useful improvement of course.

> Thanks,
> Tom

You're welcome,
Udo

Tom Burnett

unread,
Apr 10, 2015, 8:13:20 PM4/10/15
to
Modern is relative. I meant modern relative to CP/M.

Tom

Tom Burnett

unread,
Apr 10, 2015, 8:53:18 PM4/10/15
to
As usual, I tend to overthink it and make it more complex than it needs to be.

This code is running both Aztec and Mix C and should run anything else with the same issue:

case 0x15: /* Sequential write using FCB */
/*
printf("BDOS 0x15 (F_WRITE SEQ) called - fcb data:\n");
fcb_dump(pde);
*/
/* attempt to do the write */
rc = fcb_write(pde, pdma);
if (rc == 0) { /* all is well - set return registers */
setw(R, rc);
} else { /* does the file exist? */
rc = fcb_stat(pde);
if (rc == 0xff) {
/* create it - should be only the first write */
fcb_creat(pde, pdma);
/* write to it */
setw(R, fcb_write(pde, pdma));
} else {
/* some other failure */
setw(R, 0xff);
}
}
break;

It doesn't break anything else in my test script (mbasic, m80, hitech, mac, rmac, etc.

Onward!

Tom

miguelv...@gmail.com

unread,
Apr 11, 2015, 6:49:00 AM4/11/15
to
IMHO, CP/M emulators must to implement the same real CP/M behaviour.

If a program is buggy, and we don't have its source code (or we can't compile it, whatever the reason is), then we should patch it.

Regards.

Udo Munk

unread,
Apr 11, 2015, 8:09:26 AM4/11/15
to
On Saturday, April 11, 2015 at 2:13:20 AM UTC+2, Tom Burnett wrote:

> Modern is relative. I meant modern relative to CP/M.

Well, it was implemented in BSD at very active CP/M times. And
CP/M has the feature too, unofficially, not documented. At that
time many knew about such features and just used them. The
problem was that the next OS version might break your programming,
if you don't use the documented API only. That happened but
most vendors adapted their software then, so that it would work
again.

Udo Munk

unread,
Apr 11, 2015, 8:13:32 AM4/11/15
to
On Saturday, April 11, 2015 at 2:53:18 AM UTC+2, Tom Burnett wrote:

> This code is running both Aztec and Mix C and should run anything
> else with the same issue:
...
...

Looks good, that should do for all and anything. Much better than
adding workarounds for single programs.

Udo Munk

unread,
Apr 11, 2015, 8:19:00 AM4/11/15
to
On Saturday, April 11, 2015 at 12:49:00 PM UTC+2, miguelv...@gmail.com wrote:

> IMHO, CP/M emulators must to implement the same real CP/M behaviour.

Right, and it also needs to implement the undocumented behaviour, which
is not trivial in this case here, were the complete BDOS is emulated.

> If a program is buggy, and we don't have its source code (or we
> can't compile it, whatever the reason is), then we should patch it.

The case shown here are no bugs, this programs use undocumented
features. If you want you could patch the programs of course, but
for what. On a correct implemented system they just run as is.

miguelv...@gmail.com

unread,
Apr 11, 2015, 9:33:19 AM4/11/15
to
I thing the problem (or feature ;-) ) is in this part of the CP/M 2 BDOS:

--quote--
seqdiskwrite:
;sequential disk write
mvi a,1! sta seqio
;drop through to diskwrite
;
diskwrite: ;(may enter here from seqdiskwrite above)

..snipped code..

;check for end of extent, if found attempt to open
;next extent in preparation for next write
cpi lstrec ;vrecord=lstrec?
jnz diskwr3 ;skip if not
;may be random access write, if so we are done
;change next
lda seqio! cpi 1! jnz diskwr3 ;skip next extent open op
;update current fcb before going to next extent
call setfcb
call open$reel ;rmf=false
--unquote--

I think that in an unopened FCB, but with the appropiate fields filled with zeroes, the BDOS creates the 1st extent, thinking that was the next, not the first.

Bug or feature, I don't know, but it seems dangerous anyway ;)
0 new messages