ZX-Badaloc     Reloaded

Implementing the ZX-Badaloc Clone into an FPGA

Z80-accessible I/O registers implemented in current release


ZX-Spectrum standard registers:

$FE (254): Keyboard / Tape / Speaker / Border color

D7        Always '1'
D6        Tape Ear in
D5        Always '1'
D4:D0     Fully functional Keyboard from PS/2 data

D4        Speaker out
D3        Tape Mic out
D2:D0     Border Color


$1FFD (8189): ZX-Spectrum 128K +2A / +3 special mode register

D2:D0     Read back written data
D3        West Button
D7:D4     SW3:SW0

D0        Paging mode. 0 = normal; 1 = +2A/+3 special paging
D3        disk motor (not implemented)
D4        printer strobe (not implemented)

Normal mode (D0 = '0'):
D1        Ignored
D2        High bit (A15) of rom_bank

Special mode (D0 = '1'):
D2:D1     Selects a paging mode out of four possible (see the +3 documentation)


$7FFD (32765): ZX-Spectrum 128K Memory Control

Read / Write:
D5        1FFD / 7FFD Registers Lock: '1' = Locked (no further write access allowed)
D4        low bit (A14) of rom bank
D3        Video Bank select
D2:D0     128K Ram Bank Select


ZX-Badaloc Custom Registers:

$0F (15): DMX / RDM control register: see DMX page for details

$1F (31): Kempston Joystick and SD-Card chip select

D7:D0        8 bit Kempston Joystick out of 16 inputs provided by 74HC166 interface. LSB or MSB bank selectable (see below)

D7:D4        If = '1010' the Kempston port will read the 8 MSB bits instead of the LSB (default)
              If = '1011' the Programmable Joystick registers are write-enabled in memory (32 bytes)
D1:D0        SPI Chip select enable: "10" = sd_card 1, "01" = sd_card 2, "00" = onboard M25P16 Flash chip select, "11" all disabled
The first sd-card slot has been installed and successfully tested


$3F (63): SPI Interface Data Register

Read: 8 bit from selected SPI device (see $1F register)
Write: 8 bit to selected SPI device (see $1F register)

$5F (95): NMI Enable on RS-232 reception, RS-232 Status Register

D7:D4     Always read "0000"
D3        rs-232 TX Status: '0' = idle, '1' = register full (tx in progress)
D2        rs-232 Framing Error: '1' = Error
D1        rs-232 Overrun Error: '1' = Error
D0        rs-232 RX Status: '1' = Data is Available for read on port $7F

D7:D1     Not used
D0        NMI Enable when rs-232 data is received: '1' = Enabled


$7F (127): RS-232 (Female DB9 Connector) Data Registers

Read: 8 bit RS-232 RX Register
Write: 8 bit RS-232 TX Register


$24DF (9439): Rom Bank / Z80 Clock Select

Read / Write:
D7:D6     ZX-Badaloc shadow ram rd/wr control: meaningless on this FPGA implementation: not implemented
D5:D3     ZX-Badaloc high rom bank address select (A18:A16) - A15 and A14 come from 1FFD and 7FFD standard registers
           32 rom banks (16K each) can be selected into the 0-3FFF memory area combining these 5 bits.
D2        Z80 Clock / Screen / INT Doubler: '1' = Z80 Clock *2, INT = 100Hz, VGA 100 Hz instead of 50Hz
D1:D0     Z80 Clock Select: "00" = 3.54MHz; "01" = 7.08MHz; "10" = 14.16MHz; "11" = 21.25MHz


$34DF (13535): Various ZX-Badaloc control flags

Read / Write:
D7        Fastpage address space (see fastpage register): '0' = 0-$3FFF (standard); '1' = $C000-$FFFF (new in this FPGA version)
D6        Custom Registers Lock bit: '1' = Locked
D5        Context Switch inibith: '1' = no context switch takes place on $66 (NMI Vector) opcode fetch (see ZX-Badaloc documentation)
D4        Parallel Flash Write Enable (parallel flash is not used on this clone)
D3        Writing '1' Removes Context Switch. Always read as '0'
D2        Writing '1' Forces a Context Switch. Always read as '0'
D1        Further Z80 INT Frequency Doubler: '1' = Active (50 -> 100Hz or 100 -> 200Hz depending on D2 of $24DF register)
D0        Spectrum Type: '0' = 48K; '1' = 128K (Video Timings)

NOTE: The context switch is a special ZX-Badaloc feature which swaps-in a custom ROM when an NMI is being serviced (opcode fetch at address $66). This enables the RS-232 or sd-card snapshots and other special features.


$44DF (17631): Custom Register Lock Disable and FPGA BootLoader Swap Out

Writing $AA (170) resets bit D6 of $34DF register, reactivating WR access to all Custom registers.
It also disables forever the VHDL-Coded Z80 bootloader rom from address space 0 - $3FFF and activates the standard memory (for operating mode).


$54DF (21727): FASTPAGE control register

Read / Write:
D7        Paged-in memory Write Enable: '1' = enabled. When 'RAM' type is paged, writing is always enabled
D6        Page-in enable: when '1', the selected 16K memory block will appear in address space 0-$3FFF (required by ResiDOS)
D5        RAM/ROM select: '0' = RAM is paged; '1' = ROM is paged. Only meaningful on the original zx-badaloc clone, see notes
D4:D0     Bank Select: one 16K bank out of 32 (512K) can be selected for paging by these 5 bits.

NOTE: As stated above, the FPGA version of the clone does not have any static ram nor rom chip. Every 16K bank comes from the DDR memory. Hence, this register controls the access to a 1MB memory space which can be paged-in, combining the original zx-badaloc 512K of RAM and 512K of ROM. In other words, the D5 bit is just one more bank select address bit (so 64 banks = 1MB can be accessed).

For compatibility reason, however, these consideration might be taken into account:
When the clone operates normally (D6 = '0' = fastpage is not enabled) the DDR acts as the main memory for both 'ROM' and 'RAM'. Up to 512K of 'ROM' can be accessed in the 0-$3FFF area by combining A18:A16 from $24DF (nonstandard) register and A15, A14 from $1FFD and $7FFD registers respectively (this allows 128K and +2 / +3 machines to run because rom selection works as on the original hardware). The HARD-CODED half of the 512K block of DDR will be the UPPER ONE, so if the user wants to alter a ROM content on the fly by using the fastpage access, D5 should be '1'.

The other 512K space (the lower half of the megabyte) is used as RAM memory. The first 128K will be mapped as in the 128K spectrum and can be accessed using the RAM Bank bits in the standard $7FFD register, while the remainder is for general purpose and can only be accessed through fastpage register. ResiDOS by Garry Lancaster uses fastpaging to access the entire 512K RAM area and requires D5 to be low. If the user wants to alter a memory bank which will reflect to RAM through fastpaging, the D5 bit should be '0'.


$64DF (25823): DDR MSB address bank (was "HI-RES on the original zx-badaloc)

Read / Write:
D7:D6     Not used
D5:D0     Upper memory address select: Up to 64 blocks (1 megabyte each) can be selected by this register.

This is an MSB extension of the FASTPAGE register. When fastpaging is enabled, these additional 6 bits provide access to the entire 64MB DDR space.


Memory Mapped Registers:

When D7:D4 in $1F register are equal to '1011' (Programmable Joystick Write Enable), 32 bytes of key-map data for the 16 joystick inputs can be written in memory at any 32 bytes boudary. Only A4:A0 are tested, so any memory write will also store data in the joystick registers. Hence, it is possible to write 'over' a ram array (to keep a copy of stored data) or write on a 'ROM' area, to avoid corrupting ram content.

Each joystick input has a pair of data bytes:

Byte 0    ZX-Spectrum keyboard eight COLUMNS (on Z80 Address lines): D7:D0 = A15:A8. A bit SET means address column PRESSED
Byte 1    ZX-Spectrum keyboard five ROWS, readable on $FE port: D4:D0 = D4:D0. A bit SET means key PRESSED with the COLUMN byte

First pair of bytes stores keymap data for Joystick Input 1; second pair is for joy input 2 and so on.

It is imperative to perform joystick programming with interrupts disabled and in pure assembly, to avoid any undesired write operation which would certainly corrupt joystick setting.


Back to Index