Date : Mon, 24 May 2004 10:03:27 +0100
From : Angus Duggan <angus.duggan@...>
Subject: Re: Tube / Master Coprocessor question
Sprow writes:
>In article <40B120C0.6010807@...>,
> Richard Gellman <splodge@...> wrote:
>
>> Note that contrary to the expected behavior, the data is not
>> signalled by interrupts.
>
>I'd have to disagree there. A cursory disassembly of the IRQ handler shows
>that messaging from the IO processor to the 2nd processor is done
>exclusively with interrupts, and the high speed block data transfers with
>NMIs.
>
>Maybe you were talking about the host not the parasite?
>Sprow.
Sorry about the length of this. The tube has both interrupting and
non-interrupting registers. The interrupting registers are used to signal
commands, parameters are then passed by polling.
Full details below.
a.
The Tube hardware provides 4 independent bi-directional comminication paths.
Each consists of a one byte control register and a one byte data register
(which may have multibyte buffering). The characterstics of each register set
are decribed below, in the descriptions RnSTAT refers to status register n
and RnDATA refers to its corresponding data register.
Register Set 1
Host address Parasite address
R1DATA
write FEE1 FEF9
read (reading clears irq)
R1STAT
bit 7 data available/irq FEE0 FEF8
bit 6 not full
In the parasite to host direction this register set is used for the OSWRCH
call. The data register is a FIFO big enough to enable the longest VDU
command (10 bytes) to reside within it. In the host to parasite direction the
data register provides a 1 byte buffer. When the host writes to it an IRQ is
generated to the parasite. It is used to pass on event interrupts and the
escape operation.
Register Set 2
Host address Parasite address
R2DATA
write FEE3 FEFB
read
R2STAT
bit 7 data available FEE2 FEFA
bit 6 not full
This register set is used to implement long (in machine time used) OS calls,
or those which (RDCH) cannot interrupt the WRCH host background task. The
parasite passes a byte to describe the required action. The two machines then
co-operate in passing data across R2DATA until the job is done.
Register Set 3
Host address Parasite address
R3DATA
write
read FEE5 FEFD
R3STAT
bit 7 data available/nmi FEE4 FEFC
bit 6 not full
R3DATA is programmeable (from the host) to be either a 1 or 2 byte FIFO. This
register set is used for the background task of block data transfer between
the two machines (cf register set 4). For higher performance applications
this register may actually interface to a DMA controller.
Register Set 4
Host address Parasite address
R4DATA
write (writing sets irq) FEE7 FEFF
read (reading clears irq)
R4STAT
bit 7 data available/irq FEE6 FEFE
bit 6 not full/irq
This register set is used as a control channel for block transfers carried
out across R3. The host interrupts the parasite by writing a byte describing
the required action into R4DATA. The two machines then co-operate in passing
data across register 4 [? sic - ed] until the job is done.
The register set is also used to initiate the passing of an error string from
host to parasite. The host interrupts the parasite by writing an error code
into R4DATA, the two machines then cooperate in passing the error string
across R2DATA.
Notes:
(i) The BBC machine operates by polling the tube registers for work.
(ii) In all the transactions which may generate errors it is important to
realise that if the error is reported by the BBC machine under interrupt
(i.e. it was generated by a 6502 BRK sequence), the protocol which generated
the error is abandoned.
Non Interrupt protocols (parasite-side)
OSWRCH
Wait until R1DATA not full, write character into R1DATA.
OSRDCH
Wait until R2DATA not full, write RDCHNO (&00) to R2DATA
Wait for data in R2DATA, top bit of R2DATA is 6502 C bit
Wait for data in R2DATA, this is 6502 A register
OSCLI
Wait until R2DATA not full, write CLINO (&02) to R2DATA
FOR all characters in the command string (including terminating CR)
DO [
Wait until R2DATA not full, write character to R2DATA
]
Wait for data in R2DATA and read it
IF this byte =&80
THEN [
code has been loaded into the parasite by an interrupt protocol and it
should be entered at the address given by the last R4 protocol type 4
address.
]
OSBYTE
IF osbyte < &80
THEN [
Wait until R2DATA not full, write SBYTNO (&04) to R2DATA
Wait until R2DATA not full, write parameter for 6502 X register to R2DATA
Wait until R2DATA not full, write osbyteno to R2DATA
Wait for data in R2DATA, read R2DATA which is 6502 X register
]
ELSEIF osbyteno = &82 THEN [ resultis machine high order address ]
ELSEIF osbyteno = &83 THEN [ resultis low memory value ]
ELSEIF osbyteno = &84 THEN [ resultis high memory value ]
ELSE [
Wait until R2DATA not full, write SBYTNO (&04) to R2DATA
Wait until R2DATA not full, write parameter for 6502 X register to R2DATA
Wait until R2DATA not full, write parameter for 6502 Y register to R2DATA
Wait until R2DATA not full, write osbyteno to R2DATA
IF osbyteno = &9D THEN RETURN from protocol (no reply)
Wait for data in R2DATA, bit 7 is 6502 C flag
Wait for data in R2DATA, byte read is 6502 Y register
Wait for data in R2DATA, byte read is 6502 X register
]
OSWORD
IF oswordno = &00
THEN [
Wait until R2DATA not full, write RDLNNO (&0A) to R2DATA
Wait until R2DATA not full, write upper bound char to R2DATA
Wait until R2DATA not full, write lower bound char to R2DATA
Wait until R2DATA not full, write length allowed to R2DATA
Wait until R2DATA not full, write &07 allowed to R2DATA
Wait until R2DATA not full, write &00 allowed to R2DATA
Wait for data in R2DATA
IF this data > &7F THEN [ RETURN from protocol, escape was pressed ]
Read a CR terminated string from R2DATA
]
ELSE [
Wait until R2DATA not full, write WORDNO (&08) to R2DATA
Wait until R2DATA not full, write oswordno to R2DATA
Wait until R2DATA not full, write #params to send to R2DATA
Wait parameter block to R2DATA, last byte first
Wait until R2DATA not full, write #params to receive to R2DATA
Read bytes back from R2DATA into parameter block, last byte first
]
The number of parameters to send/receive is determined by:
IF oswordno < &14
THEN [
oswordno parameters to send parameters to receive
1 0 5
2 5 0
3 0 5
4 5 0
5 2 5
6 5 0
7 8 0
8 14 0
9 4 5
10 1 9
11 1 5
12 5 0
13 0 8
14 16 16
15 16 16
16 16 13
17 13 1
18 0 128
19 8 8
20 128 128
]
ELSEIF oswordno < &80
THEN [
#params to send = 16
#params to receive = 16
]
ELSE [
byte 0 of transfer block = #params to send
byte 1 of transfer block = #params to receive
]
OSBPUT
Wait until R2DATA not full, write BPUTNO (&10) to R2DATA
Wait until R2DATA not full, write file handle to R2DATA
Wait until R2DATA not full, write 6502 A to R2DATA (byte to write)
Wait for data in R2DATA, discard it
OSBGET
Wait until R2DATA not full, write BGETNO (&0E) to R2DATA
Wait until R2DATA not full, write file handle to R2DATA
Wait for data in R2DATA, top bit of byte is 6502 C flag
Wait for data in R2DATA, this is byte read from file
OSFIND
Wait until R2DATA not full, write FINDNO (&12) to R2DATA
Wait until R2DATA not full, write type of open to R2DATA
IF type = 0
THEN [
Wait until R2DATA not full, write file handle to R2DATA
Wait for data in R2DATA, read result
]
ELSE [
Wait until R2DATA not full, write file name string to R2DATA including CR
Wait for data in R2DATA, read handle from R2DATA
]
OSARGS
Wait until R2DATA not full, write ARGSNO (&0C) to R2DATA
Wait until R2DATA not full, write file handle to R2DATA
Wait until R2DATA not full, write 4 bytes osarg_data to R2DATA (most
significant byte first)
Wait until R2DATA not full, write operation code to R2DATA
Wait for data in R2DATA, read fs type from R2DATA
Wait for data in R2DATA, read 4 bytes osarg_fs type from R2DATA (most
significant byte first)
Note: osarg_data is file sequential pointer or length depending on the type
of OSARGS call.
OSFILE
Wait until R2DATA not full, write FILENO (&14) to R2DATA
Wait until R2DATA not full, write 16 byte OSFILE control block to R2DATA
(last byte written first)
Wait until R2DATA not full, write filename to R2DATA including CR
Wait until R2DATA not full, write type of transfer to R2DATA (transfer is
completed under interrupt using R3, R4)
Wait for data in R2DATA, low 7 bits is filing system type
Wait for data in R2DATA, read 16 byte OSFILE control block (last byte first)
OSGBPB
Wait until R2DATA not full, write GBPBNO (&16) to R2DATA
Wait until R2DATA not full, write 13 byte OSGBPB control block to R2DATA
(last byte written first)
Wait until R2DATA not full, write type of transfer to R2DATA (transfer is
completed under interrupt using R3, R4)
Wait for data in R2DATA, read 13 byte OSGBPB control block (last byte first)
Wait for data in R2DATA, bit 7 is 6502 C flag
Wait for data in R2DATA, read 6502 A register
Interrupt driven operations
In addition to thes parasite initiated activities the parasite is also
required to respond to interrupts from registers 1, 3 and 4.
The determine the source of an interrupt it is important to follow the order:
1. Check for register 4 interrupt
2. Check for register 1 interrupt
Register 1 interrupts
These occur only in the host to parasite direction. The interrupt sequence
is:
Read type byte from R1DATA
IF type < 0
THEN [ ; Escape flag update
Replace the escape flag with bit 6 of type
RETURN from servicing interrupt
]
ELSE [ ; Event signal
Interrupt_R1_read 6502_Y event parameter
Interrupt_R1_read 6502_X event parameter
Interrupt_R1_read 6502_A event parameter
; BBC machine will now continue processing
; actions to service event can now be taken
]
Where Interrupt_R1_read is:
UNTIL data ready in R1
DO [
IF data ready in R4 THEN CALL R4_interrupt_service
]
RETURN read R1DATA
Register 5 interrupts
Read type byte from R4DATA
IF type < 0
THEN [ ; BBC machine is reporting an error
Wait for data in R2DATA, read and discard it
Wait for data in R2DATA, read error number from R2DATA
Read a zero byte terminated string from R2DATA
]
ELSE [ ; type is a command to initiate a register 3 block transfer
Wait for data in register 4, read claimer identity from R4DATA
CASE type OF
[
0 : ; Single byte transfer parasite to host
Read 4 byte base address for transfer from R4DATA, msb first
Set NMI routine for this transfer type
Wait for and remove synchronising byte from R4DATA
1 : ; Single byte transfer host to parasite
Read 4 byte base address for transfer from R4DATA, msb first
Set NMI routine for this transfer type
Wait for and remove synchronising byte from R4DATA
2 : ; Double byte transfer parasite to host
Read 4 byte base address for transfer from R4DATA, msb first
Set NMI routine for this transfer type
Wait for and remove synchronising byte from R4DATA
3 : ; Double byte transfer host to parasite
Read 4 byte base address for transfer from R4DATA, msb first
Set NMI routine for this transfer type
Wait for and remove synchronising byte from R4DATA
4 : ; No transfer (pass address host to parasite only)
Read 4 byte base address for transfer from R4DATA, msb first
Wait for data in R4DATA, discard it
5 : ; No transfer (filing system release)
6 : ; 256 byte transfer parasite to host without interrupt
Read 4 byte base address for transfer from R4DATA, msb first
Wait for data in R4DATA, discard it
Transfer 256 bytes to host via R3DATA
Write a byte into R4DATA to stop unwanted interrupts on host
7 : ; 256 byte transfer host to parasite without interrupt
Read 4 byte base address for transfer from R4DATA, msb first
Wait for data in R4DATA, discard it
Transfer 256 bytes from host via R3DATA
]
RETURN from interrupt
]
Notes:
(i) For type 0-3: As soon as the synchronising byte is removed register 3
transfer requests (NMIs) will start to occur. When the interrupt occurs
1 or 2 bytes are transferred (depending on the current mode).
(ii) A release (type 5) is a guarantee that no more register 3 NMIs will
occur for the current transfer.
(iii) The transfers must take place within the following times:
Type Max Service Time Delay between sync and transfer start
0 24uS per byte 24uS
1 24uS per byte 24uS
2 26uS per byte 24uS
3 26uS per byte 24uS
6 10uS per byte 19uS
7 10uS per byte 19uS
END