; > 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