; > TestSrc.ExtCmd

        TTL RISC OS 2+ POST external commands
;
; External test commands for RISC OS ROM.
;
; Provides functions to read data, write data and execute code using
; parameters from an external controlling host.
;
; A minimal set of opcodes should be used (ideally, only B, LDR and ADDS)
; so that a processor test may be validly included in the internal test
; sequence.
;
;------------------------------------------------------------------------
; History
;
; Date          Name            Comment
; ----          ----            -------
; 27-Nov-89     ArtG            Initial version
; 06-Dec-89     ArtG            Release 0.2 for integration
; 30-Mar-90	ArtG		Added NOPs (ADDS r0,r0,r0) after ADDS pc,..
; 19-Apr-90	ArtG		Speedups for read/write commands.
; 15-May-90	ArtG		Fixed multiple %13 label in ts_W_FIW
; 22-May-90	ArtG		Fixed bugs in ts_B_MWW, ts_W_RIB
; 18-Jun-93	ArtG		Added Arm600 control instructions
; 1-Jul-93	ArtG		Replaced ADDS pc.. instructions with ADD pc..
;				for compatibility with SVC32_mode. 
;
;------------------------------------------------------------------------



;
; All these routines use registers as follows :
;
;       r0  - always zero
;       r1
;       r2
;       r3  - undisturbed : used as constant by I/O routine
;       r4  - return value from I/O routine, parameter to I/O routines
;       r5
;       r6
;       r7  - saved value of command byte on entry
;       r8  - operation counter
;       r9  - pointer to data transfer operation
;       r10 - increment value (0, 1 or 4) to add to pointer in r9
;       r11 - decrement constant (-1) to add to counter in r8
;       r12 - checksum accumulator
;       r13 - pointer to operation code
;       r14 - return address for calls to I/O routines
;

        SUBT    External command handlers
;
; Called by vectoring through command_table. 
; R4 contains command byte (including 3 option bits)
; Get operation count
; Get address
; If single-word data
;   Get data
;   Get checksum
;   Reply with command byte or FF
;   Do operation
; Else
;   For each word
;     Get data
;     Do operation 
;   Get checksum
;   Reply with command byte or FF
; Return by branching to GetCommand.

ts_write_memory    ROUT

        ADDS    r13,r0,r4               ; save the control byte
        ADDS    r7,r0,r4
        ADDS    r14, r0, pc             ; setup return address for ..
        B       ts_GetWord              ; .. get operation count word
        ADDS    r8, r0, r4              ; r8 is operation count
        ADDS    r12,r0,r4               ; initialise checksum 
        ADDS    r14, r0, pc
        B       ts_GetWord              ; r9 is initial target address
        ADDS    r9, r0, r4
        ADDS    r12,r12,r4              ; accumulate checksum 
        ADDS    r10,r0,r0               ; set initial constants
        LDR     r11,%01
	ADD     pc,pc,r0
01
        DCD     (0 - 1)

;
; Check for operations which don't involve reading a block of data.
; These are acknowledged BEFORE performing the operation.
;
	ADDS	r0,r0,r0
        ADDS    r13,r13,r13             ; convert operation code to vector 
        ADDS    r13,r13,r13
        LDR     r4, %02
	ADD     pc,pc,r0
02
        &       (ts_write_cmd_table - %03)
        ADDS    r4,pc,r4
        ADDS    r13,r4,r13
03
        LDR     r13,[r13]               ; fetch pointer to code
        LDR     r4,%04
	ADD     pc,pc,r0
04
        &       (ts_write_cmd_table - ts_W_fetch_operations) 
	ADDS	r0,r0,r0
        ADDS    r4,r4,r13
        BCS     ts_Write_getdata        ; defer acknowledgement till later

        ; check the above test was valid, given code layout
	; Note - this is also required by code near ts_Write_cmd_done

        ASSERT  (ts_W_RSW <  ts_W_fetch_operations)
        ASSERT  (ts_W_RSB <  ts_W_fetch_operations)
        ASSERT  (ts_W_RIW <  ts_W_fetch_operations)
        ASSERT  (ts_W_RIB <  ts_W_fetch_operations)
        ASSERT  (ts_W_FSW >= ts_W_fetch_operations)
        ASSERT  (ts_W_FSB >= ts_W_fetch_operations)
        ASSERT  (ts_W_FIW >= ts_W_fetch_operations)
        ASSERT  (ts_W_FIB >= ts_W_fetch_operations)

;
; Fetch the first data word and checksum, and acknowledge
;

        ADDS    r14,r0,pc               ;get next data word
        B       ts_GetWord
        ADDS    r12,r12,r4              ;accumulate checksum
        ADDS    r10,r0,r4
        ADDS    r14,r0,pc
        B       ts_GetWord              ;read transmitted checksum
        ADDS    r4,r4,r12               ;tx + total should be zero
        LDR     r5,%05
        ADD     pc,pc,r0
05
        &       (0 - 1)
        ADDS    r5,r5,r4                ;carry set on checksum failure
        BCS     ts_cmd_error

;
; Checksum looks OK. Send the command and the checksum back.
;
	LDR	r4,%06
	ADD     pc,pc,r0
06
	&	ts_WriteCmdByte
        ADDS    r4,r4,r7                ;restore the original 

        ADDS    r14,r0,pc
        B       ts_SendByte
        ADDS    r4,r0,r12               ;then send the calculated checksum
        ADDS    r14,r0,pc
        B       ts_SendWord

        ADDS    r4,r0,r10               ;restore the data word
        ADDS    r10,r0,r0               ;and the zero in r10
        B       ts_Write_usedata        ;dive off to do the work

;
; Enter the main loop, repeating the operation labelled in r13.
;

ts_Write_getdata
        ADDS    r9,r9,r10               ;perform increment operation
        ADDS    r8,r8,r11               ;countdown repeat counter
        BCC     ts_Write_cmd_ack
        ADDS    r14,r0,pc               ;get next data word
        B       ts_GetWord
        ADDS    r12,r12,r4              ;accumulate checksum
	B	%07

ts_Write_usedata
        ADDS    r9,r9,r10               ;perform increment operation
ts_Write_count
        ADDS    r8,r8,r11               ;countdown repeat counter
        BCC     ts_Write_cmd_done
07
        ADD     pc,pc,r13               ;jump back to operations
        &       0

;
; In this table, the operation after any word fetch is vectored by
; the 3 least significant bits of the command byte to perform some 
; combination of writing with  : 
;
; bit 2 -> 0    R : repeat with same data
;          1    F : fetch more data for next operation
;
; bit 1 -> 0    S : leave address static
;          1    I : increment address after operation
;
; bit 0 -> 0    W : word operation
;          1    B : byte operation
;

        ASSERT  ((ts_write_cmd_table - %07) = 8)

ts_write_cmd_table

        DCD     (ts_W_RSW - ts_write_cmd_table)
        DCD     (ts_W_RSB - ts_write_cmd_table)
        DCD     (ts_W_RIW - ts_write_cmd_table)
        DCD     (ts_W_RIB - ts_write_cmd_table)
        DCD     (ts_W_FSW - ts_write_cmd_table)
        DCD     (ts_W_FSB - ts_write_cmd_table)
        DCD     (ts_W_FIW - ts_write_cmd_table)
        DCD     (ts_W_FIB - ts_write_cmd_table)

;
; And here are the trailers that perform these operations.
; Each is started with the data in r4, address in r9 and completes
; by returning to Write_getdata (to read another word) or Write_usedata
; (to repeat with the same data) with r10 = increment value (initially 0)
;

ts_W_RSW
        STR     r4,[r9]                 ;store word, repeat address
        ADDS    r8,r8,r11               ;countdown repeat counter
        BCS     ts_W_RSW
        B       ts_Write_cmd_done

ts_W_RSB
        STRB    r4,[r9]                 ;store byte, repeat address
	ADDS	r8,r8,r11
	BCS	ts_W_RSB
        B       ts_Write_cmd_done

ts_W_RIW
        LDR     r10,%11
	ADD     pc,pc,r0
11
        DCD     4
12
        STR     r4,[r9]                 ;store word, increment word address
        ADDS    r9,r9,r10               ;perform increment operation
        ADDS    r8,r8,r11               ;countdown repeat counter
	BCS	%B12
        B       ts_Write_cmd_done


ts_W_RIB
	LDR	r10,%13
	ADD     pc,pc,r0
13
        DCD     1
14
        STRB    r4,[r9]                 ;store byte, increment byte address
	ADDS	r9,r9,r10
	ADDS	r8,r8,r11
	BCS	%B14
	B	ts_Write_cmd_done



ts_W_fetch_operations                   ;all past here fetch new data
                                        ;on each loop

ts_W_FSW
        STR     r4,[r9]                 ;store word, repeat address
        B       ts_Write_getdata

ts_W_FSB
        STRB    r4,[r9]                 ;store byte, repeat address
        B       ts_Write_getdata

ts_W_FIW
        STR     r4,[r9]                 ;store word, increment word address
        LDR     r10,%15
        B       ts_Write_getdata
15
        DCD     4

ts_W_FIB
        STRB    r4,[r9]                 ;store byte, increment byte address
        LDR     r10,%16
        B       ts_Write_getdata
16
        DCD     1 


;
; Operations completed. Operations that read multiple data words from
; the host must now checksum and acknowledge the block (even though
; it's a bit late to do anything about it)
;

ts_Write_cmd_ack
;
; Operation involved multiple fetches - only now ready to ACK. 
;
        ADDS    r14,r0,pc
        B       ts_GetWord              ;read transmitted checksum
        ADDS    r4,r4,r12               ;tx + total should be zero
        LDR     r5,%25
        ADD     pc,pc,r0
25
        &       (0 - 1)
        ADDS    r5,r5,r4                ;carry set on checksum failure
        BCS     ts_cmd_error

;
; Checksum looks OK. Send the command and the checksum back.
;
	LDR	r4,%26
	ADD     pc,pc,r0
26
	&	ts_WriteCmdByte
        ADDS    r4,r4,r7                ;restore the original 
        ADDS    r14,r0,pc
        B       ts_SendByte
        ADDS    r4,r0,r12               ;then send the calculated checksum
        ADDS    r14,r0,pc
        B       ts_SendWord

ts_Write_cmd_done
        B       ts_GetCommand



; Called by vectoring through command_table. 
; R4 contains command byte (including 3 option bits)
; Get operation count
; Get address
; Reply with command byte or FF
; Reply with checksum
; For each word
;   Read data
;   If Verbose option
;     Send data
; If Quiet option
;   Send result of read operation
; Send checksum of result packet
; Return by branching to GetCommand.

ts_read_memory    ROUT

        ADDS    r13,r0,r4               ; save the control byte
        ADDS    r7,r0,r4

        ADDS    r14, r0, pc             ; setup return address for ..
        B       ts_GetWord              ; .. get operation count word
        ADDS    r8, r0, r4              ; r8 is operation count
        ADDS    r12,r0,r4               ; initialise checksum 

        ADDS    r14, r0, pc
        B       ts_GetWord              ; r9 is initial target address
        ADDS    r9, r0, r4
        ADDS    r12,r12,r4              ; accumulate checksum 
        ADDS    r10,r0,r0               ; set initial constants
        LDR     r11,%01
        ADD     pc,pc,r0
01
        DCD     (0 - 1)
;
; Convert the operation options into a code pointer
;
	ADDS	r0,r0,r0
        ADDS    r13,r13,r13             ; convert operation code to vector 
        ADDS    r13,r13,r13
        LDR     r4, %02
        ADD     pc,pc,r0
02
        &       (ts_read_cmd_table - %03)
        ADDS    r4,pc,r4
        ADDS    r13,r4,r13
03
        LDR     r13,[r13]               ; fetch pointer to code

;
; Fetch the checksum, and acknowledge
;

        ADDS    r14,r0,pc
        B       ts_GetWord              ;read transmitted checksum
        ADDS    r4,r4,r12               ;tx + total should be zero
        LDR     r5,%05
        ADD     pc,pc,r0
05
        &       (0 - 1)
        ADDS    r5,r5,r4                ;carry set on checksum failure
        BCS     ts_cmd_error

;
; Checksum looks OK. Send the command and the checksum back.
;
	LDR	r4,%06
	ADD     pc,pc,r0
06
	&	ts_ReadCmdByte
        ADDS    r4,r4,r7                ;restore the original 
        ADDS    r14,r0,pc
        B       ts_SendByte
        ADDS    r4,r0,r12               ;then send the calculated checksum
        ADDS    r14,r0,pc
        B       ts_SendWord

        ADDS    r12,r0,r0               ;initialise the upload checksum 
        B       ts_Read_count		;enter the loop

;
; Enter the main loop, repeating the operation labelled in r13.
; This loop is for operations that finish with all data sent

ts_Read_Txdata                          ;send data to host
        ADDS    r12,r12,r4              ;accumulate the checksum
        ADDS    r14,r0,pc
        B       ts_SendWord             ;send this word
        ADDS    r9,r9,r10               ;perform increment operation
        ADDS    r8,r8,r11               ;countdown repeat counter
        BCC     ts_Read_cmd_done
        B       %07                     ;go off to the jump handler

ts_Read_count
        ADDS    r8,r8,r11               ;countdown repeat counter
        BCC     ts_Read_cmd_read        ;send data at finish
07
        ADD     pc,pc,r13               ;jump back to operations
        &       0

;
; In this table, the operation after any word fetch is vectored by
; the 2 least significant bits of the command byte to perform some 
; combination of reading with  : 
;
; bit 2 -> 0    Q : read data without reporting it
;          1    V : Transmit the result of every read operation
;
; bit 1 -> 0    S : leave address static
;          1    I : increment address after operation
;
; bit 0 -> 0    W : word operation
;          1    B : byte operation
;

        ASSERT  ((ts_read_cmd_table - %07) = 8)

ts_read_cmd_table

        DCD     (ts_R_QSW - ts_read_cmd_table)
        DCD     (ts_R_QSB - ts_read_cmd_table)
        DCD     (ts_R_QIW - ts_read_cmd_table)
        DCD     (ts_R_QIB - ts_read_cmd_table)
        DCD     (ts_R_VSW - ts_read_cmd_table)
        DCD     (ts_R_VSB - ts_read_cmd_table)
        DCD     (ts_R_VIW - ts_read_cmd_table)
        DCD     (ts_R_VIB - ts_read_cmd_table)

;
; And here are the trailers that perform these operations.
; Each is started with the data in r4, address in r9 and completes
; by returning to Write_getdata (to read another word) or Write_usedata
; (to repeat with the same data) with r10 = increment value (initially 0)
;

ts_R_QSW
        LDR     r4,[r9]                 ;read word, repeat address
        ADDS    r8,r8,r11               ;countdown repeat counter
	BCS	ts_R_QSW
        B       ts_Read_cmd_read        ;send data at finish


ts_R_QSB
        LDRB    r4,[r9]                 ;read byte, repeat address
	ADDS	r8,r8,r11
	BCS	ts_R_QSB
        B       ts_Read_cmd_read

ts_R_QIW
        LDR     r10,%11
	ADD     pc,pc,r0
11
        DCD     4
12
        LDR     r4,[r9]                 ;read word, increment word address
        ADDS    r9,r9,r10               ;perform increment operation
        ADDS    r8,r8,r11               ;countdown repeat counter
	BCS	%B12
        B       ts_Read_cmd_read        ;send data at finish


ts_R_QIB
        LDR     r10,%13
	ADD     pc,pc,r0
13
        DCD     1
14
        LDRB    r4,[r9]                 ;read byte, increment byte address
        ADDS    r9,r9,r10               ;perform increment operation
        ADDS    r8,r8,r11               ;countdown repeat counter
	BCS	%B14
        B       ts_Read_cmd_read        ;send data at finish


ts_R_VSW
        LDR     r4,[r9]                 ;read and tx word, repeat address
        B       ts_Read_Txdata

ts_R_VSB
        LDRB    r4,[r9]                 ;read and tx byte, repeat address
        B       ts_Read_Txdata

ts_R_VIW
        LDR     r4,[r9]                 ;read and tx word, next word address
        LDR     r10,%15
        B       ts_Read_Txdata
15
        DCD     4

ts_R_VIB
	ADDS	r0,r0,r0
        LDRB    r4,[r9]                 ;read and tx byte, next byte address
        LDR     r10,%16
        B       ts_Read_Txdata
16
        DCD     1 


;
; Operations completed. Report final result and checksum back to host.
; Quiet option only transmits read data here (this is pretty useless
; except where only one value was read)
;

ts_Read_cmd_read
	ADDS	r12,r12,r4
        ADDS    r14,r0,pc               ;send result of 'quiet' read
        B       ts_SendWord
ts_Read_cmd_done
        SUBS    r4,r0,r12               ;get overall checksum  - can't think
        ADDS    r14,r0,pc               ;how to do this using only ADDS !
        B       ts_SendWord

        B       ts_GetCommand


; Called by vectoring through command table.
; if option 1 set, read processor mode
; Read address
; Read and check checksum
; Reply with command byte or FF
; Reply with checksum
; if option 1 set, load SPSR
; Jump to code


ts_execute      ROUT
	ADDS	r12,r0,r0		; initialise checksum adder
	LDR	r8,%00			; initialise msr-jumper
	ADD	pc,pc,r0
00
	&	4
	ADDS	r7,r4,r4		; get operation type
	ADDS	r7,r7,r7
	ADD 	pc,pc,r7		; jump to pc + (r4 * 4)
	&	0

	B	%FT10
	B	%FT08
	B	%FT10
	B	%FT10
	B	%FT10
	B	%FT10
	B	%FT10
	B	%FT10


08	ADDS	r14,r0,pc		; get new processor mode
	B	ts_GetWord
	ADDS	r12,r0,r4
	ADDS	r8,r0,r0		; kill msr-jumper
10
        ADDS    r14,r0,pc
        B       ts_GetWord              ; get jump address
        ADDS    r9,r12,r4
        ADDS    r14,r0,pc
        B       ts_GetWord              ; get checksum
        ADDS    r4,r4,r9
        LDR     r5,%11
        ADD     pc,pc,r0
11
        &       (0 - 1)
        ADDS    r4,r5,r4                ; compare total chex with zero
        BCS     ts_cmd_error            ; carry set on error

	LDR	r4,%12
	ADD     pc,pc,r0
12
	&	ts_ExecuteCmdByte
	ADDS	r0,r0,r0
        ADDS    r14,r0,pc  	        ; echo command byte
        B       ts_SendByte
        ADDS    r4,r0,r9                ;return checksum (actually, the
        ADDS    r14,r0,pc               ; entire message ..)
        B       ts_SendWord


; Now jump to the location given in the message, using the given status bits

	ADD	pc,pc,r8		; jump over the msr instruction
	NOP
	&	2_11100001011010011111000000001100 ; 

	ADDS	r14,pc,r0		; Load the address of %13 into r14
			           	; to provide a return address
        ADD     pc,r0,r9		; Do the jump
13
        B      ts_GetCommand



; Called by vectoring through command table
; Read operation count
; Read target addresses
; Read data
; Send command byte or FF
; Send checksum
; For all operation count
;   write data 
;   if read-back option
;     read data
; Return by branching to GetCommand


ts_bus_exercise	ROUT
        ADDS    r7,r0,r4                ; save the control byte

        ADDS    r14, r0, pc             ; setup return address for ..
        B       ts_GetWord              ; .. get operation count word
        ADDS    r8, r0, r4              ; r8 is operation count
        ADDS    r12,r0,r4               ; initialise checksum 

        ADDS    r14, r0, pc
        B       ts_GetWord              ; r9 is first target address
        ADDS    r9, r0, r4
        ADDS    r12,r12,r4              ; accumulate checksum 
        ADDS    r14, r0, pc
        B       ts_GetWord              ; r10 is second target address
        ADDS    r10, r0, r4
        ADDS    r12,r12,r4              ; accumulate checksum 

        ADDS    r14, r0, pc
        B       ts_GetWord              ; r11 is first data word
        ADDS    r11, r0, r4
        ADDS    r12,r12,r4              ; accumulate checksum 
        ADDS    r14, r0, pc
        B       ts_GetWord              ; r13 is second data word
        ADDS    r13, r0, r4
        ADDS    r12,r12,r4              ; accumulate checksum 

;
; Fetch the checksum, and acknowledge
;

        ADDS    r14,r0,pc
        B       ts_GetWord              ;read transmitted checksum
        ADDS    r4,r4,r12               ;tx + total should be zero
        LDR     r5,%05
        ADD     pc,pc,r0
05
        &       (0 - 1)
        ADDS    r5,r5,r4                ;carry set on checksum failure
        BCS     ts_cmd_error

;
; Checksum looks OK. Send the command and the checksum back.
;
	LDR	r4,%06
	ADD     pc,pc,r0
06
	&	ts_BusExCmdByte
        ADDS    r4,r4,r7                ;restore the original 
        ADDS    r14,r0,pc
        B       ts_SendByte
        ADDS    r4,r0,r12               ;then send the calculated checksum
        ADDS    r14,r0,pc
        B       ts_SendWord

	ADDS	r12,r0,r13		; Now addresses are in r9, r10
					; and data in r11, r12.
;
; Convert the operation options into a code pointer
;
        ADDS    r13,r7,r7              ; convert operation code to vector 
        ADDS    r13,r13,r13
        LDR     r4, %02
        ADD     pc,pc,r0
02
        &       (ts_busex_cmd_table - %03)
        ADDS    r4,pc,r4
        ADDS    r13,r4,r13
03
        LDR     r13,[r13]               ; fetch pointer to code
	LDR	r7, %04			; set up decrementer in r8
	ADD 	pc,pc,r0
04
	DCD	(0 - 1)
07
        ADD     pc,pc,r13               ; jump to operation
	&	0

;
; In this table, the operation after any word fetch is vectored by
; the 3 least significant bits of the command byte to perform some 
; combination of writing with  : 
;
; bit 2 -> 0    S : Perform separate data write ops
;          1    M : Use STM / LDM instructions 
;
; bit 1 -> 0    R : Perform only read operations
;          1    W : Write before reading
;
; bit 0 -> 0    W : word operation
;          1    B : byte operation
;
; Note that byte and multiple operations are mutually
; exclusive.
;

        ASSERT  ((ts_busex_cmd_table - %07) = 8)

ts_busex_cmd_table

        DCD     (ts_B_SRW - ts_busex_cmd_table)
        DCD     (ts_B_SRB - ts_busex_cmd_table)
        DCD     (ts_B_SWW - ts_busex_cmd_table)
        DCD     (ts_B_SWB - ts_busex_cmd_table)
        DCD     (ts_B_MRW - ts_busex_cmd_table)
        DCD     (ts_B_MRB - ts_busex_cmd_table)
        DCD     (ts_B_MWW - ts_busex_cmd_table)
        DCD     (ts_B_MWB - ts_busex_cmd_table)

ts_B_SRW
	LDR	r11,[r9]		; read-only separate words
	LDR	r12,[r10]
	ADDS	r8, r8, r7
	BCS	ts_B_SRW
	B	ts_B_done

ts_B_SRB
	LDRB	r11,[r9]		; read-only separate bytes
	LDRB	r12,[r10]
	ADDS	r8, r8, r7
	BCS	ts_B_SRB
	B	ts_B_done

ts_B_SWW
	STR	r11,[r9]		; write and read separate words
	STR	r12,[r10]
	LDR	r1,[r9]
	LDR	r2,[r10]
	ADDS	r8, r8, r7
	BCS	ts_B_SWW
	B	ts_B_done

ts_B_SWB
	STRB	r11,[r9]		; write and read separate bytes
	STRB	r12,[r10]
	LDRB	r1,[r9]
	LDRB	r2,[r10]
	ADDS	r8, r8, r7
	BCS	ts_B_SWB
	B	ts_B_done


ts_B_MRW
	LDMIA	r9,{r1,r2}		; read-only multiple words
	LDMIA	r10,{r1,r2}
	ADDS	r8, r8, r7
	BCS	ts_B_MRW
	B	ts_B_done

ts_B_MWW
	STMIA	r9,{r11,r12}		; write and read multiple words
	LDMIA	r9,{r1,r2}
	STMIA	r10,{r11,r12}
	LDMIA	r10,{r1,r2}
	ADDS	r8, r8, r7
	BCS	ts_B_MWW
	B	ts_B_done

;
; Orthogonally, these should be multiple byte operations - we can't do that, 
; so they actually do a single/multiple mixture.
; The first address argument is used for word-aligned operations and the
; second for byte-aligned operations - so set only the second address
; to a non-word-aligned address.

ts_B_MRB
	LDMIA	r9,{r1,r2}		; read-only multiple words
	LDRB	r1,[r10]		; then single bytes
	LDR 	r1,[r9]			; and single words
	ADDS	r8, r8, r7
	BCS	ts_B_MRB
	B	ts_B_done

ts_B_MWB
	STMIA	r9,{r11,r12}		; store multiple words
	STRB	r11,[r10]		; write byte
	STR	r12,[r9]		; write words
	LDMIA	r9,{r1,r2}
	LDRB	r1,[r10]
	LDR	r1,[r9]			; read single and multiple words
	ADDS	r8, r8, r7
	BCS	ts_B_MWB
;	B	ts_B_done

ts_B_done
	B	ts_GetCommand



;
; All commands fall through here to respond with FF if the received
; message block checksums fail.
;

ts_cmd_error    ROUT                    ; error in command
        LDR     r4, %01                 ; return error response
        ADD     pc,pc,r0
01
        DCD     ErrorCmd
	ADDS	r0,r0,r0
        ADDS    r14, r0, pc             ; send response byte to host
        B       ts_SendByte

        B       ts_GetCommand


; generic coprocessor register names

cpr0	CN	0
cpr1	CN	1
cpr2	CN	2
cpr3	CN	3
cpr4	CN	4
cpr5	CN	5
cpr6	CN	6
cpr7	CN	7
cpr8	CN	8
cpr9	CN	9
cpr10	CN	10
cpr11	CN	11
cpr12	CN	12
cpr13	CN	13
cpr14	CN	14
cpr15	CN	15


; Called by vectoring through command table.
; Read transfer value
; Read and check checksum
; Extract copro register number
; Index suitable MRC instruction
; Perform copro write
; Reply with command byte or FF
; Reply with checksum

ts_write_cpr15h	ROUT
	ADDS	r4,r4,#8		; adjust opcode for high registers
ts_write_cpr15l
	ADDS	r7,r0,r4		; save opcode to r7
        ADDS    r14,r0,pc
        B       ts_GetWord              ; get value for copro
        ADDS    r9,r0,r4
        ADDS    r14,r0,pc
        B       ts_GetWord              ; get checksum
        ADDS    r4,r4,r9
        LDR     r5,%01
        ADD     pc,pc,r0
01
        &       (0 - 1)
        ADDS    r4,r5,r4                ; compare total chex with zero
        BCS     ts_cmd_error            ; carry set on error

	ADDS	r13,r7,r7		; point into instruction table
	ADDS	r13,r13,r13
	ADDS	r13,r13,r13
	ADD 	pc,pc,r13		; jump to pc + (r7 * 8)
	&	0

	SetCop	r9,cpr0			; transfer instructions
	B	%02
	SetCop	r9,cpr1
	B	%02
	SetCop	r9,cpr2
	B	%02
	SetCop	r9,cpr3
	B	%02
	SetCop	r9,cpr4
	B	%02
	SetCop	r9,cpr5
	B	%02
	SetCop	r9,cpr6
	B	%02
	SetCop	r9,cpr7
	B	%02
	SetCop	r9,cpr8
	B	%02
	SetCop	r9,cpr9
	B	%02
	SetCop	r9,cpr10
	B	%02
	SetCop	r9,cpr11
	B	%02
	SetCop	r9,cpr12
	B	%02
	SetCop	r9,cpr13
	B	%02
	SetCop	r9,cpr14
	B	%02
	SetCop	r9,cpr15

02
	LDR	r4,%03
	ADD     pc,pc,r0
03
	&	ts_CPWCmdByte		; build command byte + option
	ADDS	r4,r4,r7
        ADDS    r14,r0,pc  	        ; echo command byte
        B       ts_SendByte
        ADDS    r4,r0,r9                ; return checksum 
        ADDS    r14,r0,pc               ;
        B       ts_SendWord

	B	ts_GetCommand




; Called by vectoring through command table.
; Read and check checksum
; Extract copro register number
; Index suitable MCR instruction
; Perform copro read
; Reply with command byte or FF
; Reply with checksum
; Send transfer results
; Send checksum

ts_read_cpr15h	ROUT
	ADDS	r4,r4,#8		; adjust opcode for high registers
ts_read_cpr15l
	ADDS	r7,r0,r4		; save opcode in r7
        ADDS    r14,r0,pc
        B       ts_GetWord              ; get checksum to r4
	ADDS	r9,r0,r4		; copy to r9
        LDR     r5,%01
        ADD     pc,pc,r0
01
        &       (0 - 1)
        ADDS    r4,r5,r4                ; compare total chex with zero
        BCS     ts_cmd_error            ; carry set on error

	LDR	r4,%02
	ADD     pc,pc,r0
02
	&	ts_CPRCmdByte		; build command byte + option
	ADDS	r4,r4,r7
        ADDS    r14,r0,pc  	        ; echo command byte
        B       ts_SendByte
        ADDS    r4,r0,r9                ; return checksum
        ADDS    r14,r0,pc
        B       ts_SendWord

	ADDS	r13,r7,r7		; point into instruction table
	ADDS	r13,r13,r13
	ADDS	r13,r13,r13
	ADD 	pc,pc,r13		; jump to pc + (r7 * 8)
	&	0

	ReadCop	r12,cpr0		; transfer instructions
	B	%03
	ReadCop	r12,cpr1
	B	%03
	ReadCop	r12,cpr2
	B	%03
	ReadCop	r12,cpr3
	B	%03
	ReadCop	r12,cpr4
	B	%03
	ReadCop	r12,cpr5
	B	%03
	ReadCop	r12,cpr6
	B	%03
	ReadCop	r12,cpr7
	B	%03
	ReadCop	r12,cpr8
	B	%03
	ReadCop	r12,cpr9
	B	%03
	ReadCop	r12,cpr10
	B	%03
	ReadCop	r12,cpr11
	B	%03
	ReadCop	r12,cpr12
	B	%03
	ReadCop	r12,cpr13
	B	%03
	ReadCop	r12,cpr14
	B	%03
	ReadCop	r12,cpr15

03
	ADDS	r4,r0,r12		; return result
	ADDS	r14,r0,pc
	B	ts_SendWord
	SUBS	r4,r0,r12		; return checksum
	ADDS	r14,r0,pc
	B	ts_SendWord

	B	ts_GetCommand


        END