The following document is the translation from a German magazine I wrote in those days.
Soon after working with CP/M on the JOYCE I bought me the interface expansion CPS 8256 and an 300 Baud acoustic coupler.
Because I enjoyed programming myself I dealed with the serial interface extensively.
The following article referring to that topic was published in the double issue 4+5/1987 of the German magazine "JOYCE-NEWS".
Unfortunately the publishing of the JOYCE-NEWS was stopped very soon.
Later I found a compilation of technical data of the CPS8256:
In 2002 John Elliot who is very committed published a document called PCW Hardware.
Still later (in 2004!) I found a link referring to the CPS8256 a circuit diagram inclusive.
The original website does not exist anymore but a description may be found here and the diagram here.
For more information find a document describing also Intel's Z80 UART
and a description of the Intel timer 8253
(Here as 82C24, which is 8253 compatible).
This compilation may be interested for those users whose JOYCE is upgraded with the interface expansion und in connecting to the whole wide world through a serial connection.
Find hints and references for programming focused on assembler which allows
to optimize programs in the telecommunications environment, e.g. accessing mailboxes.
In a CP/M environment programs should use the BDOS system interface basically.
Sometimes it may be useful using the BIOS interface to bypass character control, e.g. using console I/O.
Running CP/M PLUS calling the BIOS for disk I/O must be avoided because it may crash the machine.
The banked version of CP/M PLUS has BIOS routines in memory banks which are not switched in normally.
An exeption from this rule may be programming in a telecommunications environment.
Here it is very important to get close information about the state of the telecommunications device.
Also important is the selective setting or resetting of control bits.
Neither the BDOS nor the BIOS does support such a function.
The following report gives a short overview of the construction of the JOYCE machine as well as a description of the extended line interface.
After this the programming of the serial line will be discussed.
Everybody who did unscrew the JOYCE for doubling the 256kbyte RAM or just for curiosity will be surprised of the few chips built into the machine (see block diagram in picture 1).
Compared to the JOYCE the interface expansion seems to be equipped with more chips.
Werner Cirsovius well known by his firmware articles in the NEWS 2+3/87 describes the serial interface and its programming here.
As distinguished from other listings – mainly written in Pascal and not usable for everyone –
neither the source assembler code nor the basic loader will be released on disk but the result of this article:
the public domain tool KERMIT especially customized for the JOYCE by Werner!
Although the floppy controller may be programmed using the so called 'BIOS extended jump block' I will not discuss this.
CP/M PLUS is able to administrate drives as well as the remaining I/O devices much better using BDOS calls.
After unscrewing the interface expansion you will see two big chips immediately:
Furthermore you will find the circuit 74LS373, an eight bit latch.
The serial interface (SIO) is built upon:
- Z80 DART A chip containing two UARTs (serial unterfaces).
- 8253 A timer chip with three independent timer chanals.
The parallel interface (CEN) is built upon:
- 1/2 Z80 DART UART
with hardware handshake lines
- 2/3 8253
two timer for transmit and receive Baud rates
Not the usage of the second UART for the parallel interface!
In the next step we will discuss the programming of the serial interface (SIO) only
because the parallel interface (CEN) will be better served by CP/M.
The following hex addressess are assigned to the I/O ports:
- 1 74LS373 Eight bit data latch
- 1/2 Z80 DART II for strobe and BUSY
- 1/3 8253 for the timing
We start programming the timer because it it easier than programming the UART.
Before sending data to a chanal a control word must be sent to port E7.
This word has the following format:
- E0 UART data port. Data may be sent or received using this address.
- E1 UART control port. Use it to set parameters for the UART or inquire particular states of it.
Indeed the programming is tricky.
- E4 timer chanal 0. Set Baud rate for the transmiter.
- E5 timer chanal 1. Set Baud rate for the receiver.
- E7 timer control, use it to set timer parameters.
Recognize that only bit SC0 has to be changed.
This results into the two possible control words:
- SC1, SC0 determine the timer to be programmed.
Using chanal 0 select SC1,SC0=0,0 and using chanal 1 select SC1,SC0=0,1
- RL1, RL0 determine the sequence the data word will be sent.
Set both bits to 1,1 which selects the usual mode of the Z80 processor (send least significant first)
- M2, M1, M0 determine the count mode.
Set to 0,1,1 for square wave mode.
- BCD select the mode if counter, set to 0.
This complies with binary counter.
Timer 0:0011 0110 or 36hex
After sending this word to the timer 8253 at port E7 the 16 bit counter value must be sent to the chanal.
On chanal 0 this corresponds to port E4, on chanal 1 it is port E5.
Timer 1:0111 0110 or 76hex
Calculate this value for a known Baud rate as follows:
The required frequency supplying the UART must be 16 times the Baud rate
(this factor must sent to the UART or is the default respectively):
fUART = 16*BAUD
The frequency supplying the timer is the half of the CPU frequency:
fTIMER = fCPU/2
Therefore the factor F is calculated as:
fTIMER = F*fUART
Enough maths, the final equation is:
Selecting a rate of 300 Baud using a CPU fequency of 4Mhz results in:
F = 417 or hex 01A1
Find here some possible examples programming the transmitter:
... running MAC or RMAC:
... running BASIC
timer equ 0e7h
baud0 equ 0e4h
word equ 0011$0110b
value equ 417
doit: mvi a,wrd
mvi a,low value
mvi a,high value
... running TURBO PASCAL
1020 OUT &HE7,&H36
1030 OUT &HE4,value MOD 256
1040 OUT &HE4,value\256
To program the Baud rate is interesting only if it will be changed during run time of course.
But most often the rate will be set once so the Amstrad utility SETSIO may be used doing this.
For the example above to set the transmitter rate to 300 Baud type the command
Word = $36;
Baud0 = $E4;
Value = 417;
procedure bd_set(Word, Baud0,
Value : integer);
Timer = $E7;
port[Timer] := Word;
port[Baud0] := lo(Value);
port[Baud0] := hi(Value);
bd_set(Word, Baud0, Value);
SETSIO TX 300
Although the normal BIOS supports setting the Baud rate
(BIOS call 21, DEVINI = DEVice INItialization)
there are still more parameters available to be changed calling the "BIOS extended JUMP block" (XBIOS).
What does XBIOS mean?
Running CP/M Plus the BIOS function 30 does exist, the so called USERF (= USER Function).
Requesting it on the JOYCE means, that the call to this function must follow a 16 bit address selecting the required XBIOS function.
The XBIOS functions may be divided into:
Interesting for a telecommunications environment is the second group, SIO driver.
Three functions are implemented as follows:
- Disk driver, e.g. execute UPD765 controller commands directly
- SIO driver
- Terminal emulator, informations about screen settings
- Keyboard, key definitions as known by SETKEYS
- Miscellaneous, e.g. accessing the JOYCE video RAM
The above example setting the transmitter Baud rate may be programmed using the XBIOS as follows:
- Function 1: Initialization of the UART
|Subfunction:||Set UART values|
| ||00H: No handshake|
| ||FFH: Handshake|
| ||D||Number of stop bits|
| ||0 : 1 stop bit|
| ||1 : 1,5 stop bits|
| ||2 : 2 stop bits|
| ||0 : None|
| ||1 : Odd|
| ||2 : Even|
| ||H||Number of receiver data bits|
| ||L||Number of transmitter data bits (5, 6, 7 or 8)|
|Subfunction:||Set or reset UART bits DTR and RTS|
|Register:||Accu||7DH RTS on|
| ||7EH RTS off|
| ||7FH DTR on|
| ||80H DTR ofd|
- Function 2: Set Baud rates
The rates are coded as follows
|Register:||H coded receiver Baud rate|
| ||L coded transmitter Baud rate|
| ||1:||50 Bd||9:||1800 Bd|
| ||2:||75 Bd||10:||2400 Bd|
| ||3:||110 Bd||11:||3600 Bd|
| ||4:||134,5 Bd||12:||4800 Bd|
| ||5:||150 Bd||13:||7200 Bd|
| ||6:||300 Bd||14:||9600 Bd|
| ||7:||600 Bd||15:||19200 Bd|
- Function 3: Read UART setting
After calling this functions the registers hold the following values:|
| ||Accu||00H: No handshake|
| ||FFH: Handshake|
| ||B||Coded receiver Baud rate|
| ||C||Coded transmitter Baud rate|
| ||D||Stop bits (see above)|
| ||E||Parity (see above)|
| ||H||Number of receiver data bits (see above)|
| ||L||Number of transmitter data bits (see above)|
CALL USERF ;Read UART setting
MOV H,B ;Let receiver as is
MVI L,6 ;Transmitter 300 Baud
CALL USERF ;Set Baud rate
One final question has to be solved − how to program the subroutine "USERF".
Concerning this the BIOS vector of function 30 must be initalized at the beginning of a program
INIT: LHLD 1 ;BIOS base address
LXI B,3*(30-1) ;Load offset
DAD B ;Calculate vector
SHLD USERF+1 ;Save as jump address
USERF: JMP $-$ ;Jump to BIOS function 30
While the programming of the 8253 is quite simple, programming of the Z80 UART is not.
Because may functions may be set by the XBIOS function 00B6H not all of the capabilities will be discussed here.
For more information please study the datasheet of the Z80 DART (by the way DART means that two UARTs are implemented on one chip, Dual UART).
But find a review here how to program data transfer as well as handling control states.
The latter will not be supported by the XBIOS.
As described above the DART occupies two Z80 I/O ports, E0H for data transfer and E1H for control.
Port E1H is equipped with some sub functions.
There are three read registers (RR0 - RR2) as well as eight write registers (WR0 - WR7).
For example WR5 handles the DTR and RTS bits.
But also the number of data bits will be written into this register.
Because this may run into conflicts handling of these functions should be performed by the XBIOS.
The remaining job is to test if data transfer has taken place or to look for external signals.
Furthermore error detection may be performed.
Function 1 : Find out if data transfer is possible.
A routine for sending a character in the Accu may look like this:
- RxCA: Receiver Character Available - indicates whether a character is available (RxCA = 1) or not (RxCA = 0)
- TxBE: Transmitter Buffer Empty - indicates whether a character may be sent (TxBE = 1) or not (TxBE = 0)
OUTPUT: PUSH PSW ; Save character
WAIT: IN 0E1H ; Wait for send ok
OUT 0E0H ; Output
Function 2 : Find out if an error occured
Because these bits will be found in register 1, RR1 must be addressed before.
A routine requesting the error state may look like this
(if no error occured the zero flag of the CPU will be set):
- PE: Parity error - the received parity does not match the selected one
- OE: Overrun error - indicates that more than three characters have been received without a read. Previous characters are overwritten
- FE: Framing error - indicates erroneous data format
ERROR: MVI A,1
OUT 0E1H ; Address RR1
IN 0E1H ; Read error state
OUT 0E1H ; Address RR0 as default
ANI 0111$0000B ; Generate state of the zero flag
Function 3 : Find out external line states
Although these bits will be found in regsister 0 (RR0, see function 1) they must be handled in a different way.
Namely a reset must be given twice to WR0 before reading the bits.
I did not found this a the data sheet but without doing so I was not able to detect a state change on any line.
- CTS: Clear to Send - the connected device is ready to receive if CTS = 1
- DSR: Data Set Ready - the connected device is ready for use if DSR = 1
- DCD: Data Carrier Detected - the connected modem or acoustic coupler sends a carrier if DCD = 1.
A routine for reading and masking the external signals may look like this:
STATUS: MVI A,0001$0000B
OUT 0E1H ; Reset once
OUT 0E1H ; .. twice
IN 0E1H ; Read external signals
ANI 0011$1000B ; Mask bits
Addendum to the printed article:
Some applictions use to send a BREAK signal.
This is a signal activating the transmitter line for about 300 milliseconds (msecs)
causing a break on the receiver side.
Write register WR5 performs this on the Z80 UART.
A routine for sending a BREAK may look as follows (routine as used by KERMIT):
In either case the BREAK signal should be at least as long as the longest duration sending a byte.
A careful consideration results into the length of the BREAK signal as follows:
Using the slowest possible rate of 50 Baud leads to 1/50 seconds, i.e. 20 msecs, to transfer one bit.
With the longest bit length of 12 bits (= 1 x start + 8 x data + 1 x parity + 2 x stop) we get a transfer time of 12x20 msecs = 240 msecs.
So 300 msecs is a good choice.
SENDBR: MVI D,1001$1010B ; BREAK mask
MVI E,30 ; Length of the BREAK signal is
; 300 milliseconds
SNDBR1: MVI A,1 ; Address RR1
IN 0E1H ; Read
ANI 0000$0001B ; Test "ALL DONE" bit
JZ SNDBR1 ; Wait until set
; Now the BREAK signal will be transmitted
SETBIT: MVI A,5 ; Address WR5
LDA TXBITS ; Load bit length for transmitter
; They are defined as folows:
; x00x$xxxx 5 bits
; x01x$xxxx 7 bits
; x10x$xxxx 6 bits
; x11x$xxxx 8 bits
ORA D ; Output BREAK,
OUT 0E1H ; TXENABLE, RTS
; Now delay for 300 milliseconds
MOV A,E ; Delay value
; Time is expired.
; Set tansmitter to normal state now.
MVI A,5 ; Address WR5
LDA TXBITS ; Reload bit length for transmitter
ORI 1000$1010B ; No BREAK
OUT 0E1H ; But TXENABLE and RTS
RET ; Done
; Example for a delay routine
; Here for 10 milliseconds
DELAY: LD C,40 ; Relating 4 MHz
DELAY2: LD B,70
DELAY3: DEC B
The present report should introduce basics into programming the serial line used for telecommunications.
Due to the poor informations coming from the JOYCE selling company SCHNEIDER not all facilities are stated here.
Consider that programming on a direct hardware level must be performed very careful independent of the programming language used.
Remember that bank switching on the JOYCE is done by setting appropriate I/O ports.
An incorrect address used for setting a port may crash the system.
A crash may be bad but a complete erasure of a disk due to erroneous programming is worse.
Postscript of the editors:
We are interested in reports on one's experiences relating telecommunications, mailboxes, serial interfaces......