Implementing the ZX-Badaloc Clone into an FPGA
Switches / buttons / Encoder usage
The project includes a PicoBlaze processor which handles the LCD display, the Encoder knob, some of the switch/buttons and leds. Z80 speed can be adjusted on-the-fly by turning the encoder knob from 42MHz down to one instruction every two seconds, with address and opcodes displayed on the LCD.
NORTH: FPGA reset
EAST: Z80 reset
SOUTH: Z80 NMI. Pressed twice, enters the bootrom main menu.
WEST: Single-step, Breakpoint enable
Disables SPI Flash boot (see below)
SW1: Enters the BreakPoint address editor (see below)
SW2: Adds a 1-second delay after sd-card snapshot restore
SW3: Not used
ENCODER: See 'PicoBlaze-controlled Functions' below
SW0 (rightmost): when turned ON, disables the SPI Flash boot attempt of the tiny bootloader. Useful for issuing RS-232 commands to the tiny bootloader when a ROM is already programmed into the SPI Flash but we don't want it to be loaded.
The LCD displays many useful information about the clone state:
content of registers $7FFD, $1FFD, $24DF, $34DF, $54DF, $64DF (see
the registers page for
Second row: current Z80 Address bus, Data bus, operation performed (m = memory, i = I/O, r = read, w = write), Z80 clock speed. These are slowed down but still unreadable when the processor runs at normal speeds. The clock speed is preceeded by an asterisk '*' if the INT frequency is also doubled to 100Hz instead of 50.
The Encoder allows on-the-fly Z80 clock setting. Rotate it clockwise to increase the speed (up to 42MHz / 100Hz interrupt). Rotate it counterclockwise to slow down the machine.
When the clock speed reaches the minimum allowed (3.5MHz) and the encoder is further rotated, the 24-bit PRESCALER MODE is entered. This amazing function will suppress a certain number of clock cycles every time the Z80 terminates a memory or I/O access. Turning the encoder 'fills-up' the 24 bit prescaler register (in 24 steps) from 000000 to FFFFFF. For example, 00000F means that 15 clock cycles will be suppressed. Hence, every step in the encoder setup will double the slowing factor. The slowest setting (7FFFFF) is so slow that the Z80 address and data bus are human readable on the LCD display (about two seconds per cycle).
Pressing the encoder toggles between Frequency / Prescaler mode setting: it can be used to quickly exit prescaler / single-step mode.
Since the processor is halted exactly after the END of any memory or I/O access, the display will show instruction's opcode fetch followed by any memory or I/O operation involved in that instruction execution. Below the slowest setting, the last possible value is FFFFFF. This is the single-step mode.
Single Step mode:
When the prescaler is set to FFFFFF (slowest possible Z80 speed), the processor is completely halted and the single-step mode is entered. Pressing the WEST BUTTON will advance to the next memory or I/O access, which will be shown on the LCD display. If the led advances, then it was an opcode fetch.
For example, this is what you will see on the LCD display if you single-step (or slow animate) the very first LDIR loop of the bootloader firmware (see the source code) by simply setting the prescaler slow enough then pressing the Z80 reset button (EAST). This loop copies the ROM content to video ram:
= Read memory at address 000A, ED
000B B0mr = Read memory at address 000B, B0 (ldir opcode fetch)
000F 01mr = Read memory (data to be copied from address 000F, source pointed by HL), 01 is read
4E2F 01mw = Write memory to address 4E2F (destination pointed by DE)
000A EDmr = Read memory at address 000A, ED (the cycle repeats until BC reaches 0000)
The rightmost led LD0 indicates that CONTEXT_SWITCH is active. This means that the BootRom firmware is active instead of any other rom that might be in use. This occurs at power-on (because the main menu' resides into the BootRom) or when any clone-specific operation is being carried out, such as snapshots, serial communication (which is NMI-based) and so on.
All other leds LD1 through LD7 will continuously display a running point which is proportional to the Z80 execution speed. A complete turn (8 steps, even if the LED0 will not light) takes exactly 500.000 Z80 instructions. Note that the counter is based on M1 and multibyte instructions will activate it on every opcode byte, so the response is a little higher than real instruction's execution speed. On the slowest prescaler settings (0FFFFF to FFFFFF) the led will advance on every single opcode fetch, since the other way is completely useless at these speeds.
From FPGA V1.30, the picoblaze can set two types of BreakPoints. Pressing the WEST BUTTON while single-step is not active will cycle between them.
NMI BreakPoint: When breakpoint address is matched, an NMI is issued and breakpoint mode is disabled. It's main purpose is entering the bootrom (which is the normal reaction to NMI) just at the end of a Tape Loading, so that a perfect snapshot could be saved on sd-card. When active, the display shows 'Bpn! xxxx' where xxxx = breakpoint address.
Single-Step breakpoint: When breakpoint address is matched, single-step mode is entered and the display will show the address and instruction fetched at breakpoint location. The machine can then be (as always) single-stepped or gradually speeded-up by rotating the encoder clockwise. Pressing the encoder resumes normal clock operation. Note that activating this type of breakpoint will set the Z80 clock to 3.5MHz or 7MHz / 100Hz, because single-step can only work at these speeds. When active, the display shows 'Bpp! xxxx' where xxxx = breakpoint address.
Every time the WEST BUTTON is pressed, the breakpoint mode is cycled between NMI, S-STEP and no breakpoint. Note that NMI breakpoint can't be enabled when bootrom firmware is already in execution. This prevents accidental triggering by the NMI service routines. When bootrom is active, the button will cycle between S-Step and no breakpoint only.
Setting the Breakpoint Address: Switching on SW1 enables the BreakPoint editor. The power-on default $05E2 address (which is the end of the 16/48K ROM Tap Loading routine) can be modified one nibble at a time by rotating the encoder knob. A cursor indicates the nibble being edited. Pressing the encoder knob advances to the next nibble, with wrap around.
Back to Index