Showing posts with label Monitor. Show all posts
Showing posts with label Monitor. Show all posts

Sunday, April 14, 2019

A 6809 Single Board Computer: Instruction Trace/Step Function

In my JMON monitor for the 6502, I implemented a trace or step function where you can execute code one instruction at a time and see the results of execution on the CPU registers. This is very useful for debugging, particularly as this implementation supports stepping through ROM code, something that can't be done with breakpoints.

For my 6809 single board computer I wondered if I could do the same for the 6809 processor. After some thought, it looked feasible, although more challenging as the 6809 has a larger and more complex instruction set than the 6502.

The basic idea is to take the instruction to be executed and store it in a buffer in RAM. The values of all CPU registers from the previous instruction trace are restored and the instruction is executed. A jump instruction is placed right after the traced instruction that goes back to the trace program. After execution, the new register values can be displayed and saved. This allows running code that is in ROM, as it gets copied to RAM when executed.

To implement this requires knowing the length of each instruction, as they can vary on the 6809 from one to five bytes depending on the instruction and addressing mode. From my previously written disassembler I already had code that could determine the instruction length and even disassemble it.

A wrinkle in this approach is handling instructions which cause a change in the flow of execution, such as a JMP (jump) instruction which would not return if simply executed in the buffer. We need to handle this instruction as a special case. We can examine the destination address and update the saved program counter accordingly. We don't need to actually execute it since it changes no other registers than the PC. We do need to check for and handle both direct (8 bit) and extended (16-bit) jump instructions. For direct, the destination address needs to be calculated by combining the instruction operand with the current value of the direct page (DP) register.

Jump to subroutine (JSR) in another special case. Here we need to push the return address on the stack (using the saved value of the stack pointer that we trace with) and then calculate the new PC value.

Similarly, we can handle BRA/LBRA and BSR/LBSR like JMP and JSR but the effective address needs to be calculated by adding the offset to the current PC value. Again we don't need to execute the instruction, just update the new PC value.

The interrupt related instructions SYNC, CWAI, SWI, SWI2, and SWI3 can all be simulated by pushing registers on the stack and setting the PC to the appropriate interrupt vector.

RTS and RTI are simulated by pulling registers (in the case of RTI) or just the PC (for RTS) off the stack. One wrinkle is that in the 6809 we need to check the E (Entire) flag in the condition code register to know of we should restore all registers from the stack.

Conditional branches are a little more tricky. They can transfer control to two different places depending on whether the condition is true or not. These are handled by writing into the execution buffer both the instruction being traced as well as different jumps depending on whether the branch is taken or not. The branch destinations can update the PC accordingly. The code in the buffer looks like below:

XXXX XX 03           Bxx $03 (Taken)         ; Instruction being traced
XXXX 7E XX XX        JMP BranchNotTaken
XXXX 7E XX XX Taken  JMP BranchTaken

We execute the instruction in the buffer and let it perform the test. We need to handle all the possible branch instructions, both short and long versions.

TFR (transfer) and EXG (exchange) instructions are okay to run except the cases where the source or destination is the PC. We need to handle those cases manually since it would otherwise change the flow of control.

Similarly, PSHS/PHSU and PULS/PULU could potentially include the PC in the list of registers pushed or pulled. Currently I just check for this case, remove the PC from the list of registers, and warn the user in this case that it is not fully handled yet.

Indexed addressing poses a challenge: we need to handle an instruction that changes flow of control like JMP 1,X with an arbitrary index addressing mode. It might also produce side effects in the case of instructions like JMP 1,X++. These are handled using a trick: instead of JMP, we run a LEAU instruction with the same indexed operand. Then we examine value of U, which should be the new PC. Currently the code can't handle addressing modes that change the U register like JMP ,U++.

A final challenge is PCR relative index addressing. If we move the instruction to the buffer to execute it, the PC relative address is now wrong. I thought about this, and it should be possible to adjust the offset based on the difference between the original instruction location and the address of the buffer where it will be run. This would get a little complicated, so I didn't implement it (yet). For now I just ignore it and display a message at run time that it is not supported.

After working out most of the logic as pseudocode, I implemented and debugged it. I started with the basic instructions and then added all of the special cases, testing them one at a time. Once done, I tested it with some smaller complete programs.

Finally, I was able to integrate it into the "combined" ROM which also contains the ASSIST09 monitor, disassembler, and Microsoft Basic. I added the trace command as a new ASSIST09 "T" command. It took some shuffling but I was able to just get them all to fit in the 8K ROM.

It hasn't been tested exhaustively, and it can't run BASIC because it uses some PC relative instructions, but it seems to work quite well. Here is some sample output:

>T D000
D000  81 30        CMPA  #$30 
PC=D002 A=FF B=FF X=FFFF Y=FFFF S=FFDF U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D002  25 04        BCS   $D008 
PC=D004 A=FF B=FF X=FFFF Y=FFFF S=FFDF U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D004  81 3C        CMPA  #$3C 
PC=D006 A=FF B=FF X=FFFF Y=FFFF S=FFDF U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D006  25 C0        BCS   $CFC8 
PC=D008 A=FF B=FF X=FFFF Y=FFFF S=FFDF U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D008  30 1F        LEAX  $1F ,X
PC=D00A A=FF B=FF X=FFFE Y=FFFF S=FFDF U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D00A  34 50        PSHS  U,X
PC=D00C A=FF B=FF X=FFFE Y=FFFF S=FFDB U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D00C  0F 41        CLR   $41 
PC=D00E A=FF B=FF X=FFFE Y=FFFF S=FFDB U=FFFF DP=FF CC=11111000 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D00E  CE C0 E7     LDU   #$C0E7 
PC=D011 A=FF B=FF X=FFFE Y=FFFF S=FFDB U=C0E7 DP=FF CC=01111110 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D011  0F 42        CLR   $42 
PC=D013 A=FF B=FF X=FFFE Y=FFFF S=FFDB U=C0E7 DP=FF CC=01111110 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT  
D013  33 4A        LEAU  $0A ,U
PC=D015 A=FF B=FF X=FFFE Y=FFFF S=FFDB U=C0F1 DP=FF CC=01011001 (EFHINZVC)
PRESS TO CONTINUE, TO QUIT 

References

  1. https://github.com/jefftranter/6809/tree/master/sbc/trace
  2. https://github.com/jefftranter/6809/tree/master/sbc/combined
  3. https://github.com/jefftranter/6809/tree/master/sbc/disasm
  4. https://github.com/jefftranter/6502/tree/master/asm/jmon

Friday, January 6, 2017

Building a 68000 Single Board Computer - The TUTOR Monitor

When the 68000 chip was introduced, Motorola offered the MEX68KECB Educational Computer Board (ECB). It included a monitor program called TUTOR. I remember briefly having access to one where I worked back in the mid 1980s when some products were moving to this new processor and staff was becoming familiar with it.

The Teesside TS2, while similar, is a simpler design using static rather than dynamic RAM, and lacks some features like the parallel port and timer (PIT) and cassette tape interfaces. The TS2 was designed to be compatible with the ECB in terms of the memory map for ROM and RAM and serial ports. This allows it to run the TUTOR monitor program.

I was able to find source and binary code for TUTOR here. I ported it to the GNU assembler so that I could modify it if desired.

It is 16KB in size (unlike the TS2 monitor which is about 3Kb) and will fit in the first two 8K EPROMs of the TS2.

I wasn't sure if TUTOR would run as is on my design. The Clements book implied that it should, but did not say so explicitly. After programming the two EEPROMs and inserting them in the board I was pleased to see that it came up and accepted commands.

The Motorola ECB included a parallel printer port and cassette tape interface using the 68230 parallel Interface/Timer (PIT) chip. That chip is not included in the TS2. However, other than commands specific to the printer port and cassette tape, everything else works.

There is a copy of the review of the Motorola ECB from Byte magazine in 1983 here. At US$495 it would be equivalent to about US$1200 today. I believe one of the reasons that the University of Teesside designed their own educational board rather than the ECB was that they could significantly reduce the cost.

The TUTOR monitor is well documented in chapter 3 of the M68000 Educational Computer Board User's Manual. It is quite sophisticated, even including a disassembler and assembler. I'll just cover a few highlights and examples of what it offers.

It provides the following features:

  1. Display and modification of memory as byte, word, longwords, strings, characters, or disassembled instructions.
  2. Display and modification of registers.
  3. Memory fill, move, search, and test functions.
  4. Number conversion between decimal and hexadecimal.
  5. The ability to set and clear breakpoints.
  6. Ability to run programs with breakpoints or line by line tracing.
  7. Output to either of two serial ports, parallel printer port, or cassette tape.
  8. Loading and saving of memory in S record format.
  9. An assembler which allows entering assembly language mnemonics.

Here is a example of displaying memory, first as hex and ASCII data, then as a disassembly:

TUTOR  1.3 > MD 8008 80
008008    60 00 0C B0 41 F8 04 4C  20 3C 00 00 02 0E 42 81  `..0Ax.L <....B.
008018    10 C1 53 80 66 FA 48 7A  00 10 21 DF 00 08 48 7A  .AS.fzHz..!_..Hz
008028    00 12 21 DF 00 0C 4E 75  21 FC 42 55 53 20 00 30  ..!_..Nu!|BUS .0
008038    60 08 21 FC 41 44 44 52  00 30 21 DF 04 CA 21 DF  `.!|ADDR.0!_.J!_
008048    04 CE 21 CF 04 44 4F FA  00 0A 21 CF 04 D6 60 00  .N!O.DOz..!O.V`.
008058    0C 34 61 00 1C 3A 3C FC  0D 0A 30 38 04 CA 61 00  .4a..:<|..08.Ja.
008068    19 48 1C FC 00 20 20 38  04 CC 61 00 19 2E 1C FC  .H.|.  8.La....|
008078    00 20 30 38 04 D0 61 00  19 30 61 00 1B 86 60 00  . 08.Pa..0a...`.

TUTOR  1.3 > MD 8008 80 ;DI
008008    60000CB0             BRA.L   $008CBA 
00800C    41F8044C             LEA.L   $0000044C,A0 
008010    203C0000020E         MOVE.L  #526,D0 
008016    4281                 CLR.L   D1 
008018    10C1                 MOVE.B  D1,(A0)+ 
00801A    5380                 SUBQ.L  #1,D0 
00801C    66FA                 BNE.S   $008018 
00801E    487A0010             PEA.L   $00008030(PC) 
008022    21DF0008             MOVE.L  (A7)+,$00000008 
008026    487A0012             PEA.L   $0000803A(PC) 
00802A    21DF000C             MOVE.L  (A7)+,$0000000C 
00802E    4E75                 RTS      
008030    21FC425553200030     MOVE.L  #1112888096,$00000030 
008038    6008                 BRA.S   $008042 
00803A    21FC414444520030     MOVE.L  #1094992978,$00000030 
008042    21DF04CA             MOVE.L  (A7)+,$000004CA 
008046    21DF04CE             MOVE.L  (A7)+,$000004CE 
00804A    21CF0444             MOVE.L  A7,$00000444 
00804E    4FFA000A             LEA.L   $0000805A(PC),A7 
008052    21CF04D6             MOVE.L  A7,$000004D6 
008056    60000C34             BRA.L   $008C8C 
00805A    61001C3A             BSR.L   $009C96 
00805E    3CFC0D0A             MOVE.W  #3338,(A6)+ 
008062    303804CA             MOVE.W  $000004CA,D0 
008066    61001948             BSR.L   $0099B0 
00806A    1CFC0020             MOVE.B  #32,(A6)+ 
00806E    203804CC             MOVE.L  $000004CC,D0 
008072    6100192E             BSR.L   $0099A2 
008076    1CFC0020             MOVE.B  #32,(A6)+ 
00807A    303804D0             MOVE.W  $000004D0,D0 
00807E    61001930             BSR.L   $0099B0 
008082    61001B86             BSR.L   $009C0A 
008086    600018F6             BRA.L   $00997E 

TUTOR  1.3 > 

The assembler is quite powerful, mostly compatible with Motorola's cross-assembler but lacking support for editing, line numbers, and labels. In pinch, if you could not afford a development system with a cross-compiler, you could use TUTOR's assembler for development and upload the disassembled source and assembled S record file.

Using TUTOR I can easily cross-compile code on a Linux laptop, generate a Motorola hex file, and then transfer it to the TS2 over the serial port.

I'm shortly going to wire up the second 16K of RAM on the board. I can use the memory test command to verify that the new memory is working.

One quirk of TUTOR is that you need to enter all commands in upper case.

Also, some commands can be interrupted by typing BREAK. This is a special serial port sequence and not a character. From minicom it can be sent using F although this doesn't seem to work if you are using a USB to serial convertor.

Overall I see little reason to use the TS2 monitor as TUTOR is much more powerful. The features like breakpoints, tracing, and disassembler make it much easier to debug test programs.

Thursday, January 5, 2017

Building a 68000 Single Board Computer - The TS2 Monitor


The original Teesside TS2 computer included a small machine language monitor program called TS2MON or TSBUG. There is a source listing for it in the book as well as on the included CD-ROM.

As I posted here earlier, I ported the monitor so it could be cross-compiled with the GNU assembler for the 68000. I now have it running on my prototype board. It is a very rudimentary monitor program, running out of ROM, and is a little over 3 Kilobytes in size.

I programmed it into two 27C64 64KB EPROMs. I've also verified that the board works with 28C64 EEPROMs.

The monitor provides twelve commands offering some basic features:

  • Examine and change memory.
  • Display and change registers.
  • Start program execution.
  • Load and save memory though a serial port using Motorola hex (S record) format.
  • Basic support for breakpoints, allow the setting and clearing of breakpoints and program execution to be halted and continued after a breakpoint.

I've documented the commands here. Here are a few examples.

?TSBUG 2 Version 23.07.86
?

Display and change some memory:

?MEM 1000
?
?00001000 0000  1234
?00001002 1234  2345
?00001004 2345  6789
?00001006 0000 -
?00001004 6789 N
?00001006 0000 N
?00001008 0000 

Display registers:

?DISP
?
?  Data reg       Address reg
?0 00000000        00000000
?1 00000000        00000000
?2 00000000        00000000
?3 00000000        00000000
?4 00000000        00000008
?5 00000040        00000000
?6 00000000        00000000
?7 00000000        00000000
?
? SS  =  00000000
? SR  =  2700
? PC  =  00001000

Change a couple of registers:

?REG PC 1000
?00001000
?
?REG D0 12345678
?00000000
?
?DISP
?
?  Data reg       Address reg
?0 12345678        00000000
?1 00000000        00000000
?2 00000000        00000000
?3 00000000        00000000
?4 00000000        00000008
?5 00000040        00000000
?6 00000000        00000000
?7 00000000        00000000
?
? SS  =  00000000
? SR  =  2700
? PC  =  00001000

Dump a range of memory to an S record file:

?DUMP 8000 8080
?
S113800000000800000080084DF80C0042AE004A51
S1138010422E0048422E00496136610005D86100B5
S1138020044E49FA09D06164207C0000C00020108D
S11380300C80524F4D3266044EA800084E714E71AA
S113804042876128614C61000080610000BE60F0DD
S113805041F90001004010BC0003117C0003000141
S113806010BC0015117C001500014E7548E700088E
S113807049FA099C61064CDF10004E752F00101C54
S10480806794
S9

The code was designed to be simple and readable. Despite its simplicity, it does have some more advanced features. It uses device control blocks (DCBs) in RAM to allow modifying the device input/output routines to redirect them. It can also be extended by code in the second set of ROMs to add more commands.



I've now wired up the second 6850 UART chip. The board has two serial ports. The rationale at the time was that users would typically have a dumb serial terminal connected to one port to use as a console, and the other port would connect to a development system computer for uploading or downloading programs. The TSMON LOAD and DUMP commands use the second serial port for this reason.



One of the simplifications in my design is to use an FTDI USB to serial (TTL-level) converter for the serial ports, avoiding the need for some additional chips and +/- 12 volt power supplies, and allowing it to be connected to a USB port. You can also power the board from USB if desired.

Typical usage today would be to connect to one computer using a terminal emulator (I'm using a laptop running Ubuntu Linux and use the minicom program). In that case it is probably more convenient to use only one serial port both as a console and for file transfers. While the monitor source code could be modified to use the monitor serial port for LOAD and DUMP, you can patch the DCB in RAM to direct the commands to use the console port rather than the auxiliary port. It is simply a matter of changing two words in the DCB. Addresses $00000D0E and $00000D26 need to be changed from $0041 to $0040. This needs to be done each time monitor is entered, i.e. after a reset.

Having done that, I can upload an S record file from my Linux laptop to the TS2 by cating the file to /dev/ttyUSB0 after running a monitor LOAD command. You can then run the program from the monitor. A simple test program can be found in git here.

In a future blog post I'll cover a more sophisticated monitor program, the TUTOR software, which was developed by Motorola for the 68000 Educational Computer Board (ECB), but also runs on the TS2 since it was designed to have a memory map compatible with the ECB.

Tuesday, May 13, 2014

Apple II Monitor Running on Briel Replica 1

As a followup to my previous blog post, here is a transcript of running some Apple II Monitor commands on the Briel Replica 1. You can find documentation on the Monitor commands in a number of places, including here. The commands typed by the user are in bold.


Monitor prompt:

*

Dump memory:

*1000.100F
1000- A2 10 EA CA D0 FA 60 BE
1008- 00 00 4A 83 00 00 75 D7

Change memory:

*1000:01 02 03

*1000.100F
1000- 01 02 03 CA D0 FA 60 BE
1008- 00 00 4A 83 00 00 75 D7

Move Memory:

*1000<2000 .2fffm="" b="">

Verify Memory:

*1000<2000 .3000v="" b="">
3000-FF (00)

Disassemble:

*FF00L
FF00-   D8          CLD   
FF01-   58          CLI   
FF02-   A0 7F       LDY   #$7F
FF04-   8C 12 D0    STY   $D012
FF07-   A9 A7       LDA   #$A7
FF09-   8D 11 D0    STA   $D011
FF0C-   8D 13 D0    STA   $D013
FF0F-   C9 DF       CMP   #$DF
FF11-   F0 13       BEQ   $FF26
FF13-   C9 9B       CMP   #$9B
FF15-   F0 03       BEQ   $FF1A
FF17-   C8          INY   
FF18-   10 0F       BPL   $FF29
FF1A-   A9 DC       LDA   #$DC
FF1C-   20 EF FF    JSR   $FFEF
FF1F-   A9 8D       LDA   #$8D
FF21-   20 EF FF    JSR   $FFEF
FF24-   A0 01       LDY   #$01
FF26-   88          DEY   
FF27-   30 F6       BMI   $FF1F

Mini-Assembler:

*7666G

!1000:LDX #$10
1000-   A2 10       LDX   #$10
! NOP
1002-   EA          NOP   
! DEX
1003-   CA          DEX   
! BNE 1000
1004-   D0 FA       BNE   $1000
! RTS
1006-   60          RTS   

Call Monitor to Disassemble:

!$1000L
1000-   A2 10       LDX   #$10
1002-   EA          NOP   
1003-   CA          DEX   
1004-   D0 FA       BNE   $1000
1006-   60          RTS   
1007-   BE 00 00    LDX   $0000,Y
100A-   4A          LSR   
100B-   83          ???   
100C-   00          BRK   
100D-   00          BRK   
100E-   75 D7       ADC   $D7,X
1010-   00          BRK   
1011-   00          BRK   
1012-   F8          SED   
1013-   87          ???   
1014-   00          BRK   
1015-   00          BRK   
1016-   B5 F6       LDA   $F6,X
1018-   42          ???   
1019-   00          BRK   

Go back to Monitor:

!$7F65G

Single step:

*1000S
1000-   A2 10       LDX   #$10
 A=10 X=10 Y=7D P=70 S=CA
*S
1002-   EA          NOP   
 A=10 X=10 Y=7D P=70 S=CA
*S
1003-   CA          DEX   
 A=10 X=0F Y=7D P=70 S=CA
*S
1004-   D0 FA       BNE   $1000
 A=10 X=0F Y=7D P=70 S=CA
*S
1000-   A2 10       LDX   #$10
 A=10 X=10 Y=7D P=70 S=CA
*

Display 6502 Registers:

*^E
 A=10 X=10 Y=7D P=70 S=CA

Hex arithmetic:

*12+34
=46
*FE-12
=EC

Go to BASIC:

*^B
>LIST

Sunday, May 11, 2014

Apple II Monitor Ported to Apple 1

As announced here,  a cassette tape was found that contains a port of the Apple II Monitor to the Apple 1. It was done by Winston Gayler. Additional work was done by Wendell Sander, who posted documentation, cassette tape sound files and Woz Mon binaries here .

I've tested the code on a Briel Replica 1 and it works quite well. The only issue I found on the Replica 1 is that the commands that require Control keys do not work as the Replica 1 does not emulate Control keys when using a PS/2 keyboard. They will work if entered from the serial port.

This weekend I went a little further adapted the original monitor source from the "Red Book" to build under the CA65 assembler, then applied the changes for the Apple 1. The result is code that can be assembled from source and easily relocated.

References:

  1. www.apple1notes.com/old_apple/Monitor_II_on_1.html
  2. www.applefritter.com/content/apple-ii-monitor-ported-apple-1
  3. github.com/jefftranter/6502/tree/master/asm/Apple%5D%5BMonitor


Monday, July 9, 2012

Implementing A Mini Assembler


One of the features missing from JMON was a "mini assembler" like the one included in the Apple II computers.

I implemented one with roughly the same features and limitations as the one in the Apple II, i.e. it assembles simple 6502 assembly language code where all numeric values are in hex and there is no support for symbols or labels.

It is very handy for writing short assembly language programs where you don't want to fire up a cross-assembler or even Krusader.

In conjunction with the disassembler you can verify the program you entered and then run it.

The code leveraged the data tables in the JMON disassembler. Most of the work is parsing the entered code to validate it and determine the addressing mode.

While I only implemented 6502 support in this first version, because it uses the tables from my disassembler, it does accept 65C02 and even 65816 instructions that use the standard 6502 addressing modes. It just doesn't yet understand the new addressing modes for the 65C02 or 65816.

A sample session is shown below, where the user entered text is in bold.

? A 6F00
6F00: CLD
6F01: CLI
6F02: LDY #7F
6F04: STY D012
6F07: LDA #A7
6F09: STA D011
6F0C: STA D013
6F0F: LDA #5C
6F11: JSR 6FEF
6F14: JSR 6F1B
6F17: BCC 6F0F
6F19: BCS 6F14
6F1B: JSR 6EE5
6F1E: LDY #01
6F20: DEY
6F21: BMI 6F1B
6F23: JSR 6EBE
6F26: STA 0200,Y
6F29: CMP #0D
6F2B: BEQ 6F38
6F2D: CMP #5F
6F2F: BEQ 6F20
6F31: CMP #1B
6F33:

It provides meaningful error messages and checks the validity of the code. Below are some error messages:

6000: LDA #1234
INVALID OPERAND
6000: LDA (1234)
INVALID ADDRESSING MODE
6000: BNE 7000
RELATIVE BRANCH OUT OF RANGE
6000: LDB
INVALID INSTRUCTION

I tested it as I built up the code, but the final test was to disassemble about a thousand lines of JMON code and then feed that back to the assembler and confirm that it accepted it and generated the same code.

I'll probably add support for the rest of the 65C02 instructions in future and maybe also the 65816.

As always, the code is available here.