• Please review our updated Terms and Rules here

Program load not 0100h best practive

One caution about David's example: That is assuming the file already exists - and you want to overwrite it (with a caveat). You want to use BDOS function 22 (16H) MAKE FILE to create a new file. Beware that using OPEN-WRITE or MAKE-WRITE can have undesirable consequences if a file by that name already exists. The typical sequence used is OPEN, if file exists warn or abort, then MAKE, then WRITE..., then CLOSE. If you are only warning about the file existing, and the user says "yes", then call DELETE to make sure the old file is gone. CP/M is pretty simplistic about duplicate file handling, so you need to delete any previous file to be sure you are starting new. Otherwise, you may get unwanted data in the file - for example if you overwrite a large file with a smaller one you will still have parts of the old, larger, file there.
 
First thing I have to do is get the two serial ports to actual function. And with the holidays, I may have to put stuff on hold for a week or two. Under duress I might add.......
 
You have me curious now... What serial ports are you using? Are they something you made yourself or an off-the-shelf item? I never learned to use the Zilog SIO, but the Intel 8251's that the PC used were easy to use and the later ones came with great features, like a 64 byte fifo ( (750 model ) which made them particularly useful in a polling environment, since you get a decent amount of time before they fill up, even at higher speeds.
 
Here it is. At least a start of it. I'm starting to do some debugging. The left hand connections are the STD Bus connectors.
 

Attachments

  • SerialIOv3.pdf
    31.5 KB · Views: 5
Ah, the infamous 8251. I've been programming those recently to do support for the Heath H8/H89 cassette tape board. I thought that PCs used the 8250, though... which has a very different software interface. Maybe the earliest PCs used the 8251? I thought they were even getting hard to come by. The 8250 designs live on in modern chips, even having 2 and 4 complete 8250's on a die.

Just a note about polling vs. interrupts. Contrary to popular belief, interrupts are not the fastest way to receive data over a serial port. If it is time constrained (i.e. high bauds), you need to use a dedicated poll loop to get the best throughput. I see you have hard-wired the baud to 9600, which may be fairly slow depending on your CPU clock. But, the nagging problem with downloads is unexpected interrupts from other sources causing the receive to fall behind. This includes the "fire hose" protocol if trying to periodically write data to disk. If your system has spontaneous interrupts (like the Heath systems "2mS Clock") you may have issues keeping up.
 
Actually, Jameco still carries them; albeit refurbished (equipment pulls?). I basically pulled the circuit from what the CPUville card has on it, and added some interface glue chips. I'm probably gonna have to tweak the data bus direction control parts a bit though. We will see.

1671503747452.png
 
That puts the FCB for file.com automatically at 005C

Be careful about doing this on a Z80 system, 0066 is the NMI vector.

Just a note about polling vs. interrupts. Contrary to popular belief, interrupts are not the fastest way to receive data over a serial port. If it is time constrained (i.e. high bauds), you need to use a dedicated poll loop to get the best throughput.

What interrupts do is let your serial input be buffered while your "foreground" task is busy doing something like writing a sector to disk. You can make your serial receive loop as fast as you want, but once you have to write something to disk you've lost your real-time response.
 
I always wondered what CP/M did about the NMI - I figured I'd just page in the startup ROM with it and remove the zero-page when I get around to making the hardware. Then it doesn't matter about the FCB.

I assume the default position of CP/M about the NMI is "It doesn't exist"?
 
Be careful about doing this on a Z80 system, 0066 is the NMI vector.
...
Any Z80 system that supports CP/M must not interfere with CP/M use of page 0. If a platform uses NMI, it must do so in a way that does not corrupt that part of memory. For example, the Kaypro uses NMI for a floppy I/O completion, and it ensures that the program does not run while the I/O is pending, and it saves 3 bytes at 0066H and restores them after the NMI. CP/M programmers DO NOT need to be concerned with whether a platform uses NMI. If a platform does not use NMIs in a CP/M-compatible way, there's nothing an application programmer can do about it.
 
Ah, the infamous 8251. I've been programming those recently to do support for the Heath H8/H89 cassette tape board. I thought that PCs used the 8250, though... which has a very different software interface. Maybe the earliest PCs used the 8251? I thought they were even getting hard to come by. The 8250 designs live on in modern chips, even having 2 and 4 complete 8250's on a die.

Just a note about polling vs. interrupts. Contrary to popular belief, interrupts are not the fastest way to receive data over a serial port. If it is time constrained (i.e. high bauds), you need to use a dedicated poll loop to get the best throughput. I see you have hard-wired the baud to 9600, which may be fairly slow depending on your CPU clock. But, the nagging problem with downloads is unexpected interrupts from other sources causing the receive to fall behind. This includes the "fire hose" protocol if trying to periodically write data to disk. If your system has spontaneous interrupts (like the Heath systems "2mS Clock") you may have issues keeping up.
So, this is what I have to start. I am fiddling with some test code using BASIC just to get some concepts. But the attached is the start of what I have found is somewhat common in several 8251 driver code modules I have looked at. Not sure where I read the part about sending 00 three times to start with though. I did read it many years ago. It may be redundantly wasteful....

/code/
;
; STD Bus Serial Board Addresses
SACR EQU 025H ;2SIO port A control register
SADR EQU 024H ;2SIO port A data register
SBCR EQU 027H ;2SIO port B control register
SBDR EQU 026H ;2SIO port B data register
;
;------------------------------------------------------
;8251A UART Initialization routine
;------------------------------------------------------
;Port 24H is Read/Write Data for 8251A UART 0
;Port 25H is Control & Status Port for 8251A UART 0
;Port 26H is Read/Write Data for 8251A UART 1
;Port 27H is Control & Status Port for 8251A UART 1
;------------------------------------------------------
;8251A UART Initialization
;When power is first applied, the 8251A may come up
;in the Mode, Sync character, or Command format. To
;guarantee that the device is in the Command Instruction
;format before the Reset command is issued,
;it is safest to execute the worst-case initialization
;sequence (sync mode with two sync characters).
;Loading three 00Hs consecutively into the de-
;vice with C/*D=1 configures sync operation and
;writes two dummy 00H sync characters.
LD A,00H ;First of UART init commands
OUT (SACR),A ;Output to serial0 control port
OUT (SBCR),A ;Output to serial1 control port
OUT (SACR),A ;Output to serial0 control port
OUT (SBCR),A ;Output to serial1 control port
OUT (SACR),A ;Output to serial0 control port
OUT (SBCR),A ;Output to serial1 control port
;
;8251A UART Reset Command
;Issuing a 40H command returns the 8251A to the 'idle' state
;and to the Mode Instruction format.
LD A,40H ;UART reset command
OUT (SACR),A ;Output to serial0 control port
OUT (SBCR),A ;Output to serial1 control port
;
;Mode instruction byte breakdown
;Baud rate selector - data bits 0 & 1
;bit0=0 & bit1=0 - Sync mode
;bit0=1 & bit1=0 - 1X mode
;bit0=0 & bit1=1 - 16X mode (THIS IS SELECTED)
;bit0=1 & bit1=1 - 64X mode
;Character length selector
;bit2=0 & bit3=0 - 5 bits
;bit2=1 & bit3=0 - 6 bits
;bit2=0 & bit3=1 - 7 bits
;bit2=1 7 bit3=1 - 8 bits (THIS IS SELECTED)
;Parity enable
;bit4=0 - disable (THIS IS SELECTED)
;bit4=1 - enabled
;Even parity generator/check
;bit5=0 - odd (THIS IS SELECTED)
;bit5=1 - even
;Number of stop bits
;bit6=0 & bit7=0 - invalid
;bit6=1 & bit7=0 - 1 bit (THIS IS SELECTED)
;bit6=0 & bit7=1 - 1-1/2 bits
;bit6=1 & bit7=1 - 2 bits
; B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0
; 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0
LD A,4EH ;UART mode instruction
OUT (SACR),A ;Output to serial0 control port
OUT (SBCR),A ;Output to serial1 control port
;
;Command instruction breakdown
;Transmit enable
;bit0=0 - disabled
;bit0=1 - enabled (THIS IS SELECTED)
;Date Terminal Ready
;bit1=0 - DTR set high
;bit1=1 - DTR set low (THIS IS SELECTED)
;Receive enable
;bit2=0 - disabled
;bit2=1 - enabled (THIS IS SELECTED)
;Send break character
;bit3=0 - normal operation (THIS IS SELECTED)
;bit3=1 - set TxD low
;Error reset
;bit4=0 - do not reset error flags
;bit4=1 - reset error flags (THIS IS SELECTED)
;Request to send
;bit5=0 - RTS set high
;bit5=1 - RTS set low (THIS IS SELECTED)
;Internal reset
;bit6=0 - normal operation (THIS IS SELECTED)
;bit6=1 - sets 8251 to Mode instruction Format
;Enter hunt mode (no effect in async mode)
;bit7=0 - disabled (THIS IS SELECTED)
;bit7=1 - enabled
; B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0
; 0 | 0 | 1 | 1 | 0 | 1 | 1 | 1
LD A,37H ;UART command instruction
OUT (SACR),A ;Output to serial0 control port
OUT (SBCR),A ;Output to serial1 control port
/code/
 
The 8251 is a little "funky" in that it resets (powers up) in a special mode where the byte you write to the control port has a different meaning than the rest of the time. You see in that code where it sends a "reset command" to the 8251 to try and get to a known state. But, in order for the reset command to work, you have to know what state the 8251 is in. So, it sends three 00 bytes to each 8251 control port, which ensures you are in a known state, albeit (possibly) an invalid configuration.
 
You have me curious now... What serial ports are you using? Are they something you made yourself or an off-the-shelf item? I never learned to use the Zilog SIO, but the Intel 8251's that the PC used were easy to use and the later ones came with great features, like a 64 byte fifo ( (750 model ) which made them particularly useful in a polling environment, since you get a decent amount of time before they fill up, even at higher speeds.
The standard PC UART in the XT era was the National Semiconductor 8250, not the Intel 8251. If I remember correctly, the AT used a 16450, which allowed higher speeds. Later the 16550 and subsequent chips added various depth FIFOs.

The Intel 8251 is capable of synchronous operation (it's a USART) and works quite differently. The 8251 tops out at 19.2kbps.

Anyway, that's a bit off topic....

Coming from the TRSDOS world, where a command binary (CMD extension in TRSDOS) is in a load module format that allows loading anywhere in memory with a transfer address that doesn't have to be at the start of the program, I find this discussion rather interesting. In a way it seems a lot simpler to just have everything load at a fixed address; but terminate and stay resident stuff or even user loadable drivers seem more difficult.

I wrote a couple of drivers for TRSDOS 6 back in the day, and dynamic relocation code was the normal way to install into the TRSDOS driver chain, either at the end of LOWCORE or by moving the HIMEM pointer. But TRSDOS is a rather different OS from CP/M.

On TRSDOS you use the DUMP command:
Code:
DUMP
Copies an area of memory to a disk file

Syntax:

   DUMP filespec (parameter)

Parameters:

   Start=    Starts dump at address specified (must be greater than X'2FFF')
   End=      Last address of dump
   Tra=      Execution transfer address
   Ascii     Specifies ASCII dump
   Etx=      Writes value to end of ASCII file

But that's TRSDOS and doesn't help the OP.

The question then becomes why are you wanting to run at 0D000H?
 
Ah, the infamous 8251. I've been programming those recently to do support for the Heath H8/H89 cassette tape board. I thought that PCs used the 8250, though... which has a very different software interface. Maybe the earliest PCs used the 8251? I thought they were even getting hard to come by. The 8250 designs live on in modern chips, even having 2 and 4 complete 8250's on a die.

Just a note about polling vs. interrupts. Contrary to popular belief, interrupts are not the fastest way to receive data over a serial port. If it is time constrained (i.e. high bauds), you need to use a dedicated poll loop to get the best throughput. I see you have hard-wired the baud to 9600, which may be fairly slow depending on your CPU clock. But, the nagging problem with downloads is unexpected interrupts from other sources causing the receive to fall behind. This includes the "fire hose" protocol if trying to periodically write data to disk. If your system has spontaneous interrupts (like the Heath systems "2mS Clock") you may have issues keeping up.
Well, I discovered a BIG error in my hardware design. The 8251A goes into an idle state whenever the Reset line is high. Everything else in my system gets reset when the system Reset line goes low. Everything operates when the Reset line is high. The 8251A does just the opposite. Time to add a 74LS04 I guess! There is a good reason to read 'all' of the datasheet........ LOL
 
Well, I discovered a BIG error in my hardware design. The 8251A goes into an idle state whenever the Reset line is high. Everything else in my system gets reset when the system Reset line goes low. Everything operates when the Reset line is high. The 8251A does just the opposite. Time to add a 74LS04 I guess! There is a good reason to read 'all' of the datasheet........ LOL

Just call the first one a "Prototype" - I have made a lot of circuits in my life, and it's really hard to get them right on the first time. It's not impossible, but I'd never plan on it happening - A few times I fluked it though. :) Getting resets mixed up is a pretty common error too - I've done that more than once.
 
oh, I know. I suspect there will be several iterations before I get to the 'As Built - Production' level. I'll call this one Preliminary Breadboard Prototype.. This is why I love doing things in wire-wrap too.
 
The Amstrad PCW uses the NMI for floppy interrupts, but it ensures that while the NMI is enabled, the memory banking has the BIOS (rather than the TPA) paged in at address 0000h.

ZCN is a CP/M workalike for the Amstrad notepad computers which has to support their use of the NMI - I think it puts a RST instruction at 0066h while backing up whatever byte was there before.
 
Back
Top