ARM CODE SINGLE STEPPER (2)

David Spencer adds enhancements to last month's program, including dual screen operation.

A potential problem with any debugger program is that the screen output it produces will interfere with that produced by the target program. To get around this there are a number of possible solutions:
1. Restrict the debugger's output to a window on the screen, saving that window before it is used, and restoring it afterwards.
2. Use two banks of screen memory, devoting one to the program's output and the other to the debugger.
3. Communicate with the debugger via a remote terminal, using the serial port as an interface.

Each of these methods has its own advantages and disadvantages. With the first method the output 'screen' for the debugger is limited in size, and hence the information that can be displayed is restricted. The second method is better, but requires two complete screen banks which could cause memory problems. The serial port solution solves all these problems, but requires extra hardware to implement. The additions to the single stepper given here allow dual screens, or serial port output to be used.

Start by adding the lines given here to the listing from last month. It is obviously important that the original program has not been renumbered in any way. Once the changes have been made, save the new program. The program can then be run and the new module installed as described last month.

USING THE NEW MODULE

The single stepper is started as before, but will now select the dual screen, and clear it. Pressing the Tab key will display the program's screen, which is where all the program output will be generated. A subsequent keypress will return to the single stepper screen. All the other commands are as before. When using dual screens, there must be sufficient memory to allow two banks of screen RAM for the current mode.

To use remote tracing through the serial port, the single stepper should be started using either the command *SERIALSTEP instead of *SINGLESTEP, or SWI "SingleStep_StartSerial" (&C0801). See last month's article for more details of starting the single stepper. The single stepper will use the currently set baud rate, data format, and XON/XOFF setting, so these must be set up beforehand using SYS "OS_SerialOp", or the equivalent *FX calls. Of course, the remote terminal must also be set up to send and receive plain text. If you have a Master 128 then the built-in Terminal application is ideal. In this mode all screen output produced by the single stepper will be passed to the remote machine. Similarly, all the single stepper keyboard input will be taken from the remote machine.

OTHER CHAnGES

A couple of other changes have been made to the original single stepper. Firstly, the VDU queue is now preserved across instructions. Previously, it was not possible to single step through multi-byte VDU sequences as the single stepper's own output got mixed with that produced by the program.

Secondly, a further SWI has been added - "SingleStep_StopStep" (&C0802) which is equivalent to the 'G' command. In other words, it resumes normal execution from the next instruction. This SWI, together with SWI "SingleStep_StartStep" can be used to bracket a particular section of interest within a larger program.

A bug which caused the single stepper to 'disappear' if the computer was reset while it was in use has also been corrected.

80 DIM code 4000
120 EQUD 0:EQUD service:EQUD title
160 EQUS "StartStep":EQUB 0
161 EQUS "StartSerial":EQUB 0
162 EQUS "StopStep":EQUB 0:EQUB 0
260 EQUD shelp
261 EQUS "Serialstep":EQUB 0:ALIGN
262 EQUD serial:EQUD &10001:EQUD sssyn
263 EQUD sshelp:EQUB 0:ALIGN
264 .sshelp EQUS "*Serialstep invokes the machine code single stepper to work via a remote terminal.":EQUB 13
265 .sssyn EQUS "Syntax: Serialstep <start address>":EQUB 0:ALIGN
310 .init MOV R6,R14:MOV R3,#1536
341 STR R0,[R2,#&400]
360 .swi CMP R11,#2:MOVHIS PC,R14
370 LDR R12,[R12]:STRB R11,[R12,#171]
371 LDRB R11,[R12,#169]:BEQ swioff
451 .serial LDR R12,[R12]:MOV R2,#1
452 STRB R2,[R12,#171]:B step1
460 .step LDR R12,[R12]:MOV R2,#0
461 STRB R2,[R12,#171]:.step1
611 MOV R0,#1:LDRB R1,[R12,#171]
612 CMP R1,#1:MOVEQ R0,#0:BLNE window
613 STRB R0,[R12,#176]:MOV R0,#0
614 STRB R0,[R12,#177]
615 STRB R0,[R12,#178]:BL savevdu
945 CMP R0,#9:BEQ tab
1185 BL defwindow
1271 BL restorevdu
1272 BL defwindow
2451 BL restorevdu
2511 BL savevdu
3670 .jumpback MOV PC,R14
3680 .savevdu STMFD R13!,{R14}
3690 MOV R0,#&3C:MOV R1,#0:MOV R2,#0
3700 ADD R3,R12,#&400:SWI "OS_SpriteOp"
3710 LDRB R1,[R12,#171]
3720 ORR R1,R1,R1,LSL #1:MOV R2,#0
3730 MOV R0,#&EC:SWI "OS_Byte"
3740 LDRB R1,[R12,#171]:MOV R0,#2:SWI "OS_Byte"
3741 LDRB R1,[R12,#171]:CMP R1,#1
3742 BEQ savevdu2:MOV R0,#112
3743 MOV R1,#2:SWI "OS_Byte"
3744 MOV R0,#113:MOV R1,#2
3745 SWI "OS_Byte"
3746 LDRB R1,[R12,#178]:CMP R1,#0
3747 BNE savevdu2:BL window
3748 SWI &10C:MOV R0,#1:STRB R0,[R12,#178]
3749 .savevdu2
3750 LDMFD R13!,{PC}^
3760 .restorevdu STMFD R13!,{R14}
3770 MOV R0,#&3C:MOV R1,#0:MOV R2,#0
3780 MOV R3,#1:SWI "OS_SpriteOp"
3790 MOV R1,#0:MOV R2,#0
3800 MOV R0,#&EC:SWI "OS_Byte"
3801 MOV R0,#2:MOV R1,#0:SWI "OS_Byte"
3802 LDRB R1,[R12,#176]:CMP R1,#2
3803 MOV R0,#112
3804 MOV R1,#1:SWI "OS_Byte"
3805 MOV R0,#113:MOV R1,#1
3806 SWI "OS_Byte":B restorevdu3
3807 .restorevdu2
3810 .restorevdu3 LDRB R0,[R12,#177]
3811 CMP R0,#0:STRNEB R0,[R12,#176]
3812 MOVNE R0,#0:STRNEB R0,[R12,#177]
3813 LDMFD R13!,{PC}^
4000 .swioff LDR R0,[R12,#160]
4010 LDR R1,[R12,#164]:STR R1,[R0]
4020 MOV R0,#0:STR R0,[R12,#169]
4030 MOVS PC,R14
4040 .window STMFD R13!,{R14}
4045 MVN R0,#0:MOV R1,#1
4050 SWI "OS_ReadModeVariable"
4060 MOV R3,R2
4070 MVN R0,#0:MOV R1,#2
4080 SWI "OS_ReadModeVariable"
4090 SWI &100+28:MOV R0,#0
4100 SWI "OS_WriteC"
4110 MOV R0,R2:SWI "OS_WriteC"
4120 MOV R0,R3:SWI "OS_WriteC"
4130 MOV R0,#0:SWI "OS_WriteC"
4140 LDMFD R13!,{PC}^
4150 .tab LDRB R0,[R12,#171]
4160 CMP R0,#0:BNE main
4170 BL restorevdu
4180 .tab2 SWI "OS_ReadC"
4190 BCC tab3:MOV R0,#&7E
4200 SWI "OS_Byte"
4210 .tab3 BL savevdu
4220 B main
4230 .defwindow STMFD R13!,{R14}
4235 MOV R0,#134
4240 SWI "OS_Byte":SWI &100+26
4250 SWI &100+31:MOV R0,R1
4260 SWI "OS_WriteC":MOV R0,R2
4270 SWI "OS_WriteC"
4280 LDMFD R13!,{PC}^
4290 .service STMFD R13!,{R0-R2,R14}
4300 CMP R1,#&27:LDMNEFD R13!,{R0-R2,PC}^
4310 LDR R2,[R12]:MOV R0,#0
4320 STRB R0,[R2,#169]
4330 LDMFD R13!,{R0-R2,PC}^
9999 ]NEXT
10000 SYS "OS_File",10,"Sstep",&FFA,,code,O%