THE Z80 SIO SERIAL COMMUNICATIONS CONTROLLER The programming complexities of large scale integration components are usually directly proportional to the facilities and versatility of the device.In the case of the Z80SIO, it will probably take some time even for even the more experienced programmer to work out how to make it perform even the most rudimentary tasks. To the beginner at microprocessor programming, it is possible that the bewildering array of registers will cause a total confusion unless a logical approach is taken from the start. Let us look at what is on offer then. The SIO contains 3x READ ONLY registers for the 'B' channel, 2x READ ONLY registers for the 'A' channel, 8x WRITE registers on the 'B' channel and 7x WRITE registers for the 'A'. Clearly for anyone attempting to make one of these things work correctly, a degree of understanding on which have to be programmed and which may be left alone, will make the job much easier. First of all, break down the task into more manageable chunks. Hopefully those new to the device will initially be concerned with a single channel. i.e. Receive 'A' and Transmit 'A'. We can therefore ignore any of the dedicated channel 'B' registers. Hopefully (!) Most programmers will be using the device in ASYNC mode, which means that we can ignore any references to SYNC, SDLC and HDLC. That's a few more out the way! Lastly, although it is up to the individual as to whether they use the extensive interrupt facilities on offer, or whether to use the much simpler 'Polling' method of operation.  With INTERRUPTS, the CPU ignores the SIO until it's attention is grabbed by the SIO raising an INTERRUPT. In the case of the much simpler POLLING method, the CPU periodically shuffles over to the SIO to see if it has anything that needs dealing with. Both can be made to work equally well, but from the programmer's point of view, it is often far easier to resort to polling. Let's take a typical WORKING example that may be applied to ANY circuit using the device. Obviously, it may be necessary to change some of the values if the particular application calls for it. First and foremost, ensure that you have a proper LIST of the addresses that will be needed to access the SIO. The HARDWARE will need to be organised correctly in order to do this.  Connect up the SIO as an I/O device with it's two control lines taken to Address lines 0 and 1. This allows the CPU to access the two separate channels and the control / data registers therein. In the programming example that follows, we will choose an I/O address of 30h. If we now attach the two register select lines A/B and C/D to address lines 0 and 1, we can select the registers by using the following table:  30   Selects the Data register on channel A   31   Selects the Data register on channel B   32   Selects the Control registers on channel A   33   Selects the Control registers on channel B  Both the READ and WRITE control registers (excepting register 0), need TWO consecutive SIO transfers in order to gain access to them. The FIRST access is a 'pointer' byte in write register 0 of that channel, before the chosen register can be either programmed or read. Look at the WORKING RECEIVER example which follows: 410C  3E  410D  18     Load the accumulator with value 18h 410E  D3    410F  32     Output the 18h to Write control register 0. RESET CHANNEL 4110  00     NOP 4111  3E     4112  04     Load the accumulator with value 04h 4113  D3 4114  32     Output 04h to write ctl reg 0: Request transfer to register 4 4115  3E 4116  44     Load the accumulator with 44h 4117  D3 4118  32     Output the 44 to Register 4: x16 clock, 1 stop bit, no parity 4119  3E      411A  03     Load the accumulator with 03h 411B  D3 411C  32     Output the 03h to write ctl reg 0:Request transfer to register 3 411D  3E      411E  C0     Load the accumulator with C0h 411F  D3      4120  32     Output the C0h to register 3: Set receive config to 8 bits 4121  3E      4122  05     Load A with 05h 4123  D3 4124  32     Output 05h to write control reg 0: Request transfer to reg 5 4125  3E     4126  60     Load A with 60h 4127  D3    4128  32     Output to Reg 5: Transmitter configuration set to 8 bits Channel A can now be considered set up for both receiving and transmitting. The above initializing routines only need setting up at the beginning of the program, unless some factors are to be altered once the program is running. In order to use the device for RECEIVING, (and by using the same transfer methods we used above) we need to send a C1h to Write register '3' (remember,at I/O address 32h?) - which will enable the receiver. After doing this, all that is necessary, if the POLLING method of usage is being applied is to periodically send a ZERO to read register 0 (code in the above example would be D3 32) then READ in the status register by using the command DB 32. As the'Read character available' bit in this register is actually Bit 0, we can rotate the result, so putting Bit 0 into the 'Carry' flag position by using the command 'RRA'. (there are of course several other alternative ways of testing it.) After which the 'Jump if no carry' command can be used if it is empty; thus: 481A   3E 481B   03    Ld A,03 481C   D3    481D   32    Output to 32 481E   3E 481F   C1    Ld A,C1 4820   D3 4821   32    Output to 32 4822   00 4823   00   4824   97    Zero A TEST FOR A RECEIVED CHARACTER STARTS HERE 4825   D3 4826   32    Output to 00 4827   DB 4828   32    Read in 32 4829   1F    RRA 482A   D2 482B   35 482C   48    Jump if no carry to 4835h (go to do other tasks elsewhere) 482D   DB  482E   30    Carry bit is set. Read in ASCII character from SIO to accumulator A few last points to note. The conditional jump at 482C is there to allow other processing tasks to be performed before the program returns to 4824 to 'poll' the register again. Obviously once the program has found a character and is running beyond 482E,it is up to the programmer to determine just what to do with it! A simple TRANSMITTER routine to set up and output a character follows here: 47DC    3E 47DD    05    LDA,05 47DE    D3 47DF    32    Output 05 to request register 5 47E0    3E 47E1    68    LDA,68 47E2    D3 47E3    32    Enable transmitter at register 5 47E4    97    Zero A 47E5    D3 47E6    32    Access read register 0 47E7    DB 47E8    32    Read in register 0 47E9    CB 47EA    57    Test bit 2 of byte read in for transmitter already busy 47EB    CA 47EC    E4 47ED    47    Jump if zero (i.e. not empty and in use) to 47E4 to retest 47EE    7A    LDA,D    Load A with the byte to transmit                  - in this program we've put it in the D register 47EF    D3 47F0    30    Write the SIO data register with the byte to be sent If a return were to be added to the bottom of this routine (at 47F1h) then the whole block of code may be considered a SUBROUTINE in it's own right - to use it, one simply has to place the character to be transmitted in the 'D'register then use the GOSUB command with the start address:      CD      DC      47 Strictly speaking (as I'm in a picky mood this evening!) It is not necessary to enable the transmitter each and every time one sends a character, so one could theoretically jump into the subroutine at address 47E4h. Happy programming! Izabella      |