RC2014 & CP/M: a few questions

230 views
Skip to first unread message

Michelle Lawson

unread,
Nov 27, 2025, 6:21:37 PMNov 27
to RC2014-Z80
Looks like it won't be that much longer than I can start getting ready to fire this thing up, and I'd like to get as much set up as possible so it is smooth sailing right into a CP/M prompt. So I've been mulling these questions over in my head and figured now is as good as any to spring them. And thanks for everyone's help.

1. TPA starts at 0100h, but how high uo can I go before I slam into the CCP and start corrupting the OS; given an out of the box base Pro system?

2. Is there a listing somewhere of the I/O port configuration for the boards that make up an out of the box base Pro system running the CP/M 2.2 that is on the supplied CF card?

3. Is there something that shows, or describes, the required jumper config for the boards that are part of the Pro system, intending to run CP/M 2.2?

Phillip Stevens

unread,
Nov 27, 2025, 10:36:16 PMNov 27
to RC2014-Z80
On Friday, 28 November 2025 at 07:21:37 UTC+8 Michelle Lawson wrote:
1. TPA starts at 0100h, but how high uo can I go before I slam into the CCP and start corrupting the OS; given an out of the box base Pro system?

Every time you run a command it will be evaluated by the CCP as either inbuilt (DIR, ERA, etc), or as a transient program. Once the command is loaded into RAM at 0x0100 and started the CCP is considered “dead” and is reloaded upon return from the command. Therefore your transient program can use all the way up to FBASE which is the start of BDOS. That 16 bit address (the start of BDOS) is alway found in 0x0006 following the JP instruction in 0x0005.

Part of the CP/M operating process is to reload CCP and BDOS at the end of each transient instruction. Therefore there is very little state information held by CP/M. Mainly state information will be held in files which are used by SUBMIT (for example).
 
2. Is there a listing somewhere of the I/O port configuration for the boards that make up an out of the box base Pro system running the CP/M 2.2 that is on the supplied CF card?

Here’s the spreadsheet that contains a list of all RC2014 modules. 
3. Is there something that shows, or describes, the required jumper config for the boards that are part of the Pro system, intending to run CP/M 2.2?

Check Spencer’s documentation. It is  quite complete.

Good luck.
P.

Michelle Lawson

unread,
Dec 3, 2025, 8:54:34 AMDec 3
to RC2014-Z80
Thanks Phillip. I've been thinking about this since I read your reply and got to thinking; 'what if my program never stops processing'? As in, once it loads, it constantly runs, and just uses the OS for disk I/O, console I/O, printer I/O, etc. If it reloads CCP & BDOS after each BDOS interaction, then reloading CCP would wipe out my code if I did use up to FBASE. Granted, I am far from being any kind of CP/M 'guru' but, for my own sanity, might it be best to keep my stuff below where CCP runs?

Phillip Stevens

unread,
Dec 3, 2025, 10:28:03 AMDec 3
to RC2014-Z80
On Wednesday, 3 December 2025 at 21:54:34 UTC+8 Michelle Lawson wrote:
Thanks Phillip. I've been thinking about this since I read your reply and got to thinking; 'what if my program never stops processing'? As in, once it loads, it constantly runs, and just uses the OS for disk I/O, console I/O, printer I/O, etc. If it reloads CCP & BDOS after each BDOS interaction, then reloading CCP would wipe out my code if I did use up to FBASE. Granted, I am far from being any kind of CP/M 'guru' but, for my own sanity, might it be best to keep my stuff below where CCP runs?

Hi Michelle,

I’m sorry that I’ve caused confusion by being loose with language. I saw where I said “instruction” rather than “command”. What I meant was the same thing. Every time you return from a Transient Program, a well behaved Transient Program returns by execution of a warm reboot, which reloads the CCP and BDOS code before running the CCP again to present a command prompt.

The return is typically done with a JP 0x0000 or with a RST0 instruction (which will be provided by the CRT0 if you’re using a C compiler for your program). If you’re writing assembly, that should be done by you as the last instruction of a well behaved program.

You can call BDOS functions or even the BIOS functions as often as you like and your Transient Program will not reload the CCP or BDOS.
(unless you call the RESET - BDOS function 0 specifically).

A summary of BDOS calls is provided here.

I would have fixed my comment to be more precise, but unfortunately Groups doesn’t allow for human frailty.

Hope this helps.
P

Phillip Stevens

unread,
Dec 3, 2025, 10:54:08 AMDec 3
to RC2014-Z80
On Wednesday, 3 December 2025 at 23:28:03 UTC+8 Phillip Stevens wrote:
On Wednesday, 3 December 2025 at 21:54:34 UTC+8 Michelle Lawson wrote:
Thanks Phillip. I've been thinking about this since I read your reply and got to thinking; 'what if my program never stops processing'? As in, once it loads, it constantly runs, and just uses the OS for disk I/O, console I/O, printer I/O, etc. If it reloads CCP & BDOS after each BDOS interaction, then reloading CCP would wipe out my code if I did use up to FBASE. Granted, I am far from being any kind of CP/M 'guru' but, for my own sanity, might it be best to keep my stuff below where CCP runs?

The return is typically done with a JP 0x0000 or with a RST0 instruction (which will be provided by the CRT0 if you’re using a C compiler for your program). If you’re writing assembly, that should be done by you as the last instruction of a well behaved program.

A summary of BDOS calls is provided here.

There’s a much more detailed view of what happens here in Section 5.1.


To see what a CRT0 (used to wrap your C code by the compiler) looks like, there’s one here for CP/M. Your program will start from _main. Everything prior to calling _main and after the return from _main is provided by the compiler / linker. On exit it jumps to the __cpm_base_address which initiates the warm reboot.


Michelle Lawson

unread,
Dec 17, 2025, 11:01:09 AM (2 days ago) Dec 17
to RC2014-Z80
I got to thinking of a few more questions.....

1. The SIO-2 board has two serial ports. Port 1 is obviously for the console and thus it's code is baked into CP/M as the CONSOLE. But what about Port 2, is it baked into the provided CP/M, as say the PUNCH/READER; or does Port 2 rely on some external program for use?

2. And if it is an external program, which one(s), and is it provided on the supplied CF Card?

3. Along with that, is the source code for the external program(s) available in case one might want to modify it, or include it in some other program?

Thanks,

Dave White

unread,
Dec 17, 2025, 7:30:13 PM (2 days ago) Dec 17
to RC2014-Z80
Port two isn't tied into anything in CP/M, it's just available on the chip so is free for you to use as you wish.

Michelle Lawson

unread,
Dec 17, 2025, 7:57:46 PM (2 days ago) Dec 17
to rc201...@googlegroups.com
Thanks Dave. Somewhat nice to know I have full control (hopefully) over Port 2 on the SIO-2 serial card. That said I'd like to use the same initialization routines for Port 2 as is Used on Port 1, with obvious changes to the I/O port values. Any idea where I can find that code; per chance?

--
You received this message because you are subscribed to the Google Groups "RC2014-Z80" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rc2014-z80+...@googlegroups.com.
To view this discussion, visit https://groups.google.com/d/msgid/rc2014-z80/08617b21-db62-4563-96c6-efbfa814217dn%40googlegroups.com.

Phillip Stevens

unread,
Dec 17, 2025, 9:01:20 PM (2 days ago) Dec 17
to RC2014-Z80
On Thursday, 18 December 2025 at 00:01:09 UTC+8 Michelle Lawson wrote:

1. The SIO-2 board has two serial ports. Port 1 is obviously for the console and thus it's code is baked into CP/M as the CONSOLE. But what about Port 2, is it baked into the provided CP/M, as say the PUNCH/READER; or does Port 2 rely on some external program for use?

There is a level of abstraction built into the standard CP/M implementation which supports port reassignment, and with RomWBW there is an additional level of abstraction  that enables further customisation.

The best place to start is with the STAT command, specifically STAT VAL:

A>stat val:

Temp R/O Disk: d:=R/O
Set Indicator: d:filename.typ $R/O $R/W $SYS $DIR
Disk Status  : DSK: d:DSK:
User Status  : USR:
Iobyte Assign:
CON: = TTY: CRT: BAT: UC1:
RDR: = TTY: PTR: UR1: UR2:
PUN: = TTY: PTP: UP1: UP2:
LST: = TTY: CRT: LPT: UL1:
A>

Here we can see the virtual ports available in CP/M CON: RDR: PUN: LST:, and the physical ports which are realised by the CP/M BIOS CRT: TTY: PTR: PTP: LPT: etc, and BAT:.
The STAT command allows us to assign any physical port to the provided virtual ports in a convenient way. It is also possible to use BIOS calls to modify the IOBYTE (0x0003) or even to write to it directly as this is where the serial port mapping is held.

Implementation of the CP/M serial ports is done in the BIOS. Every BIOS has a slightly different implementation. But for the default CP/M provided by Spencer the implementation is SIO/2 Port A and Port B are tied to the CRT: and TTY: ports, unless there is a BAT: rerouting active.

In CP/M-IDE the implementation is essentially the same, but it is slightly easier to read as I've added documented for understanding.

So to answer your question, the BIOS implementation can support many different physical ports, but in the specific implementation only two are provided, being SIO/2 A and B.

And, just to point out that RomWBW has a second "proprietary" remapping of multiple (I don't know that maximum, but we're talking more than 8) physical ports to any of the BIOS ports.

2. And if it is an external program, which one(s), and is it provided on the supplied CF Card?

The mapping is done by setting bits in the IOBYTE. There is a program provided (STAT) and it is found on the CF card.
 
3. Along with that, is the source code for the external program(s) available in case one might want to modify it, or include it in some other program?

The program logic is pretty straightforward, once you understand how the IOBYTE works. In the end it just pokes the byte at 0x0003 with the desired port mapping.

Hope this helps.
Phillip

Michelle Lawson

unread,
Dec 17, 2025, 9:24:23 PM (2 days ago) Dec 17
to rc201...@googlegroups.com
Thanks Phillip. I guess what I am looking for is the routine that is used to setup/initialize Port A of the SIO-2 board, so I can change the hardware port numbers, and re-use the code to initialize Port B similarly. Code that loads the various registers in the SIO-2 chip to allow me to send & receive data through it.

--
You received this message because you are subscribed to the Google Groups "RC2014-Z80" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rc2014-z80+...@googlegroups.com.

Phillip Stevens

unread,
Dec 17, 2025, 10:05:13 PM (2 days ago) Dec 17
to RC2014-Z80
On Thursday, 18 December 2025 at 10:24:23 UTC+8 Michelle Lawson wrote:
Thanks Phillip. I guess what I am looking for is the routine that is used to setup/initialize Port A of the SIO-2 board, so I can change the hardware port numbers, and re-use the code to initialize Port B similarly. Code that loads the various registers in the SIO-2 chip to allow me to send & receive data through it.

So let me answer the literal question, and then add some better code.

The standard RC2014 BIOS initialisation of both Port A and Port B of the SIO/2 is here. The send and receive code for Port A and Port B is here.
But, that code is a) spaghetti b) is difficult to read, is not run in IM2 interrupt (fast) mode, and d) has a bug that the receive interrupt doesn't drain the SIO hardware buffer.

Ok, so the SIO/2 has a long history and people have written nice things to make it easy to use.
I've taken some of those things, and added documentation to make the code easy to understand.

So now, let's look at how CP/M-IDE does this same setup.
The code is tightly tied to the z88dk RC2014 target and build system, so some of the code is located there.
To initialise the SIO/2 there is a small program that pushes bytes into the registers using a table of configuration specifically for CP/M-IDE.

The code for the interrupt system, including a test to ensure the receive buffer is empty before leaving the interrupt, is here. The IM2 mode allows for each different interrupt type to be handled by its own code, resulting in shorter / faster handling.
The input getc and output putc code is found from here.

Cheers,
Phillip

Michelle Lawson

unread,
Dec 17, 2025, 10:44:07 PM (2 days ago) Dec 17
to rc201...@googlegroups.com
Thanks Phillip. I suspect that is exactly what I am looking for. I've been going though the spec sheets for that chip and trying to map out what I would 'think' are the bit configurations for each of the write registers. The init process is nice and linear and just the stuff I can grasp; and I'll add comments along the way. I'm kinda big on documentation and code comments because I hate to relearn something months down the road. But, in what I am hearing, interrupts are used.... Hmm, I figure that needs to happen for the CP/M Console side of things, but could I turn them off for the Port B side? Maybe for portions of code I write that don't require interrupts.... Or is it a case that if you turn it off for one port, it turns it off for both..... Well, the learning will continue, until the brain improves..... Thanks again

--
You received this message because you are subscribed to the Google Groups "RC2014-Z80" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rc2014-z80+...@googlegroups.com.

Phillip Stevens

unread,
Dec 17, 2025, 11:49:09 PM (2 days ago) Dec 17
to RC2014-Z80
On Thursday, 18 December 2025, Michelle Lawson wrote:
Thanks Phillip. I suspect that is exactly what I am looking for. I've been going though the spec sheets for that chip and trying to map out what I would 'think' are the bit configurations for each of the write registers. The init process is nice and linear and just the stuff I can grasp; and I'll add comments along the way. I'm kinda big on documentation and code comments because I hate to relearn something months down the road. But, in what I am hearing, interrupts are used....

Yes. The SIO/2 is a Zilog device, which supports IM2. This is a Zilog specific feature, and I'd say no non-Zilog devices are capable of IM2 (I'm sure someone will provide a counter example ;-) ). It is very useful as the interrupt is vectored (steered) to precisely the code required (across a range of Zilog devices, including CTC, DMA, PIO and SIO) and interrupts are daisy chained. There is no need to read a status byte to determine whether it is a transmit, receive or error interrupt, on either port. IM2 is therefore much faster than IM1 (and IM0).

Unfortunately the standard RC2014 CP/M does not use IM2. Hence it needs to interrogate the SIO/2 in its interrupt status byte to see what has happened, before handling it.

Both CP/M-IDE and RomWBW do implement IM2 for the SIO/2. Hence they both need to provide an interrupt vector table for the SIO, and a high byte of the vector table address in their setup routines.
 
Hmm, I figure that needs to happen for the CP/M Console side of things, but could I turn them off for the Port B side? Maybe for portions of code I write that don't require interrupts.... Or is it a case that if you turn it off for one port, it turns it off for both..... Well, the learning will continue, until the brain improves..... Thanks again

Apologies for saying but, the main reason that you (and anyone) are using a CP/M operating system is that you do not need to get involved in rewriting the BIOS code, any more than you would for Windows or Linux.

The Port B of the SIO/2 is already fully initialised and ready to use in every CP/M available for the RC2014.
It can be accessed using standard BDOS calls, and will be directed based on the values in the IOBYTE.

Of course learning is the exception to this rule. IMHO, the best place to learn about configuring serial ports is to get a ROM burner, and then play with an "on the metal" build. That is very accessible and the learning path most people take with assembly. Zaks has some good initial code for this kind of learning. And, read the SIO technical manual too. You can use the code examples I already linked to build your own solution.

But before then, you IMHO should play with writing assembly and running it from within MSBASIC and for that the RC2014 MSBASIC has a HLOAD command that can be used to upload your assembled programs. MSBASIC has a very simple BIOS too, which exposes one serial port (on that ACIA), but there's nothing stopping you ignoring (overwriting) the default settings here and uploading your own code (which will not break the ROM MSBASIC code).

Cheers,
Phillip

Ed Silky

unread,
Dec 18, 2025, 12:39:45 AM (yesterday) Dec 18
to rc201...@googlegroups.com
Hi Michelle,
Phillip gave you a lot of great information, but to answer one of your specific questions; The SIO can be configured to use interrupts for Channel A and not for Channel B (use polling for it). That would be configured using WR1 of each of the channels. However, you will still have some interrupt configuration done through Channel B, as WR2 is the base interrupt vector value and RR2 is the modified interrupt vector value (modified based on the highest priority interrupt source within the chip), but those registers are only accessed through the Channel B register set.

Hope that helps,
Ed  

--
You received this message because you are subscribed to the Google Groups "RC2014-Z80" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rc2014-z80+...@googlegroups.com.

Michelle Lawson

unread,
Dec 18, 2025, 11:21:26 AM (yesterday) Dec 18
to RC2014-Z80
A lot to digest is an understatement. And some extremely great info too. The comments in the cbios128 code ( ; Check if there is a char in channel A &  ; If not, there is a char in channel B ) seem to imply that either, or both, could be used as the console; if I read that correctly. If that is the case I could connect channel A up to my RS232 to Ethernet dongle and have network access, and connect channel B to a locally connected dumb terminal, by setting Clk2 to .6144 to get 9600 baud.  That sure adds some versatility to things.

I did copy over the channel B initialization code to figure out what it is doing, and other than the interrupt stuff, it matched pretty much what I assumed. The differences were with regards to interrupts, Auto Enable, and the DTR line, given it isn't even connected. And it told me what the clock divisor was set to, 64x. Given these facts, and my total lack understanding, or ever having used, interrupts, it's probably best to leave that be the way it is. I can easily work around that and would rather get the system working without the potential of throwing a wrench in things by my fiddling about. 

As a side note/question; what address equates to CBASE in the Pro system running CP/M 2.2? From what I see in cbios128.asm, CBASE is 0D000h. Unless I am misreading that, that is the value I will go with. And thank you all again for helping me along my 'RC2014 Path To Enlightenment'. 

Ed Silky

unread,
Dec 18, 2025, 1:56:07 PM (yesterday) Dec 18
to rc201...@googlegroups.com
Hi Michelle,

On programming the SIO, if you do decide to do that, I should have also mentioned that CHB WR1 bit D2 (Status Affects Vector) controls both channels. So, if you are reprogramming CHB after both channels have been configured by something else that is using CHA, you will need to maintain the state of that bit or you might mess up whatever is using CHA. For example, in the cbios128.asm that Phillip pointed you to, CHB-WR1-D2 is written with a 0 (status does not affect vector), so you would want to make sure that you also write CHB-WR1-D2 with 0.

You mention the cbios128 code checking if there is a character in A, and if not, there is a character in B... Had it used 'Status Affects Vector' it wouldn't need to do that check. It could immediately go to the correct routine (CHA character available or CHB character available).

-Ed

Phillip Stevens

unread,
Dec 18, 2025, 11:16:48 PM (20 hours ago) Dec 18
to RC2014-Z80
On Friday, 19 December 2025, Ed Silky wrote:
On programming the SIO, if you do decide to do that, I should have also mentioned that CHB WR1 bit D2 (Status Affects Vector) controls both channels. So, if you are reprogramming CHB after both channels have been configured by something else that is using CHA, you will need to maintain the state of that bit or you might mess up whatever is using CHA. For example, in the cbios128.asm that Phillip pointed you to, CHB-WR1-D2 is written with a 0 (status does not affect vector), so you would want to make sure that you also write CHB-WR1-D2 with 0.

You mention the cbios128 code checking if there is a character in A, and if not, there is a character in B... Had it used 'Status Affects Vector' it wouldn't need to do that check. It could immediately go to the correct routine (CHA character available or CHB character available).

Yes. Absolutely. But (one of) the issues with the default CP/M implementation is that it doesn't exploit IM2 capabilities at all. While the SIO can differentiate the cause of the interrupt and vector accordingly, the code provides just one routine for both channels, and doesn't handle error cases at all.

Both CP/M-IDE and RomWBW do provide proper IM2 vectored routines.
 
On Thu, Dec 18, 2025, Michelle Lawson wrote:
A lot to digest is an understatement. And some extremely great info too. The comments in the cbios128 code ( ; Check if there is a char in channel A &  ; If not, there is a char in channel B ) seem to imply that either, or both, could be used as the console; if I read that correctly. If that is the case I could connect channel A up to my RS232 to Ethernet dongle and have network access, and connect channel B to a locally connected dumb terminal, by setting Clk2 to .6144 to get 9600 baud.  That sure adds some versatility to things.

 Yes. That's right. Both channels are configured and active. One is the CRT: the other is the TTY:.
To which CP/M port they are routed to depends on the configuration in the IOBYTE.
Either CRT: or TTY: can be the console CON:, depending on how you set it.
 
As a side note/question; what address equates to CBASE in the Pro system running CP/M 2.2? From what I see in cbios128.asm, CBASE is 0D000h. Unless I am misreading that, that is the value I will go with. And thank you all again for helping me along my 'RC2014 Path To Enlightenment'.

Yes. That's right.

However, the FBASE, the base of BDOS, is loaded into 0x0006 on boot. This is the address you need to refer to.
CBASE is not further useful, except as the initial address to jump to initialise the CCP as done by the BIOS.

It is common for a C compiler CRTO to place the stack directly below the FBASE (which overwrites some of the CCP) as it is guaranteed that the CCP will be reloaded once the application program is completed. (Here the stack pointer is set to the address found in 0x0006, for example, which with decrement before push is just below the FBASE).
 
Of course learning is the exception to this rule. IMHO, the best place to learn about configuring serial ports is to get a ROM burner, and then play with an "on the metal" build. That is very accessible and the learning path most people take with assembly. Zaks has some good initial code for this kind of learning. And, read the SIO technical manual too. You can use the code examples I already linked to build your own solution.

Usually I would read the documentation first, and then prepare a set of plain English references to avoid needing to remember all the bit values.

Then when configuring these references can be used to make the configuration clear and easy to read.
Using a routine found in "Assembly Language Subroutines", Leventhal (1983) (very much worth reading/having),
you can program the SIO and other Zilog devices.

Cheers,
Phillip

Ed Silky

unread,
Dec 18, 2025, 11:42:06 PM (20 hours ago) Dec 18
to rc201...@googlegroups.com
Hi Phillip,
But (one of) the issues with the default CP/M implementation is that it doesn't exploit IM2 capabilities at all. 
Yes, I understand that, but I was trying to provide some information to Michelle about the SIO and its capabilities.
-Ed


--
You received this message because you are subscribed to the Google Groups "RC2014-Z80" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rc2014-z80+...@googlegroups.com.

Ed Silky

unread,
12:56 AM (18 hours ago) 12:56 AM
to rc201...@googlegroups.com
Phillip,
Your statement: 
 it doesn't exploit IM2 capabilities
is more correct than your earlier statements:
is not run in IM2 interrupt (fast) mode
and
Unfortunately the standard RC2014 CP/M does not use IM2

The code you provide references to does use Interrupt Mode 2. It puts a vector into the SIO CHB-WR2 here:
and into the Z80 here:
and it sets IM2 here:
With the interrupt routine address stored here:
So, it is using Interrupt Mode 2 (IM2), it's just not getting much benefit from it.

I only point this out, because people that are new to the Z80 that are reading the code that you linked to might get confused. It is using Interrupt Mode 2, not Interrupt Mode 0 or Interrupt Mode 1. I've never seen IM0 used with a Zilog peripheral device (could you put a RST opcode in the vector register?).

-Ed

Phillip Stevens

unread,
6:27 AM (13 hours ago) 6:27 AM
to RC2014-Z80
On Friday, 19 December 2025, Ed Silky wrote:
Phillip,
Your statement: 
 it doesn't exploit IM2 capabilities
is more correct than your earlier statements:
is not run in IM2 interrupt (fast) mode
and
Unfortunately the standard RC2014 CP/M does not use IM2

The code you provide references to does use Interrupt Mode 2. It puts a vector into the SIO CHB-WR2 here:
So, it is using Interrupt Mode 2 (IM2), it's just not getting much benefit from it.

I only point this out, because people that are new to the Z80 that are reading the code that you linked to might get confused. It is using Interrupt Mode 2, not Interrupt Mode 0 or Interrupt Mode 1. I've never seen IM0 used with a Zilog peripheral device (could you put a RST opcode in the vector register?).
 
Ed.
Yes. You're quite right.
Unfortunately I didn't read the code properly before commenting, and there's no second bite with Google Groups, so a falsehood or mistake remains for ever.
Oh well.

However, there is still a significant advantage in using IM2 as opposed to IM1 with CP/M, even where the advantage of vectored interrupts is not exploited.
I guess you know what it is but, for the curious, it has to do with the CP/M debuggers DDT, SID, and ZSID.

P.

Michelle Lawson

unread,
10:35 AM (9 hours ago) 10:35 AM
to RC2014-Z80
Hmmm, with all this info, I'm thinking it is best for me to just let the base RC2014 CP/M 'Out Of The Box' implementation stay as it is. Then just use BDOS calls as needed to slowly get into the CP/M 'pool'. I am still a bit confused over the " the FBASE, the base of BDOS, is loaded into 0x0006 on boot. This is the address you need to refer to" thing. If I just run with what came with the kit, as it comes loaded on the CF Card, and without modification, shouldn't that address always be the same? If not, who, or what, changes it? I have two other CP/M machines, one S-100 and the other an SBC, and I never did more than run what it came built as. So, a big head scratch......
Reply all
Reply to author
Forward
0 new messages