|Z88 Developers' Notes|
25. Manipulating the Blink Registers
It is generally programming practice to use the operating
system calls provided rather than manipulating the hardware
directly; it avoids compatibility problems with future releases,
and treading on the toes of the operating system. We are
therefore NOT going to encourage the reader to poke to the screen
or disable the operating system! However we shall attempt to give
as full a description of the hardware that exists.
Overview of the BLINK registers
The following table lists all the registers in the BLINK chip,
which are accessed through the Z80 I/O ports. Not all of the
registers are useful to programmers, but they are all included
for completeness. Some are described in more detail later in this
section. Note that because registers can only be written to or
read from, but not both, it would be possible to lose track of
register contents. Therefore the operating system use addresses
$0400 to $04FF to store 'soft copies' of the values in the BLINK
registers, with the low byte of the address being taken from the
address of the I/O port. You can read these soft copies, to check
out the contents of the registers, but most importantly you
should always write to the soft copy for a register before
writing to a register itself, for reasons explained below.
I/O port WRITE READ $70 PB0, pixel base reg.0 - $71 PB1, pixel base reg.1 - $72 PB2, pixel base reg.2 - $73 PB3, pixel base reg.3 - $74 SBR, screen base reg. - $B0 COM, command register - $B1 INT, mask & control STA, interrupt status $B2 - KBD, keyboard $B3 EPR, EPROM programming - $B4 TACK, RTC ack. - $B5 TMK, RTC int. mask TSTA, RTC int. status $B6 ACK, main int. mask - $D0 SR0, segment reg. 0 TIM0, RTC 5ms counter $D1 SR1, segment reg. 1 TIM1, RTC seconds counter (6 bits) $D2 SR2, segment reg. 2 TIM2, RTC minutes counter $D3 SR3, segment reg. 3 TIM3, RTC minutes/256 counter $D4 - TIM4, RTC minutes/64K counter (5 bits) $E0 - RXD, UART receive data register $E1 - RXE, extended receiver data $E2 RXC, receiver control - $E3 TXD, transmit data - $E4 TXC, transmit control - $E5 UMK, UART int. mask UIT, UART int. status $E6 UAK, UART int. mask -
NOTE: RTC stands for "Real Time Clock", int. stands
for "Interrupt", and ack. stands for
The COM register ( COM, $B0)
This register is detailed first because it controls various diverse aspects of BLINK operations:
Bit Name Function 7 SRUN Speaker source (0=SBIT, 1=TxD or 3200Khz) 6 SBIT SRUN=0: 0=low, 1=high; SRUN=1: 0=3200 Khz, 1=TxD 5 OVERP Set to overprogram EPROMs 4 RESTIM Set to reset the RTC, clear to continue 3 PROGRAM Set to enable EPROM programming 2 RAMS Binding of lower 8K of segment 0: 0=bank 0, 1=bank 20 1 VPPON Set to turn programming voltage ON 0 LCDON Set to turn LCD ON, clear to turn LCD OFF
The two speaker control bits operate in the following fashion:
SRUN SBIT Effect 0 1 Speaker line low 0 1 Speaker line high 1 0 Speaker line oscillates at 3200 Khz 1 1 Speaker line attached to Tx data (Tx data still output to comms. port)
RAMS is cleared on reset thus paging in ROM at logical
addresses $0000 to $1FFF. This is necessary since the Z80 program
counter is loaded with zero on reset. In normal operation RAMS is
set and the lower 8K is the system RAM, which is also used for
application static workspace and stack.
Bank Switching ( SR0-3, $D0-3 )
System calls inevitably require a significant time overhead while they decode their input parameters and perform general housekeeping. This could have an effect on some programs which need to switch banks around a great deal, so we present here the method for binding banks via hardware. It should not be necessary to use this code because of the existence of the fast code interface described in "Miscellaneous useful routines". This section is included to provide some explanations as how things work. If you want your code to be compatible with future versions of the machine you should only use the fast code interface.
To rebind one of the segments 0 to 3, the program writes the bank number into the relevant "segment register"; there are four segment registers, one for each segment. These are held in the BLINK chip and adressed via the Z80 I/O ports $D0 to $D3. Thus:
ld a,20 ; do not use this code... out ($D3),a ; under any circumstances
will bind bank 20 (internal RAM) to segment 3.
Because the segment registers are write-only, the operating system needs 'soft copies' of the current bindings so it can restore the old bindings correctly after it has rebound banks at the start of OS calls or interrupt service routines. These soft copies are stored at machine locations $04D0 to $04D3. It is VITAL that the desired bindings are stored here BEFORE actually binding the bank; if the bank were bound first, then in the event of an interrupt occurring immediatly after the output instruction, the interrupt service routine would rebind the bank to the contents of the soft copy (assuming it does rebind the relevant segment), and the desired change would be lost. The equivalent of an OS_Mpb would be:
ld bc, $04D0 + segment ; address of soft copy ld a, bank ; bank number ld (bc),a ; update the soft copy out (c),a ; bind in the bank
Similarly, the equivalent of the OS_Mgb would be simply to read the soft copy:
ld a,($04D0 + segment)
EPROMs ( EPR, $B3 )
No convenient system call is provided for blowing individual bytes to EPROM. Hence we detail a method for doing so by directly manipulating the gate array registers.
To write a byte to EPROM, the relevant physical address must be in slot 3, ie. banks $C0 to $FF. The user first sets up the correct programming signals for the type of EPROM concerned. This is done by writing to the BLINK register EPR, addressed by I/O port $B3.
EPR, EPROM programming register:
BIT NAME FUNCTION 7 PD1 Two bits representing the length of delay period 6 PD0 5 PGMD State of program pulse during delay period 4 EOED State of EOE during delay period 3 SE3D State of slot 3 select during delay period 2 PGMP State of program pulse during porch period 1 EOEP State of EOE during porch period 0 SE3P State of slot 3 select during porch period
NOTE: For 32K EPROMs write $48 (@01001000) to EPR and for 128K, 256K EPROMs use $69 (@01101001).
The delay periods are as follows, but note that during overprogramming (when OVERP is set in COM) the period is tripled. The porch period is not exact but is never less than 2.4us.
PD1 PD0 Period 0 0 4.88us 0 1 312.5us 1 0 2.5ms 1 1 10ms
To enter EPROM-programming mode, the user must set VPPON and PROGRAM in the COM register, addressed by I/O port $B0, and also switch off the LCD by clearing the LCDON bit. When this is done, programming can be achieved by writing to the relevant address (which obviously needs to be a physical address in slot 3 ie. banks $C0 to $FF) as though it were RAM. However, writing to slot 3 addresses in program mode causes BLINK to take over. BLINK will hold the data and address busses with the appropriate data and then do a porch cycle, followed by a delay cycle and then another porch cycle before returning control to the processor. Once a byte has been programmed, it needs to be verified. This is done by exiting programming mode - clear VPPON and PROGRAM - and reading the byte back to see if it has been successfully blown. No more than 75 attempts should be made to blow any byte, and if it has not been blown by that stage, something is clearly wrong. Note that a byte will usually be successfully blown in one attempt. Once a byte has been successfully programmed, OVERP (in COM) should be set and the byte overprogrammed. Each byte should be overprogrammed the same number of times as it first took to program.
A code fragment to blow a byte in register C to logical address (HL) - assumed to be bound to an EPROM address - is reproduced below. Note that when the Filer writes to the EPROM it does so by blowing blocks of bytes, rather than writing one byte at a time, and so operates a little faster than blowing each byte individually.
.start ld b, 75 ; Max. number of attempts ld a, $48 ; for 32K EPROMs out ($B3),a ; Set EPROM programming signals .proloop ld a, $0E out ($B0),a ; Set VPP and PROGRAM bits ld (hl),c ; write byte to EPROM (address) ld a, $04 out ($B0),a ; Reset VPP and PROGRAM bits ld a,(hl) cp c ; verify byte jr z, byteok djnz proloop
; handle failure to write byte here...
ret .byte ld a, 76 ; one more than maximum number of attempts sub b ; same number of times it took to program ld a,b .ovploop ld a, $2E ; Reset VPP, PROGRAM out ($B0),a ; and OVERPROGRAM ld (hl),c ; write byte ld a, $04 out ($B0),a ; reset VPP, PROGRAM and OVERPROGRAM djnz ovploop ld a, $05 ; set COM register to out ($B0),a ; turn screen back on ret
The Z88 Assembler Workbench application Zprom uses the above algorithm in principle, but blows to EPROM in blocks of max. 16K in one go (depending of the user defined range) by using the standard Z80 instruction LDIR.
UART Receive registers
RXD ($E0), receive data register
7 6 5 4 3 2 1 0
D7 D6 D5 D4 D3 D2 D1 D0
RXE ($E1), extended receive data register
BIT NAME Function 7 - Always clear 6 - Always clear 5 FE Frame error, set if error 4 RXD Value of RXD pin on BLINK 3 TCLK Internal transmit clock 2 RCLK Internal receince clock 1 PAR Parity or first stop bit 0 START Start bit (should be zero)
RXC ($E2), receive control register
BIT NAME Function 7 SHTW Set to select short word mode 6 LOOP Set to connect transmit to receive (used for testing) 5 UART Set to hold UART in RESET 4 ARTS Auto RTS mode 3 IRTS Invert RTS 2 BAUD 2 These three bits define receiver baud rate 1 BAUD 1 0 BAUD 0
SHTW is used to align RXC register with the incoming data such that the byte you want ends up in RXC and you do not get stuck with parity or stop bits. We can see the effect of SHTW by showing how an incoming data stream is mapped onto RXC and RXE. Suppose the incoming data is
--> S2 S1 D7 D6 D5 D4 D3 D2 D1 D0 ST --> Z88
BITS If SHTW=0 If SHTW=1 S2 FE (inverted) Not clocked in S1 PAR FE (inverted) D7 D7 PAR D7-D0 D7-D0 D7-D0 ST START START
When ARTS is set then RTS will be asserted every time a new character is received and cleared when the receive register has been read. Manual control of RTS can be achieved by using IRTS to change the current state of the line.
The baud rates set by BAUD 2 to BAUD 0 are as follows:
Value (Baud2-0) Baud rate 0 000 75 1 001 300 2 010 600 3 011 1200 4 100 2400 5 101 9600 6 110 19200 7 111 38400
UART Transmit registers
The transmit data registers is 11 bits wide with the upper 3 bits being written by the address lines A8-A10 during the OUT instruction. The register looks like this:
TXD ($E3), Transmit data register
10 9 8 7-0 -------------------------------------------- STOP2 STOP1 START D7 - D0 --------------------------------------------
If SHTW (in RXC) is set then STOP2 will not be sent out and only 10 bits will be sent in all. To load the register you must use a code sequence like:
ld a, data ; 8 bits to send ld b, @00000110 ; 2 stops, 1 start ld c, TXD ; I/O port $B3 out (a),a ; transmit data
TXC ($E4), Transmit control register
BIT NAME Function 7 UTEST Set fast baud rate for receive and transmit 6 IDCD If set, DCD interrupts when low (else when high) 5 ICTS If set, CTS interrupts when low (else when high) 4 ATX Auto transmit mode 3 ITX Invert Tx data output pin 2 BAUD2 These three bits define transmit baud reate 1 BAUD1 (See above table for baud rates) 0 BAUD0
When ATX is set the data in TXD will not be sent until CTS is
asserted. Manual control of the TxD pin can be achieved by using
ITX to change the current state of the line.
UART interrupts and status
UIT ($E5), UART interrupt status register
BIT NAME Function 7 RSRD Receive shift register full (cleared when read) 6 DCDI DCD interrupt 5 CTSI CTS interrupt 4 TDRE Transmit data register empty 3 - - 2 RDRF Receive data register full 1 DCD State of DCD line 0 CTS State of CTS line
The registers UMK and UAK control the enabling and acknowledging of the UART interrupts. CTS and DCD can both be enabled to cause interrupts and the interrupts can be set to occur on either state of the line (IDCD and ICTS in the TXC register). To clear a DCD interrupt the state of IDCD needs to be changed (since the interrupt is level and not edge triggered) and then the DCD bit should be set in the interrupt acknowledge register UAK. CTS works in exactly the same way as DCD.
UMK ($E5), UART interrupt mask register
BIT NAME Function 7 - - 6 DCD If set, DCD interrupts are enabled 5 CTS If set, CTS interrupts are enabled 4 TDRE If set, transmit data register empty interrupt enabled 3 - - 2 RDRF If set, receive data register empty interrupt enabled 1 - -
UAK ($E6), UART interrupt acknowledge register
BIT NAME Function 7 - - 6 DCD Set to acknowledge DCD interrupt 5 CTS Set to acknowledge CTS interrupt 4 - 0 - -
To clear TDRE and RDRE interrupts you write to the transmit
data register or read from the receive data register
It is sometimes desirable to explicitly manipulate the RTS line of the serial interface for example when auto-dialing modems. This may be done by manipulating the IRTS bit in the RXC register. In programming terms this is bit 3 of I/O port $E2. It is important that the soft copy is updated first.
Bit 3 is XOR'ed with the normal state of the RTS line, as defined by RDRF in UIT (receive data register full) and ARTS (auto RTS) in RXC.
The logic is RTS=[[RDRD AND ARTS] XOR IRTS]. This bit therefore toggles the RTS line. A code fragment to achieve this might be:
ld bc, $04E2 ; address of soft copy ld a,(bc) ; fetch old value or 8 ; or AND 247 to reset ld (bc),a ; update soft copy out (c),a ; update hardware
The TxD (transmit data) line can be inverted by changing the
state of ITX in TXC (the transmit control register) using bit 3
of I/O port $E4 (soft copy address $04E4) in a similar way to the
RTS line. The value of the RxD line (receive data) can be found
by reading RXDB in RXE (extended receive data register, using bit
4 of I/O port $E1 (soft copy $04E1 - the soft copy will not
necessarily be up to date).
The Keyboard ( KBD, $B2 )
The keyboard is read by outputting a row on the address line A8 to A15 and reading the KBD register in BLINK. The keyboard matrix looks like this:
| D7 D6 D5 D4 D3 D2 D1 D0
A15 (#7) | RSH SQR ESC INDEX CAPS . / £
A14 (#6) | HELP LSH TAB DIA MENU , ; '
A13 (#5) | [ SPACE 1 Q A Z L 0
A12 (#4) | ] LFT 2 W S X M P
A11 (#3) | - RGT 3 E D C K 9
A10 (#2) | = DWN 4 R F V J O
A9 (#1) | \ UP 5 T G B U I
A8 (#0) | DEL ENTER 6 Y H N 7 8
DIA <DIAMOND> key SQR <SQUARE> key LSH Left <SHIFT> key RSH Right <SHIFT> key LFT <LEFT> arrow key RGT <RIGHT> arrow key DWN <DOWN> arrow key UP <UP> arror key
The keyboard can be read directly using a piece of code like below, although note that while reading the keyboard, BLINK will stop the processor for up to 40us:
ld c, $B2 ; I/O port $B2 ld b, row ; one row of A15-8 in a, (c) ; get column data in A
To check for the escape key being pressed.
ld c, $B2 ld b, @01111111 ;Detect keys in matrix top row. in a, (c) cp @11011111 ;Bit pattern returned if only the escape key is pressed.
If KWAIT (in INT) is set then performing a key read read will
send the machine into Snooze state. When a key press is made the
machine will wake up and if KEY (in INT) is set then a keyboard
interrupt will occur.
The INT ($B1) register controls which interrupts are enabled:
BIT NAME Function 7 KWAIT If set, reading the keyboard will Snooze 6 A19 If set, an active high on A19 will exit Coma 5 FLAP If set, flap interrupts are enabled 4 UART If set, UART interrupts are enabled 3 BTL If set, battery low interrupts are enabled 2 KEY If set, keyboard interrupts (Snooze or Coma) are enabl. 1 TIME If set, RTC interrupts are enabled 0 GINT If clear, no interrupts get out of blink
The ACK ($B6) register is used to acknowledge and thus clear an interrupt:
BIT NAME Function 7 - - 6 A19 Acknowledge A19 interrupt 5 FLAP Acknowledge FLAP interrupt 4 - - 3 BTL Acknowledge battery low interrupt 2 KEY Acknowledge keyboard interrupt 1 - - 0 - -
The STA ($B1) register provides information about which interrupt has actually occurred:
BIT NAME Function 7 FLAPOPEN If set, flap open else flap closed 6 A19 If set, high level on A19 occurred during coma 5 FLAP If set, positive edge has occurred on FLAPOPEN 4 UART If set, an enabled UART interrupt is active 3 BTL If set, battery low pin is active 2 KEY If set, a column has gone low in snooze (or coma) 1 - - 0 TIME If set, an enabled TIME interrupt is active
Coma and Snooze
The COMA state is entered via a HALT instruction. Any interrupt can cause a wake up, providing there is enough power to run the machine and the interrupt is enabled. If all interrupts are disabled withing BLINK (regardless of whether they are enabled in Z80 - the interrupt line to the Z80 comes from BLINK) before a HALT instruction, then the machine will never be able to wake up again. One special way of waking the machine is by ensuring KEY and KWAIT (in INT) are set before executing HALT. During HALT the upper 8 address bits hold the contents of the Z80 I (Interrupt) register. If this is set appropriately, a special key sequence can cause an interrupt to occur, waking the machine. This is how the pressing the two <SHIFT> keys wakes up the machine. The I register is loaded with @00111111 before HALT is executed. The two <SHIFT> keys occur in the two left hand columns of the keyboard matrix, so they can be sensed with the address lines in this state. Note that the minimum time between entering COMA and waking up again is 5ms, so the COMA state would not be suitable for waiting for regular interrupts. Finally note that the UART will not work in COMA because all the UART clocks are shut down.
During snooze the Z80 clock is stopped, but all the other
system clocks continue to run. Therefore it is possible to use
the UART from snooze. Any keyboard column going low will cause a
wakeup from snooze, even if the keyboard interrupts are disabled.
Note that the keyboard data returned after wakeup will not
necessarily be valid, so the keyboard should definitely be read
Real Time Clock (TIM0-4, $D0-4)
Register Period Counts to Width in bits TIM0 5ms 199 8 TIM1 1 second 59 6 TIM2 1 minute 255 8 TIM3 256 minutes 255 8 TIM4 64K minutes 31 5
The clock is reset to zero by settings RESTIM in the COM register. The clock will be held in reset, ie. it won't count until RESTIM is cleared again. In order to guarantee a valid result from any of these registers, software needs to read until two equal values are returned. This should always occur within three read cycles.
There are three interrupts that the real time clock can generate and these are TICK (100 times a second), SEC (once a second) and MIN (once a minute). Three registers are associated with these interrupts:
TSTA ($B5), Timer interrupt status
BIT NAME Function 7 - 3 - - 2 MIN Set if minute interrupt has occurred 1 SEC Set if second interrupt has occurred 0 TICK Set if tick interrupt has occurred
TMK ($B5), Timer interrupt mask
BIT NAME Function 7 - 3 - - 2 MIN Set to enable minute interrupt 1 SEC Set to enable second interrupt 0 TICK Set to enable tick interrupt
TACK ($B4), Timer interrupt acknowledge
BIT NAME Function 7 - 3 - - 2 MIN Set to acknowledge minute interrupt 1 SEC Set to acknowledge second interrupt 0 TICK Set to acknowledge tick interrupt
Unused I/O ports
The I/O ports $F0 to $FF are not used by the system and so are
available to hardware developers. The soft copy page $0400 is
entirely reserve for I/O port use and should be used. You must
not use this memory for any other purpose. Remember that when
updating a soft copy, it must always be done before updating the
port because of the possibility of an interrupt occurring and
receiving bogus information about the state of a port.
The addresses of the screen files are held in BLINK registers PB0 to PB3 and SBR. Their width determine the file granularity in a bank. For example, the LORES1 can be stored at 0, 4, 8 or 12K. Their softcopies are stored at ($046x) for the most significant bits and ($047x) for the 8 right bits. The role of these registers is as follows:
Register Name Role Lentgh Granularity Width ($046x) PB0 ($70) SC_LR0 LORES0 512 bytes 512 bytes 13 bits 5 bits PB1 ($71) SC_LR1 LORES1 3.5K bytes 4K bytes 10 bits 8 bits PB2 ($72) SC_HR0 HIRES0 6K bytes 8K bytes 9 bits 1 bit PB3 ($73) SC_HR1 HIRES1 2K bytes 2K bytes 11 bits 3 bits SBR ($74) SC_SBR SBF 2K bytes 2K bytes 11 bits 3 bits
When reading or writing to these registers IN or OUT (C),A instructions are used. B always contains the left bits of data (more than 8), A the data, C the port. So, A is ($047x) and B is ($046x). Please, refer to the Screen Files chapter for more about their structure.
|BBC BASIC & in-line assembler||Manipulating the Blink Registers||Z88 Motherboard Hardware|