Table of Contents
- Overview
- User Commands
- AVR Ports
- Hardware Commands
- Breakpoint Register
- Address/Dout Register
- Data Multiplexer
- Target Specific Code
Overview
The firmware for each of targets (6502/Z80/6809) is built from the same source file: https://github.com/hoglet67/AtomBusMon/blob/master/firmware/AtomBusMon.c
There is some use of conditional compilation described in Compiling-firmware#target-specific-customizations
The main() method in the firmware implements a infinite command processing loop:
- Reads a command line from serial input
- Parses the command line into a user command and parameters
- Calls the user command implementation
User Commands
The user command implementations are all prefixed by doCmd:
- doCmdBreakI
- doCmdBreakRdIO
- doCmdBreakRdMem
- doCmdBreakWrIO
- doCmdBreakWrMem
- doCmdClear
- doCmdContinue
- doCmdCrc
- doCmdDis
- doCmdFill
- doCmdHelp
- doCmdIO
- doCmdList
- doCmdMem
- doCmdReadIO
- doCmdReadMem
- doCmdRegs
- doCmdReset
- doCmdStep
- doCmdTest
- doCmdTrace
- doCmdTrigger
- doCmdWatchI
- doCmdWatchRdIO
- doCmdWatchRdMem
- doCmdWatchWrIO
- doCmdWatchWrMem
- doCmdWriteIO
- doCmdWriteMem
AVR Ports
The firmware uses the following AVR Ports to interact with the Bus Monitor hardware:
Port | Bit Range | Direction | Function |
---|---|---|---|
A | 7..4 | In/Out | HD44780 LCD data |
A | 3 | unused | |
A | 2 | Output | HD44780 LCD enable |
A | 1 | Output | HD44780 LCD read/notWrite |
A | 0 | Output | HD44780 LCD register select |
B | 7..6 | unused | |
B | 5 | Output | Hardware command edge |
B | 4..0 | Output | Hardware command data |
C | 7..0 | unused | |
D | 7 | Input | Event FIFO empty flag |
D | 6 | Input | Interrupt switch (GODIL SW1) |
D | 5..0 | Output | Multiplexor select |
E | 7..0 | Input | Multiplexor data |
F | 7..0 | unused |
Note: The functionality for the HD44780 LCD is currently disabled in the VHDL projects, and #ifdefed out in the C source.
Hardware Commands
The operation of the bus monitor hardware is controlled through a command interface AVR PortB.
Command | Param | Description | |
---|---|---|---|
0x00 | CMD_SINGLE | 0 | Disable single stepping |
0x01 | CMD_SINGLE | 1 | Enable single stepping |
0x02 | CMD_BRKPT | 0 | Disable breakpoints (and watchpoints) |
0x03 | CMD_BRKPT | 1 | Enable breakpoints (and watchpoints) |
0x04 | CMD_LOAD_BRKPT | 0 | Shift a zero into the breakpoint register |
0x05 | CMD_LOAD_BRKPT | 1 | Shift a one into the breakpoint register |
0x06 | CMD_RESET | 0 | Release reset on the target processor |
0x07 | CMD_RESET | 1 | Assert reset on the target processor |
0x08 | CMD_STEP | Single Step target processor on instruction | |
0x09 | CMD_WATCH_READ | Read Event FIFO | |
0x0A | CMD_FIFO_RST | Reset Event FIFO | |
0x0B | unused | ||
0x0C | CMD_LOAD_MEM | 0 | Shift a zero into the address/data register |
0x0D | CMD_LOAD_MEM | 1 | Shift a one into the address/data register |
0x0E-0x0F | unused | ||
0x10 | CMD_RD_MEM | Read memory | |
0x11 | CMD_RD_MEM_INC | Read memory and increment address register | |
0x12 | CMD_WR_MEM | Write memory | |
0x13 | CMD_WR_MEM_INC | Write memory and increment address register | |
0x14 | CMD_RD_IO | Read IO | |
0x15 | CMD_RD_IO_INC | Read IO and increment address register | |
0x16 | CMD_WR_IO | Write IO | |
0x17 | CMD_WR_IO_INC | Write IO and increment address register | |
0x18-0x1F | unused |
Breakpoint Register
Much of the power of the emulator comes from the ability to set breakpoints and watchpoints. These only active when the emulator is in running mode, not when single stepping. They are controlled via a set of registers collectively called the breakpoint register.
The firmware maintains the state of the breakpoints locally in memory, and then loads these serially into the hardware's breakpoint register just prior to entering the running state (as part of the continue command).
The break point register has the following structure:
The number of entries in the breakpoint register 8 for the 6502 and 6809, and 4 for the Z80, as the Z80 processor core is larger, so there is less space in the FPGA. Each entry in the breakpoint register is 46 bits wide. So for the 6502, the size of the register is 46 x 8 = 368 bits.
To load the breakpoint register, data is shifted in one bit at a time by making multiple calls to the CMD_BRKPT_LOAD command (with the data bit value to be loaded in command bit zero). Each time the command is used, the register is shifted right one bit and the new data bit is placed in the most significant bit. This means the order of the bits beings sent is bit 0 first and bit 367 last.
Address/Dout Register
The Address/Dout register is used by commands that read or write host memory when the emulator is in command mode
This is a 24 bit register, where:
- bits 23..8 are the address (for reads and writes)
- bits 7..0 are the data (for writes only, for reads the data is accessed via the multiplexer, see below)
To load the Address/Dout register, data is shifted in one bit at a time by making multiple calls to the CMD_LOAD_MEM command (with the data bit value to be loaded in command bit zero). Each time the command is used, the register is shifted right one bit and the new data bit is placed in the most significant bit. This means the order of the bits beings sent is bit 0 first and bit 23 last.
Data Multiplexer
State from the bus monitor hardware can be read by via an 8-bit wide 64-to-1 multiplexer. The select input is set by writing a value (0 to 63) to Port D, and the 8-bit value can then be read back from Port E.
Select | Value |
---|---|
0 | Latched instruction address (7:0) |
1 | Latched instruction address (15:8) |
2 | Latched data bus value |
3 | Current cycle count (23..16) |
4 | Current cycle count (7..0) |
5 | Current cycle count (15..8) |
6 | Event instruction address (7:0) |
7 | Event instruction address (15:8) |
8 | Event address (7:0) |
9 | Event address (15:8) |
10 | Event data bus value |
11 | Event status |
12 | Event cycle count (7:0) |
13 | Event cycle count (15:8) |
14 | Event cycle count (23:16) |
15-31 | unused |
32..63 | processor registers (see below) |
When the emulator is stopped (or single stepping), the current values of the address, data and cycle count are in slots 0 through to 6.
When the emulator is running and a breakpoint or watchpoint is triggered, the address, data, cycle count and status are written to the Event FIFO.
The AVR periodically checks for events by looking at the state of the Event FIFO empty flag (AVR Port D bit 7). If the FIFO is not empty, the head event can be accessed a byte at a time via slots 7 through to 14 in the multiplexor (AVR Ports D and E). Once the event has been logged, the CMD_WATCH_READ causes the event to be discarded.
Target Specific Code
Code that is specific to a target processor is factored out into separate files. This is really just two things:
- An opcode disassembler
- A register formatter
Opcode Disassembler
This reads the opcode from host memory and formats it for printing.
The prototype for this is:
unsigned int disassemble(unsigned int addr);
The return value is the address of the next opcode.
For the 6502, the implementation is:
For the Z80, the implementation is:
For the 6809, the implementation is:
Register formatter
This reads the register data via the wide multiplexer described above.
The prototype for this is:
void doCmdRegs(char *params);
i.e. is entire implementation of the regs command.
For the 6502, the implementation is:
For the Z80, the implementation is:
For the 6809, the implementation is:
GODIL Hardware (now obsolete)
XC6SLX9 Mini Board (eepizza)
Tutorials:
User Manual
Hardware design notes
Software design notes