diff --git a/data/nextreg.txt b/data/nextreg.txt
new file mode 100644
index 0000000..2c18c2f
--- /dev/null
+++ b/data/nextreg.txt
@@ -0,0 +1,1232 @@
+
+0x00 (00) => Machine ID
+(R)
+ 0000 1000 = EMULATORS
+
+ 0000 1010 = ZX Spectrum Next
+ 1111 1010 = ZX Spectrum Next Anti-brick
+
+ 1001 1010 = ZX Spectrum Next Core on UnAmiga Reloaded
+ 1010 1010 = ZX Spectrum Next Core on UnAmiga
+ 1011 1010 = ZX Spectrum Next Core on SiDi
+ 1100 1010 = ZX Spectrum Next Core on MIST
+ 1101 1010 = ZX Spectrum Next Core on MiSTer
+ 1110 1010 = ZX Spectrum Next Core on ZX-DOS
+
+0x01 (01) => Core Version
+(R)
+ bits 7:4 = Major version number
+ bits 3:0 = Minor version number
+ (see register 0x0E for sub minor version number)
+
+0x02 (02) => Reset
+(R)
+ bit 7 = 1 if the reset signal to the expansion bus and esp is asserted
+ bits 6:5 = Reserved
+ bit 4 = 1 if multiface nmi was generated by an i/o trap (experimental, see nextreg 0xda)
+ bit 3 = 1 if multiface nmi was generated by this nextreg
+ bit 2 = 1 if divmmc nmi was generated by this nextreg
+ bit 1 = 1 if the last reset was a hard reset
+ bit 0 = 1 if the last reset was a soft reset
+ * Only one of bits 1:0 will be set
+(W)
+ bit 7 = Assert and hold reset to the expansion bus and the esp wifi (hard reset = 0)
+ bits 6:5 = Reserved must be zero
+ bit 4 = Clear i/o trap (write zero to clear) (experimental) **
+ bit 3 = Generate multiface nmi (write zero to clear) **
+ bit 2 = Generate divmmc nmi (write zero to clear) **
+ bit 1 = Generate a hard reset (reboot) *
+ bit 0 = Generate a soft reset *
+ * Hard reset has precedence
+ ** These signals are ignored if the multiface, divmmc, dma or external nmi master is active
+ ** Copper cannot clear these bits
+ ** An i/o trap could occur at the same time as mf / divmmc cause; always check this bit in nmi isr if important
+
+0x03 (03) => Machine Type
+(R)
+ bit 7 = nextreg 0x44 second byte indicator
+ bits 6:4 = Display timing
+ bit 3 = User lock on display timing applied
+ bits 2-0 = Machine type
+(W)
+ A write to this register disables the bootrom
+ bit 7 = 1 to allow changes to bits 6:4
+ bits 6:4 = Selects display timing
+ affects port decoding and contention
+ 000 = Internal Use
+ 001 = ZX 48K display timing
+ 010 = ZX 128K/+2 display timing
+ 011 = ZX +2A/+2B/+3 display timing
+ 100 = Pentagon display timing (changes to 50 Hz)
+ bit 3 = 1 to toggle user lock on display timing (hard reset = 0)
+ bits 2:0 = Selects machine type (config mode only)
+ determines roms loaded
+ 000 = Configuration mode
+ 001 = ZX 48K
+ 010 = ZX 128K/+2
+ 011 = ZX +2A/+2B/+3
+ 100 = Pentagon
+
+0x04 (04) => Config Mapping (config mode only, bootrom disabled)
+(W)
+ bit 7 = Reserved, must be 0
+ bits 6:0 = 16K SRAM bank mapped to 0x0000-0x3FFF (hard reset = 0)
+** Even multiplies of 256K are unreliable if storing data in sram for the next core started.
+
+0x05 (05) => Peripheral 1 Setting
+(R/W)
+ bits 7:6 = Joystick 1 mode (LSB)
+ bits 5:4 = Joystick 2 mode (LSB)
+ bit 3 = Joystick 1 mode (MSB)
+ bit 2 = 50/60 Hz mode (0 = 50Hz, 1 = 60Hz, Pentagon forces 50Hz)
+ bit 1 = Joystick 2 mode (MSB)
+ bit 0 = Enable scandoubler (1 = enabled for vga, 0 for crt)
+Joystick modes:
+ 000 = Sinclair 2 (12345)
+ 001 = Kempston 1 (port 0x1F)
+ 010 = Cursor (56780)
+ 011 = Sinclair 1 (67890)
+ 100 = Kempston 2 (port 0x37)
+ 101 = MD 1 (3 or 6 button joystick port 0x1F)
+ 110 = MD 2 (3 or 6 button joystick port 0x37)
+ 111 = User Defined Keys Joystick
+* Joysticks can be placed in i/o mode via nextreg 0x0B.
+* Programming the user defined keys joystick is done through the ps2 keymap interface
+on nextreg 0x28, 0x29 and 0x2B:
+1. Write 128 to nextreg 0x28
+2. Write 0 (left joystick) or 16 (right joystick) to nextreg 0x29
+3. Write twelve bytes to nextreg 0x2B in order. The bytes correspond to the twelve
+buttons on an md pad (MODE=11 X Z Y START A C B U D L R=0)
+4. Each byte written identifies a key in the 8x7 membrane; bits 5:3 select the row
+and bits 2:0 select the column with 111 meaning no action
+* In kempston and md modes, excess buttons on a controller not read via ports will
+generate key input if so programmed
+
+0x06 (06) => Peripheral 2 Setting
+(R/W)
+ bit 7 = Enable F8 cpu speed hotkey and F5/F6 expansion bus hotkeys (soft reset = 1)
+ bit 6 = Divert BEEP only to internal speaker (hard reset = 0)
+ bit 5 = Enable F3 50/60 Hz hotkey (soft reset = 1)
+ bit 4 = Enable divmmc nmi by DRIVE button (hard reset = 0)
+ bit 3 = Enable multiface nmi by M1 button (hard reset = 0)
+ bit 2 = PS/2 mode (0 = keyboard primary, 1 = mouse primary; config mode only)
+ bits 1-0 = Audio chip mode (00 = YM, 01 = AY, 10 = ZXN-8950, 11 = Hold all AY in reset)
+
+0x07 (07) => CPU Speed
+(R)
+ bits 7:6 = Reserved
+ bits 5:4 = Current actual cpu speed
+ bits 3:2 = Reserved
+ bits 1:0 = Programmed cpu speed
+(W)
+ bits 7:2 = Reserved, must be 0
+ bits 1:0 = Set cpu speed (soft reset = 00)
+ 00 = 3.5 MHz
+ 01 = 7 MHz
+ 10 = 14 MHz
+ 11 = 28 MHz
+
+0x08 (08) => Peripheral 3 Setting
+(R/W)
+ bit 7 = Unlock port 0x7ffd (read 1 indicates port 0x7ffd is not locked)
+ bit 6 = Disable ram and port contention (soft reset = 0)
+ bit 5 = AY stereo mode (0 = ABC, 1 = ACB) (hard reset = 0)
+ bit 4 = Enable internal speaker (hard reset = 1)
+ bit 3 = Enable 8-bit DACs (A,B,C,D) (hard reset = 0)
+ bit 2 = Enable port 0xff Timex video mode read (hides floating bus on 0xff) (hard reset = 0)
+ bit 1 = Enable turbosound (currently selected AY is frozen when disabled) (hard reset = 0)
+ bit 0 = Implement issue 2 keyboard (hard reset = 0)
+
+0x09 (09) => Peripheral 4 Setting
+(R/W)
+ bit 7 = Place AY 2 in mono mode (hard reset = 0)
+ bit 6 = Place AY 1 in mono mode (hard reset = 0)
+ bit 5 = Place AY 0 in mono mode (hard reset = 0)
+ bit 4 = Sprite id lockstep (nextreg 0x34 and port 0x303B are in lockstep) (soft reset = 0)
+ bit 3 = Reset divmmc mapram bit (port 0xe3 bit 6) (read returns 0)
+ bit 2 = 1 to silence hdmi audio (hard reset = 0)
+ bits 1:0 = Scanline weight
+ 00 = scanlines off
+ 01 = scanlines 50%
+ 10 = scanlines 25%
+ 11 = scanlines 12.5%
+
+0x0A (10) => Peripheral 5 Setting
+(R/W)
+ bit 7:6 = Multiface type (hard reset = 00) (config mode only)
+ 00 = Multiface +3 (enable port 0x3F, disable port 0xBF)
+ 01 = Multiface 128 v87.2 (enable port 0xBF, disable port 0x3F)
+ 10 = Multiface 128 v87.12 (enable port 0x9F, disable port 0x1F)
+ 11 = Multiface 1 (enable port 0x9F, disable port 0x1F)
+ bit 5 = Reserved, must be zero
+ bit 4 = Enable divmmc automap (hard reset = 0)
+ bit 3 = 1 to reverse left and right mouse buttons (hard reset = 0)
+ bit 2 = Reserved, must be zero
+ bits 1:0 = mouse dpi (hard reset = 01)
+ 00 = low dpi
+ 01 = default
+ 10 = medium dpi
+ 11 = high dpi
+
+0x0B (11) => Joystick I/O Mode
+(R/W) (soft reset = 0x01)
+ bit 7 = 1 to enable i/o mode
+ bit 6 = Reserved, must be 0
+ bits 5:4 = I/O Mode
+ 00 = bit bang
+ 01 = clock
+ 10 = uart on left joystick port
+ 11 = uart on right joystick port
+ bits 3:1 = Reserved, must be 0
+ bit 0 = Parameter
+ bit bang : copied to pin 7
+ clock : 0 = hold high when clock becomes high, 1 = run *
+ uart : 0 = redirect esp uart0 to joystick, 1 = redirect pi uart1 to joystick
+ (Tx out on pin 7, Rx in from pin 9, CTS_n in from pin 6 **)
+The state of output pin 7 is stored internally in a register and is retained across changing
+modes and while i/o mode is disabled. While in i/o mode, keyboard joystick types (Sinclair,
+Cursor, etc) produce no readings but the current state of pins can still be read via the
+Kempston ports. When leaving i/o mode, joystick operation resumes after ~64 scan lines
+have passed.
+* CTC channel 3 is currently used to drive pin 7 in clock mode. Freq = Fctc3 / 2.
+** CTS_n is only active if the seleced uart is in hw flow control mode.
+
+0x0E (14) => Core Version (sub minor number)
+(R) (see register 0x01 for the major and minor version number)
+
+0x0F (15) => Board ID
+(R)
+ bits 7:4 = Reserved, 0
+ bits 3:0 = Board ID
+ 0000 = ZXN Issue 2, XC6SLX16-2FTG256, 128Mbit W25Q128JV, 24bit spi, 64K*8 core size
+ 0001 = ZXN Issue 3, XC6SLX16-2FTG256, 128Mbit W25Q128JV, 24bit spi, 64K*8 core size
+ 0010 = ZXN Issue 4, XC7A15T-1CSG324, 256Mbit MX25L25645G, 32bit spi, 64K*34 core size
+
+0x10 (16) => Core Boot
+(R)
+ bit 7 = Reserved
+ bits 6:2 = Cored ID
+ bit 1 = Button DRIVE (divmmc) is pressed
+ bit 0 = Button M1 (multiface) is pressed
+(W)
+ bit 7 = Start selected core
+ bits 6:5 = Reserved, must be 0
+ bits 4:0 = Core ID 0-31 (config mode only) *
+* A write of an out of range core id is ignored; this is the preferred way to determine max id
+
+0x11 (17) => Video Timing (writable in config mode only)
+(R/W)
+ bits 7:3 = Reserved, must be 0
+ bits 2:0 = Mode (VGA = 0..6, HDMI = 7)
+ 000 = Base VGA timing, clk28 = 28000000 \ HDMI compatible
+ 001 = VGA setting 1, clk28 = 28571429 / HDMI compatible
+ 010 = VGA setting 2, clk28 = 29464286
+ 011 = VGA setting 3, clk28 = 30000000
+ 100 = VGA setting 4, clk28 = 31000000
+ 101 = VGA setting 5, clk28 = 32000000
+ 110 = VGA setting 6, clk28 = 33000000
+ * 50/60Hz selection depends on bit 2 of nextreg 0x05
+
+0x12 (18) => Layer 2 Active RAM bank
+(R/W)
+ bit 7 = Reserved, must be 0
+ bits 6:0 = Starting 16K RAM bank (soft reset = 8)
+
+0x13 (19) => Layer 2 Shadow RAM bank
+(R/W)
+ bit 7 = Reserved, must be 0
+ bits 6:0 = Starting 16K RAM bank (soft reset = 11)
+
+0x14 (20) => Global Transparency Colour
+(R/W)
+ bits 7:0 = Transparency colour value (soft reset = 0xe3)
+ * Note: This value is 8-bit, so the transparency colour is compared against
+ the MSB bits of the final 9-bit colour only.
+ * Note: This colour only applies to Layer 2, ULA and LoRes.
+ Sprites use nextreg 0x4B and the tilemap uses nextreg 0x4C for transparency except in text mode
+
+0x15 (21) => Sprite and Layers System
+(R/W)
+ bit 7 = Enable lores mode (soft reset = 0)
+ bit 6 = Sprite priority (1 = sprite 0 on top, 0 = sprite 127 on top) (soft reset = 0)
+ bit 5 = Enable sprite clipping in over border mode (soft reset = 0)
+ bits 4:2 = Set layer priority (eg SLU = sprites over layer 2 over ula) (soft reset = 000)
+ 000 - S L U
+ 001 - L S U
+ 010 - S U L
+ 011 - L U S
+ 100 - U S L
+ 101 - U L S
+ 110 - (U|T)S(T|U)(B+L) Blending layer and Layer 2 combined, colours clamped to [0,7]
+ 111 - (U|T)S(T|U)(B+L-5) Blending layer and Layer 2 combined, colours clamped to [0,7]
+ bit 1 = Enable sprites over border (soft reset = 0)
+ bit 0 = Enable sprites (soft reset = 0)
+
+0x16 (22) => Layer2 X Scroll LSB
+(R/W)
+ bits 7:0 = X Offset (0-255) (soft reset = 0)
+
+0x17 (23) => Layer2 Y Scroll
+(R/W)
+ bits 7:0 = Y Offset (limited to 0-191 when vertical resolution is 192 pixels) (soft reset = 0)
+
+0x18 (24) => Clip Window Layer 2
+(R/W)
+ bits 7:0 = Clip window coordinate (inclusive)
+ 1st write - X1 position (soft reset = 0)
+ 2nd write - X2 position (soft reset = 255)
+ 3rd write - Y1 position (soft reset = 0)
+ 4rd write - Y2 position (soft reset = 191)
+ Reads do not advance the clip position
+
+0x19 (25) => Clip Window Sprites
+(R/W)
+ bits 7:0 = Clip window coordinate (inclusive)
+ 1st write - X1 position (soft reset = 0)
+ 2nd write - X2 position (soft reset = 255)
+ 3rd write - Y1 position (soft reset = 0)
+ 4rd write - Y2 position (soft reset = 191)
+ Reads do not advance the clip position
+ When the clip window is enabled for sprites in "over border" mode,
+ the X coords are internally doubled and the clip window origin is
+ moved to the sprite origin inside the border.
+
+0x1A (26) => Clip Window ULA (and LoRes, see note)
+(R/W)
+ bits 7:0 = Clip window coordinate (inclusive)
+ 1st write = X1 position (soft reset = 0)
+ 2nd write = X2 position (soft reset = 255)
+ 3rd write = Y1 position (soft reset = 0)
+ 4rd write = Y2 position (soft reset = 191)
+ Reads do not advance the clip position
+ LoRes may get a separate clip window in the future
+
+0x1B (27) => Clip Window Tilemap
+(R/W)
+ bits 7:0 = Clip window coordinate (inclusive)
+ 1st write = X1 position (soft reset = 0)
+ 2nd write = X2 position (soft reset = 159)
+ 3rd write = Y1 position (soft reset = 0)
+ 4rd write = Y2 position (soft reset = 255)
+ Reads do not advance the clip position
+ The X coordinates are internally doubled.
+
+0x1C (28) => Clip Window control
+(R) (may change)
+ bits 7:6 = Tilemap clip index
+ bits 5:4 = ULA/Lores clip index
+ bits 3:2 = Sprite clip index
+ bits 1:0 = Layer 2 clip index
+(W) (may change)
+ bits 7:4 = Reserved, must be 0
+ bit 3 = Reset the tilemap clip index
+ bit 2 = Reset the ULA/LoRes clip index
+ bit 1 = Reset the sprite clip index
+ bit 0 = Reset the Layer 2 clip index
+
+0x1E (30) => Active video line (MSB)
+(R)
+ bits 7:1 = Reserved
+ bit 0 = Active line MSB
+
+0x1F (31) => Active video line (LSB)
+(R)
+ bits 7:0 = Active line LSB
+
+0x20 (32) => Generate Maskable Interrupt
+(R/W)
+ bit 7 = line
+ bit 6 = ula
+ bits 5:4 = reserved
+ bits 3:0 = ctc 3:0
+* Set bits on R indicate whether an interrupt occurred or is pending (alias of bits in NR 0xC8 - 0xCA)
+* Set bits on W always generate a maskable interrupt ignoring enables (NR 0xC4 - 0xC6)
+
+0x22 (34) => Line Interrupt control
+(R/W)
+ bit 7 = (R) Indicates if the ula is asserting an interrupt (even if disabled)
+ bits 7:3 = Reserved, must be 0
+ bit 2 = Disables ula interrupt (soft reset = 0) **
+ bit 1 = Enables line Interrupt (soft reset = 0) **
+ bit 0 = MSB of line interrupt value (soft reset = 0)
+** Aliases of interrupt enable bits in nextreg 0xC4
+
+0x23 (35) => Line Interrupt Value LSB
+(R/W)
+ bits 7:0 = Line Interrupt value LSB (soft reset = 0)
+
+0x24 (36) => Reserved
+ Protection against "OUT (0x3B),A", see Disciple Disk Interface for example
+ In legacy modes set selected nextreg to 0x24
+
+0x26 (38) => ULA X Scroll
+(R/W)
+ bits 7:0 = X Offset (0-255) (soft reset = 0)
+
+0x27 (39) => ULA Y Scroll
+(R/W)
+ bits 7:0 = Y Offset (0-191) (soft reset = 0)
+
+0x28 (40) => PS/2 Keymap Address MSB
+(R)
+ bits 7:0 = Stored palette value from nextreg 0x44
+(W)
+ bit 7 = 0 to select ps2 keymap, 1 to select key joystick
+ bits 6:1 = Reserved, must be 0
+ bit 0 = MSB address
+
+0x29 (41) => PS/2 Keymap Address LSB
+(W)
+ bits 7:0 = LSB adress
+
+0x2A (42) => PS/2 Keymap Data MSB
+(W)
+ bits 7:1 = Reserved, must be 0
+ bit 0 = MSB data
+* Not currently used by hardware, write 0
+
+0x2B (43) => PS/2 Keymap Data LSB
+(W) (write causes the data to be written and auto-increments the keymap address)
+ bits 7:0 = LSB data
+
+0x2C (44) => DAC B Mirror (left)
+(R)
+ bits 7:0 = MSB of current I2S (pi) left side sample
+ the LSB is latched and can be read from nextreg 0x2D later
+(W)
+ bits 7:0 = 8-bit sample written to left side DAC B (soft reset = 0x80)
+
+0x2D (45) => DAC A+D Mirror (mono)
+(R)
+ bits 7:0 = LSB of last I2S (pi) sample read from nextreg 0x2C or nextreg 0x2E
+(W)
+ bits 7:0 = 8-bit sample written to DACs A and D (soft reset = 0x80)
+
+0x2E (46) => DAC C Mirror (right)
+(R)
+ bits 7:0 = MSB of current I2S (pi) right side sample
+ the LSB is latched and can be read from nextreg 0x2D later
+(W)
+ bits 7:0 = 8-bit sample written to right side DAC C (soft reset = 0x80)
+
+0x2F (47) => Tilemap X Scroll MSB
+(R/W)
+ bits 7:2 = Reserved, must be 0
+ bits 1:0 = MSB X Offset (soft reset = 0)
+ Meaningful Range is 0-319 in 40 char mode, 0-639 in 80 char mode
+
+0x30 (48) => Tilemap X Scroll LSB
+(R/W)
+ bits 7:0 = LSB X Offset (soft reset = 0)
+ Meaningful range is 0-319 in 40 char mode, 0-639 in 80 char mode
+
+0x31 (49) => Tilemap Offset Y
+(R/W)
+ bits 7:0 = Y Offset (0-255) (soft reset = 0)
+
+0x32 (50) => LoRes X Scroll
+(R/W)
+ bits 7:0 = X Offset (0-255) (soft reset = 0)
+ LoRes scrolls in "half-pixels" at the same resolution and smoothness as Layer 2.
+
+0x33 (51) => LoRes Y Scroll
+(R/W)
+ bits 7:0 = Y Offset (0-191) (soft reset = 0)
+ LoRes scrolls in "half-pixels" at the same resolution and smoothness as Layer 2.
+
+0x34 (52) => Sprite Number
+(R/W)
+ If the sprite number is in lockstep with port 0x303B (nextreg 0x09 bit 4 is set)
+ bit 7 = Pattern address offset (add 128 to pattern address)
+ bits 6:0 = Sprite number 0-127, Pattern number 0-63
+ Selects which sprite has its attributes connected to the following registers.
+ Effectively performs an out to port 0x303B with the same value
+ Otherwise
+ bit 7 = Ignored
+ bits 6:0 = Sprite number 0-127
+ Selects which sprite has its attributes connected to the following registers.
+ Bit 7 always reads back as zero.
+
+0x35 (53) => Sprite Attribute 0
+0x75 (117) => Sprite Attribute 0 with automatic post increment of Sprite Number
+(W) See documentation at https://www.specnext.com/sprites/
+
+0x36 (54) => Sprite Attribute 1
+0x76 (118) => Sprite Attribute 1 with automatic post increment of Sprite Number
+(W) See documentation at https://www.specnext.com/sprites/
+
+0x37 (55) => Sprite Attribute 2
+0x77 (119) => Sprite Attribute 2 with automatic post increment of Sprite Number
+(W) See documentation at https://www.specnext.com/sprites/
+
+0x38 (56) => Sprite Attribute 3
+0x78 (120) => Sprite Attribute 3 with automatic post increment of Sprite Number
+(W) See documentation at https://www.specnext.com/sprites/
+
+0x39 (57) => Sprite Attribute 4
+0x79 (121) => Sprite Attribute 4 with automatic post increment of Sprite Number
+(W) See documentation at https://www.specnext.com/sprites/
+
+0x40 (64) => Palette Index
+(R/W)
+ bits 7:0 = Select the palette index to change the associated colour. (soft reset = 0)
+ For the ULA only, INKs are mapped to indices 0-7, Bright INKS to indices 8-15,
+ PAPERs to indices 16-23 and Bright PAPERs to indices 24-31.
+ In ULANext mode, INKs come from a subset of indices 0-127 and PAPERs come from
+ a subset of indices 128-255. The number of active indices depends on the number
+ of attribute bits assigned to INK and PAPER out of the attribute byte.
+ In ULA+ mode, the top 64 entries hold the ula+ palette.
+ The ULA always takes border colour from paper for standard ULA and ULAnext.
+
+0x41 (65) => Palette Value (8 bit colour)
+(R/W)
+ bits 7:0 = Colour for the palette index selected by nextreg 0x40.
+ The format is RRRGGGBB - the lower blue bit of the 9-bit colour will be the logical
+ OR of blue bits 1 and 0 of this 8-bit value.
+ After the write, the palette index is auto-incremented to the next index if the
+ auto-increment is enabled in nextreg 0x43. Reads do not auto-increment.
+ Any other bits associated with the index will be zeroed.
+
+0x42 (66) => ULANext Attribute Byte Format
+(R/W)
+ bits 7:0 = Mask indicating which bits of an attribute byte are used to represent INK.
+ Other bits represent PAPER. (soft reset = 0x07)
+ The mask can only indicate a solid sequence of bits on the right side of an attribute
+ byte (1, 3, 7, 15, 31, 63, 127 or 255).
+ INKs are mapped to base index 0 in the palette and PAPERs and border are
+ mapped to base index 128 in the palette.
+ The 255 value enables the full ink colour mode making all the palette entries INK.
+ In this case PAPER and border are both taken from the fallback colour in nextreg 0x4A.
+ If the mask is not one of those listed above, the INK is taken as the logical AND of
+ the mask with the attribute byte and the PAPER and border colour are again both taken
+ from the fallback colour in nextreg 0x4A.
+
+0x43 (67) => Palette Control
+(R/W)
+ bit 7 = Disable palette write auto-increment (soft reset = 0)
+ bits 6-4 = Select palette for reading or writing (soft reset = 000)
+ 000 = ULA first palette
+ 100 = ULA second palette
+ 001 = Layer 2 first palette
+ 101 = Layer 2 second palette
+ 010 = Sprites first palette
+ 110 = Sprites second palette
+ 011 = Tilemap first palette
+ 111 = Tilemap second palette
+ bit 3 = Select Sprites palette (0 = first palette, 1 = second palette) (soft reset = 0)
+ bit 2 = Select Layer 2 palette (0 = first palette, 1 = second palette) (soft reset = 0)
+ bit 1 = Select ULA palette (0 = first palette, 1 = second palette) (soft reset = 0)
+ bit 0 = Enabe ULANext mode (soft reset = 0)
+
+0x44 (68) => Palette Value (9 bit colour)
+(R/W)
+ Two consecutive writes are needed to write the 9 bit colour
+ 1st write:
+ bits 7:0 = RRRGGGBB
+ 2nd write:
+ bits 7:1 = Reserved, must be 0
+ bit 0 = lsb B
+ If writing to an L2 palette
+ bit 7 = 1 for L2 priority colour, 0 for normal.
+ An L2 priority colour moves L2 above all layers. If you need the same
+ colour in both priority and normal modes, you will need to have two
+ different entries with the same colour one with and one without priority.
+ After two consecutive writes the palette index is auto-incremented if
+ auto-increment is enabled in nextreg 0x43.
+ Reads only return the 2nd byte and do not auto-increment.
+ Writes to nextreg 0x40, 0x41, 0x43 reset to the 1st write.
+
+0x4A (74) => Fallback Colour
+(R/W)
+ bits 7:0 = 8-bit colour used if all layers are transparent (soft reset = 0xe3)
+
+0x4B (75) => Sprite Transparency Index
+(R/W)
+ bits 7:0 = Sprite colour index treated as transparent (soft reset = 0xe3)
+ For 4-bit sprites only the bottom 4-bits are used
+
+0x4C (76) => Tilemap Transparency Index
+(R/W)
+ bits 7-4 = Reserved, must be 0
+ bits 3-0 = Tilemap colour index treated as transparent (soft reset = 0xf)
+
+0x50 (80) => MMU slot 0
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0x0000 - 0x1FFF (soft reset = 255)
+ Pages range from 0 to 223 on a fully expanded Next.
+ A 255 value causes the ROM to become visible.
+
+0x51 (81) => MMU slot 1
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0x2000 - 0x3FFF (soft reset = 255)
+ Pages range from 0 to 223 on a fully expanded Next.
+ A 255 value causes the ROM to become visible.
+
+0x52 (82) => MMU slot 2
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0x4000 - 0x5FFF (soft reset = 10)
+ Pages range from 0 to 223 on a fully expanded Next.
+
+0x53 (83) => MMU slot 3
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0x6000 - 0x7FFF (soft reset = 11)
+ Pages range from 0 to 223 on a fully expanded Next.
+
+0x54 (84) => MMU slot 4
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0x8000 - 0x9FFF (soft reset = 4)
+ Pages range from 0 to 223 on a fully expanded Next.
+
+0x55 (85) => MMU slot 5
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0xA000 - 0xBFFF (soft reset = 5)
+ Pages range from 0 to 223 on a fully expanded Next.
+
+0x56 (86) => MMU slot 6
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0xC000 - 0xDFFF (soft reset = 0)
+ Pages range from 0 to 223 on a fully expanded Next.
+
+0x57 (87) => MMU slot 7
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0xE000 - 0xFFFF (soft reset = 1)
+ Pages range from 0 to 223 on a fully expanded Next.
+
+0x60 (96) => Copper Data 8-bit Write
+(W)
+ bits 7:0 = Byte to write to copper instruction memory
+ Note that each copper instruction is two bytes long
+ After a write, the copper address is auto-incremented to the next memory position
+
+0x61 (97) => Copper Address LSB
+(R/W)
+ bits 7:0 = Copper instruction memory address LSB (soft reset = 0)
+ (Copper addresses range over 0 - 0x7FF = 2K)
+
+0x62 (98) => Copper Control
+(R/W)
+ bits 7:6 = Start control (soft reset = 00)
+ 00 = Copper fully stopped
+ 01 = Copper start, execute the list from index 0, and loop to the start
+ 10 = Copper start, execute the list from last point, and loop to the start
+ 11 = Copper start, execute the list from index 0, and restart the list
+ when the raster reaches position (0,0)
+ bits 2:0 = Copper instruction memory address MSB (soft reset = 0)
+ (Copper addresses range over 0 - 0x7FF = 2K)
+ Writing the same start control value does not reset the copper
+
+0x63 (99) => Copper Data 16-bit Write
+(W)
+ The 16-bit value is written in pairs. The first 8-bits are the MSB and
+ are destined for an even copper instruction address. The second 8-bits are
+ the LSB and are destined for an odd copper instruction address.
+ After each write, the copper address is auto-incremented to the next memory position
+ After a write to an odd address, the entire 16-bits is written to copper memory at once
+
+0x64 (100) => Vertical Line Count Offset
+(R/W)
+ bits 7:0 = Offset added to the vertical line counter affects copper, line interrupt and active line count.
+ Normally the ula's pixel row 0 aligns with vertical line count 0. With a non-zero
+ offset, the ula's pixel row 0 will align with the vertical line offset. Eg, if the offset is 32
+ then vertical line 32 will correspond to the first pixel row in the ula and vertical line 0
+ will align with the first pixel row of the tilemap and sprites.
+ * Since a change in offset takes effect when the ula reaches row 0, the change can take up to
+ one frame to occur.
+
+0x68 (104) => ULA Control
+(R/W)
+ bit 7 = Disable ULA output (soft reset = 0)
+ bits 6:5 = Blending in SLU modes 6 & 7 (soft reset = 0)
+ = 00 for ula as blend colour
+ = 10 for ula/tilemap mix result as blend colour
+ = 11 for tilemap as blend colour
+ = 01 for no blending
+ bit 4 = Cancel entries in 8x5 matrix for extended keys
+ bit 3 = ULA+ enable (soft reset = 0)
+ bit 2 = ULA half pixel scroll (may change) (soft reset = 0)
+ bit 1 = Reserved, must be 0
+ bit 0 = Enable stencil mode when both the ULA and tilemap are enabled (soft reset = 0)
+ (if either are transparent the result is transparent otherwise the result is a logical AND of both colours)
+
+0x69 (105) => Display Control 1
+(R/W)
+ bit 7 = Enable layer 2 (alias port 0x123B bit 1)
+ bit 6 = Enable ULA shadow display (alias port 0x7FFD bit 3)
+ bits 5:0 = Port 0xFF bits 5:0 alias (Timex display modes)
+
+0x6A (106) => LoRes Control
+(R/W)
+ bits 7-6 = Reserved, must be 0
+ bit 5 = LoRes is Radastan mode (128x96x4, 6144 bytes) (soft reset = 0)
+ bit 4 = LoRes Radastan timex display file xor (soft reset = 0)
+ bits 3:0 = LoRes palette offset (bits 1:0 apply in ula+ mode) (soft reset = 0)
+
+0x6B (107) => Tilemap Control
+(R/W)
+ bit 7 = 1 Enable the tilemap (soft reset = 0)
+ bit 6 = 0 for 40x32, 1 for 80x32 (soft reset = 0)
+ bit 5 = Eliminate the attribute entry in the tilemap (soft reset = 0)
+ bit 4 = Palette select (soft reset = 0)
+ bit 3 = Select textmode (soft reset = 0)
+ bit 2 = Reserved, must be 0
+ bit 1 = Activate 512 tile mode (soft reset = 0)
+ bit 0 = Force tilemap on top of ULA (soft reset = 0)
+
+0x6C (108) => Default Tilemap Attribute
+(R/W)
+ Active if nextreg 0x6B bit 5 is set
+ bits 7:4 = Palette offset (soft reset = 0)
+ bit 3 = X mirror (soft reset = 0)
+ bit 2 = Y mirror (soft reset = 0)
+ bit 1 = Rotate (soft reset = 0)
+ bit 0 = ULA over tilemap (soft reset = 0)
+ (or bit 8 of the tile number if 512 tile mode is enabled)
+
+0x6E (110) => Tilemap Base Address
+(R/W) (soft reset = 0x6c00)
+ bit 7 = 1 to select bank 7, 0 to select bank 5
+ bit 6 = Reserved, must be 0
+ bits 5:0 = MSB of address of the tilemap in Bank 5
+ The value written into bits 5:0 is an offset into 16K bank 5 or 8K bank 7
+ allowing the tilemap to be placed at any multiple of 256 bytes. The value
+ written here can be thought of as the MSB of an address in bank 5 0x40-0x7f
+ or bank 7 0xc0-0xff. Because bank 7 is only 8K in size, addresses wrap
+ across the 8K boundary instead of the 16K boundary.
+
+0x6F (111) => Tile Definitions Base Address
+(R/W) (soft reset = 0x4c00)
+ bit 7 = 1 to select bank 7, 0 to select bank 5
+ bit 6 = Reserved, must be 0
+ bits 5:0 = MSB of address of tile definitions in Bank 5
+ The value written into bits 5:0 is an offset into 16K bank 5 or 8K bank 7
+ allowing the tile definitions to be placed at any multiple of 256 bytes. The
+ value written here can be thought of as the MSB of an address in bank 5
+ 0x40-0x7f or bank 7 0xc0-0xff. Because bank 7 is only 8K in size, addresses
+ wrap across the 8K boundary instead of the 16K boundary.
+
+0x70 (112) => Layer 2 Control
+(R/W)
+ bits 7:6 = Reserved, must be 0
+ bits 5:4 = Layer 2 resolution (soft reset = 0)
+ 00 = 256x192x8
+ 01 = 320x256x8
+ 10 = 640x256x4
+ bits 3:0 = Palette offset (soft reset = 0)
+
+0x71 (113) => Layer 2 X Scroll MSB
+(R/W)
+ bits 7:1 = Reserved, must be 0
+ bit 0 = MSB of scroll amount
+
+0x75 (117) => Sprite Attribute 0 with automatic post increment of Sprite Number
+(W) see nextreg 0x35
+
+0x76 (118) => Sprite Attribute 1 with automatic post increment of Sprite Number
+(W) see nextreg 0x36
+
+0x77 (119) => Sprite Attribute 2 with automatic post increment of Sprite Number
+(W) see nextreg 0x37
+
+0x78 (120) => Sprite Attribute 3 with automatic post increment of Sprite Number
+(W) see nextreg 0x38
+
+0x79 (121) => Sprite Attribute 4 with automatic post increment of Sprite Number
+(W) see nextreg 0x39
+
+0x7F (127) => User Register 0
+(R/W)
+ bits 7:0 = Unused storage available to the user (soft reset = 0xff)
+
+NEXTREG 0x80 AND HIGHER ARE INACCESSIBLE TO THE COPPER
+
+0x80 (128) => Expansion Bus Enable
+(R/W) (hard reset = 0)
+IMMEDIATE
+bit 7 = 1 to enable the expansion bus
+bit 6 = 1 to enable romcs rom replacement from divmmc banks 14/15
+bit 5 = 1 to disable i/o cycles & ignore iorqula
+bit 4 = 1 to disable memory cycles & ignore romcs
+AFTER SOFT RESET (copied into bits 7-4)
+bit 3 = 1 to enable the expansion bus
+bit 2 = 1 to enable romcs rom replacement from divmmc banks 14/15
+bit 1 = 1 to disable i/o cycles & ignore iorqula
+bit 0 = 1 to disable memory cycles & ignore romcs
+
+0x81 (129) => Expansion Bus Control
+(R/W) (hard reset = 0)
+bit 7 = 1 if ROMCS is asserted on the expansion bus (read only)
+bit 6 = 1 to allow peripherals to override the ULA on some even port reads (rotronics wafadrive)
+bit 5 = 1 to disable expansion bus nmi debounce (opus discovery)
+bit 4 = 1 to propagate the max cpu clock at all times including when the expansion bus is off
+bits 1-0 = max cpu speed when the expansion bus is on (currently fixed at 00 = 3.5MHz)
+
+0x85,0x84,0x83,0x82 (133-130) => Internal Port Decoding Enables (0x85 is MSB) (soft reset if bit 31 = 1, hard reset if bit 31 = 0 : all 1)
+0x89,0x88,0x87,0x86 (137-134) => Expansion Bus Decoding Enables (0x89 is MSB) (soft reset if bit 31 = 0, hard reset if bit 31 = 1 : all 1)
+(R/W)
+ bit 0 = port ff
+ bit 1 = port 7ffd
+ bit 2 = port dffd
+ bit 3 = port 1ffd
+ bit 4 = +3 floating bus
+ bit 5 = port 6b zxn dma
+ bit 6 = port 1f kempston / md1
+ bit 7 = port 37 kempston 2 / md2
+ -----
+ bit 8 = port e3 divmmc control
+ bit 9 = multiface (two variable ports)
+ bit 10 = port 103b,113b i2c
+ bit 11 = port e7,eb spi
+ bit 12 = port 133b,143b,153b,163b uart
+ bit 13 = port fadf,fbdf,ffdf mouse (also disables kempston alias on port df)
+ bit 14 = port 57,5b,303b sprites
+ bit 15 = port 123b layer2
+ -----
+ bit 16 = port fffd,bffd ay
+ bit 17 = port 0f,1f,4f,5f dac soundrive mode 1
+ bit 18 = port f1,f3,f9,fb dac soundrive mode 2
+ bit 19 = port 3f,5f dac stereo profi covox
+ bit 20 = port 0f,4f dac stereo covox
+ bit 21 = port fb dac mono pentagon/atm (sd mode 2 off)
+ bit 22 = port b3 dac mono gs covox
+ bit 23 = port df dac mono specdrum, port 1f kempston alias
+ -----
+ bit 24 = port bf3b,ff3b ula+
+ bit 25 = port 0b z80 dma
+ bit 26 = port eff7 pentagon 1024 memory
+ bit 27 = port 183b,193b,1a3b,1b3b,1c3b,1d3b,1e3b,1f3b z80 ctc
+ ...
+ bit 31 = register reset mode (soft or hard reset selection)
+ -----
+ The internal port decoding enables always apply.
+ When the expansion bus is on, the expansion port decoding enables are logically ANDed with the internal enables.
+ A zero bit indicates the internal device is disabled. If the expansion bus is on, this allows io cycles for
+ disabled ports to propagate to the expansion bus, otherwise corresponding io cycles to the expansion bus are filtered.
+
+0x8A (138) => Expansion Bus IO Propagate
+(R/W)
+ bits 7:6 = Reserved, must be 0
+ bit 5 = Propagate port 0xeff7 io cycles (hard reset = 0)
+ bit 4 = Propagate port 0xff io cycles (hard reset = 0)
+ bit 3 = Propagate port 0x1ffd io cycles (hard reset = 0)
+ bit 2 = Propagate port 0xdffd io cycles (hard reset = 0)
+ bit 1 = Propagate port 0x7ffd io cycles (hard reset = 0)
+ bit 0 = Propagate port 0xfe io cycles (hard reset = 0)
+ If any of the bits are set, io cycles for the corresponding ports are propagated to the expansion bus when
+ the expansion bus is on. If the internal port decode is still active, any response sent by devices on the
+ expansion bus will be ignored. The purpose here is to allow external peripherals to monitor changes in state
+ inside the zx next.
+ Port 0xfe is treated specially so that external keyboards can be attached. When its propagate bit is set,
+ the value read from the bus will be mixed into keyboard reads on port 0xfe.
+
+0x8C (140) => Alternate ROM
+(R/W) (hard reset = 0)
+IMMEDIATE
+ bit 7 = 1 to enable alt rom
+ bit 6 = 1 to make alt rom visible only during writes, otherwise replaces rom during reads
+ bit 5 = 1 to lock ROM1 (48K rom)
+ bit 4 = 1 to lock ROM0 (128K rom)
+AFTER SOFT RESET (copied into bits 7-4)
+ bit 3 = 1 to enable alt rom
+ bit 2 = 1 to make alt rom visible only during writes, otherwise replaces rom during reads
+ bit 1 = 1 to lock ROM1 (48K rom)
+ bit 0 = 1 to lock ROM0 (128K rom)
+The locking mechanism also applies if the alt rom is not enabled. For the +3 and zx next, if the two lock bits are not
+zero, then the corresponding rom page is locked in place. Other models use the bits to preferentially lock the corresponding
+48K rom or the 128K rom.
+
+0x8E (142) => Spectrum 128K Memory Mapping
+(R/W)
+ bit 7 = port 0xdffd bit 0 \ RAM
+ bits 6:4 = port 0x7ffd bits 2:0 / bank 0-15
+R bit 3 = 1
+W bit 3 = 1 to change RAM bank, 0 = no change to mmu6 / mmu7 / RAM bank in ports 0x7ffd, 0xdffd
+ bit 2 = port 0x1ffd bit 0 paging mode
+If bit 2 = paging mode = 0 (normal)
+ bit 1 = port 0x1ffd bit 2 \ ROM
+ bit 0 = port 0x7ffd bit 4 / select
+If bit 2 = paging mode = 1 (special allRAM)
+ bit 1 = port 0x1ffd bit 2 \ all
+ bit 0 = port 0x1ffd bit 1 / RAM
+Writes can affect all ports 0x7ffd, 0xdffd, 0x1ffd
+Writes always change the ROM / allRAM mapping
+Writes immediately change the current mmu mapping as if by port write
+
+0x8F (143) => Memory Mapping Mode
+(R/W) (hard reset = 0)
+ bits 7:2 = Reserved, must be zero
+ bits 1:0 = Mapping mode applied
+ 00 = Standard ZX 128k +3
+ 01 = Reserved
+ 10 = Pentagon 512K
+ 11 = Pentagon 1024K (limited to 768K on 1MB machines)
+* Standard ZX 128K +3 = principally ports 0x7ffd, 0xdffd, 0x1ffd
+* Pentagon 512K = principally port 0x7ffd
+* Pentagon 1024K = principally ports 0x7ffd, 0xeff7
+** The mapping modes affect how ports 0x7ffd, 0xdffd, 0x1ffd and 0xeff7 carry out memory paging, see ports.txt
+
+0x93,0x92,0x91,0x90 (147-144) => PI GPIO Output Enable (0x93 is MSB)
+(R/W)
+ bits 27:0 Set bits enable GPIO output on the corresponding GPIO pin (soft reset = all 0)
+ (GPIO pins 1:0 cannot be enabled)
+
+0x9B,0x9A,0x99,0x98 (155-152) => PI GPIO (0x9B is MSB)
+(R/W)
+ bits 27:0 Read / Write the GPIO pin state (soft reset = 0x00001ff)
+ (writes only propagate when the corresponding pin has its output enabled)
+
+0xA0 (160) => PI Peripheral Enable
+(R/W)
+ bits 7:6 = Reserved, must be 0
+ bit 5 = Enable UART on GPIO 14,15 (overrides gpio)* (soft reset = 0)
+ bit 4 = 0 to connect Rx to GPIO 15, Tx to GPIO 14 (for comm with pi hats) (soft reset = 0)
+ = 1 to connect Rx to GPIO 14, Tx to GPIO 15 (for comm with pi)
+ bit 3 = Enable I2C on GPIO 2,3 (override gpio) (soft reset = 0)
+ bits 2:1 = Reserved, must be 0
+ bit 0 = Enable SPI on GPIO 7,8,9,10,11 (overrides gpio) (soft reset = 0)
+* GPIO 16,17 will function as rtr_n and cts_n if the uart is in hw flow control mode
+
+0xA2 (162) => PI I2S Audio Control
+(R/W)
+ bits 7:6 = I2S enable (soft reset = 00)
+ 00 = i2s off
+ 01 = i2s is mono source right
+ 10 = i2s is mono source left
+ 11 = i2s is stereo
+ bit 5 = Reserved, must be 0
+ bit 4 = 0 PCM_DOUT to pi, PCM_DIN from pi (hats) (soft reset = 0)
+ = 1 PCM_DOUT from pi, PCM_DIN to pi (pi)
+ bit 3 = Mute left side (soft reset = 0)
+ bit 2 = Mute right side (soft reset = 0)
+//bit 1 = Slave mode (PCM_CLK, PCM_FS supplied externally) (soft reset = 0)
+ bit 1 = Reserved must be 1
+ bit 0 = Direct i2s audio to EAR on port 0xFE (soft reset = 0)
+
+// 0xA3 (163) => PI I2S Clock Divide (Master Mode)
+// (R/W)
+// bits 7:0 = Clock divide sets sample rate when in master mode (soft reset = 11)
+// clock divider = 538461 / SampleRateHz - 1
+
+0xA8 (168) => ESP Wifi GPIO Output Enable
+(R/W) (soft reset = 0)
+ bit 2 = GPIO2 output enable (fixed at 0, GPIO2 is read-only)
+ bit 0 = GPIO0 output enable
+
+0xA9 (169) => ESP Wifi GPIO
+(R/W)
+ bit 2 = Read / Write ESP GPIO2 (soft reset = 1)
+ bit 0 = Read / Write ESP GPIO0 (soft reset = 1)
+
+0xB0 (176) => Extended Keys 0
+(R)
+ bit 7 = 1 if ; pressed
+ bit 6 = 1 if " pressed
+ bit 5 = 1 if , pressed
+ bit 4 = 1 if . pressed
+ bit 3 = 1 if UP pressed
+ bit 2 = 1 if DOWN pressed
+ bit 1 = 1 if LEFT pressed
+ bit 0 = 1 if RIGHT pressed
+* Nextreg 0x68 bit 4 stops extended keys from making entries in the 8x5 matrix
+
+0xB1 (177) => Extended Keys 1
+(R)
+ bit 7 = 1 if DELETE pressed
+ bit 6 = 1 if EDIT pressed
+ bit 5 = 1 if BREAK pressed
+ bit 4 = 1 if INV VIDEO pressed
+ bit 3 = 1 if TRUE VIDEO pressed
+ bit 2 = 1 if GRAPH pressed
+ bit 1 = 1 if CAPS LOCK pressed
+ bit 0 = 1 if EXTEND pressed
+* Nextreg 0x68 bit 4 stops extended keys from making entries in the 8x5 matrix
+
+0xB2 (178) => Extended MD Pad Buttons
+(R)
+ bit 7 = 1 if Right Pad X pressed
+ bit 6 = 1 if Right Pad Z pressed
+ bit 5 = 1 if Right Pad Y pressed
+ bit 4 = 1 if Right Pad MODE pressed
+ bit 3 = 1 if Left Pad X pressed
+ bit 2 = 1 if Left Pad Z pressed
+ bit 1 = 1 if Left Pad Y pressed
+ bit 0 = 1 if Left Pad MODE pressed
+
+0xB8 (184) => Divmmc Entry Points 0
+(R/W) (soft reset = 0x83)
+ bit 7 = 1 to enable automap on address 0x0038 (instruction fetch)
+ bit 6 = 1 to enable automap on address 0x0030 (instruction fetch)
+ bit 5 = 1 to enable automap on address 0x0028 (instruction fetch)
+ bit 4 = 1 to enable automap on address 0x0020 (instruction fetch)
+ bit 3 = 1 to enable automap on address 0x0018 (instruction fetch)
+ bit 2 = 1 to enable automap on address 0x0010 (instruction fetch)
+ bit 1 = 1 to enable automap on address 0x0008 (instruction fetch)
+ bit 0 = 1 to enable automap on address 0x0000 (instruction fetch)
+
+0xB9 (185) => Divmmc Entry Points Valid 0
+(R/W) (soft reset = 0x01)
+ bit 7 = 1 for always else only when rom3 is present (0x0038)
+ bit 6 = 1 for always else only when rom3 is present (0x0030)
+ bit 5 = 1 for always else only when rom3 is present (0x0028)
+ bit 4 = 1 for always else only when rom3 is present (0x0020)
+ bit 3 = 1 for always else only when rom3 is present (0x0018)
+ bit 2 = 1 for always else only when rom3 is present (0x0010)
+ bit 1 = 1 for always else only when rom3 is present (0x0008)
+ bit 0 = 1 for always else only when rom3 is present (0x0000)
+
+0xBA (186) => Divmmc Entry Points Timing 0
+(R/W) (soft reset = 0x00)
+ bit 7 = 1 for instant mapping else delayed (0x0038)
+ bit 6 = 1 for instant mapping else delayed (0x0030)
+ bit 5 = 1 for instant mapping else delayed (0x0028)
+ bit 4 = 1 for instant mapping else delayed (0x0020)
+ bit 3 = 1 for instant mapping else delayed (0x0018)
+ bit 2 = 1 for instant mapping else delayed (0x0010)
+ bit 1 = 1 for instant mapping else delayed (0x0008)
+ bit 0 = 1 for instant mapping else delayed (0x0000)
+
+0xBB (187) => Divmmc Entry Points 1
+(R/W) (soft reset = 0xCD)
+ bit 7 = 1 to enable automap on addresses 0x3DXX (instruction fetch, instant, ROM3) > TRDOS
+ bit 6 = 1 to disable automap on addresses 0x1FF8-0x1FFF (instruction fetch, delayed)
+ bit 5 = 1 to enable automap on address 0x056A (instruction fetch, delayed, ROM3) \ tape traps
+ bit 4 = 1 to enable automap on address 0x04D7 (instruction fetch, delayed, ROM3) / nextzxos (better compatibility)
+ bit 3 = 1 to enable automap on address 0x0562 (instruction fetch, delayed, ROM3) \ tape traps
+ bit 2 = 1 to enable automap on address 0x04C6 (instruction fetch, delayed, ROM3) / esxdos + original divmmc
+ bit 1 = 1 to enable automap on address 0x0066 (instruction fetch + button, instant)
+ bit 0 = 1 to enable automap on address 0x0066 (instruction fetch + button, delayed)
+
+// INTERRUPTS
+
+0xC0 (192) => Interrupt Control
+(R/W) (soft reset = 0)
+ bits 7:5 = Programmable portion of im2 vector*
+ bit 4 = Reserved must be 0
+ bit 3 = Enable stackless nmi response**
+ bits 2:1 = Current Z80 interrupt mode 0,1,2 (read only, write ignored)
+ bit 0 = Maskable interrupt mode: pulse (0) or hw im2 mode (1)
+* In hw im2 mode the interrupt vector generated is:
+ bits 7:5 = nextreg 0xC0 bits 7:5
+ bits 4:1 = 0 line interrupt (highest priority)
+ = 1 uart0 Rx
+ = 2 uart1 Rx
+ = 3-10 ctc channels 0-7
+ = 11 ula
+ = 12 uart0 Tx
+ = 13 uart1 Tx (lowest priority)
+ bit 0 = 0
+* In hw im2 mode the expansion bus is the lowest priority interrupter
+ and if no vector is supplied externally then 0xFF is generated.
+** The return address pushed during an nmi acknowledge cycle will
+ be written to nextreg instead of memory (the stack pointer will
+ be decremented) and the first RETN after the acknowledge will
+ take its return address from nextreg instead of memory (the stack
+ pointer will be incremented). If bit 3 = 0 and in other
+ circumstances, RETN functions normally.
+
+0xC2 (194) => NMI Return Address LSB
+(R/W) (soft reset = 0)
+
+0xC3 (195) => NMI Return Address MSB
+(R/W) (soft reset = 0)
+
+The return address written during an nmi acknowledge cycle is
+always stored in these registers.
+
+--
+
+0xC4 (196) => INT EN 0
+(R/W) (soft reset = 0x81)
+ bit 7 = Expansion bus /INT
+ bits 6:2 = Reserved must be 0
+ bit 1 = Line **
+ bit 0 = ULA **
+* If a device interrupt is disabled, it enters a polled mode
+** Aliases of interrupt enable bits in nextreg 0x22
+
+0xC5 (197) => INT EN 1
+(R/W) (soft reset = 0)
+ bit 7 = ctc channel 7 zc/to
+ bit 6 = ctc channel 6 zc/to
+ bit 5 = ctc channel 5 zc/to
+ bit 4 = ctc channel 4 zc/to
+ bit 3 = ctc channel 3 zc/to
+ bit 2 = ctc channel 2 zc/to
+ bit 1 = ctc channel 1 zc/to
+ bit 0 = ctc channel 0 zc/to
+* If a device interrupt is disabled, it enters a polled mode
+
+
+0xC6 (198) => INT EN 2
+(R/W) (soft reset = 0)
+ bit 7 = Reserved must be zero
+ bit 6 = UART1 Tx empty
+ bit 5 = UART1 Rx near full \ shared
+ bit 4 = UART1 Rx available / interrupt
+ bit 3 = Reserved must be zero
+ bit 2 = UART0 Tx empty
+ bit 1 = UART0 Rx near full \ shared
+ bit 0 = UART0 Rx available / interrupt
+* Rx near full overrides Rx available
+* If a device interrupt is disabled, it enters a polled mode
+
+0xC7 (199) => Reserved, write 0
+
+--
+
+0xC8 (200) => INT Status 0
+(R/W)
+ bits 7:2 = Reserved must be 0
+ bit 1 = Line
+ bit 0 = ULA
+* (R) Set bits indicate the device generated an interrupt in the past or an interrupt is pending
+* (W) Set bits clear the status. In hw im2 mode the status will continue to read as set until the
+ interrupt pending condition is cleared
+
+0xC9 (201) => INT Status 1
+(R/W)
+ bit 7 = ctc channel 7 zc/to
+ bit 6 = ctc channel 6 zc/to
+ bit 5 = ctc channel 5 zc/to
+ bit 4 = ctc channel 4 zc/to
+ bit 3 = ctc channel 3 zc/to
+ bit 2 = ctc channel 2 zc/to
+ bit 1 = ctc channel 1 zc/to
+ bit 0 = ctc channel 0 zc/to
+* (R) Set bits indicate the device generated an interrupt in the past or an interrupt is pending
+* (W) Set bits clear the status. In hw im2 mode the status will continue to read as set until the
+ interrupt pending condition is cleared
+
+0xCA (202) => INT Status 2
+(R/W)
+ bit 7 = Reserved must be zero
+ bit 6 = UART1 Tx empty
+ bit 5 = UART1 Rx half full \ shared
+ bit 4 = UART1 Rx available / interrupt
+ bit 3 = Reserved must be zero
+ bit 2 = UART0 Tx empty
+ bit 1 = UART0 Rx half full \ shared
+ bit 0 = UART0 Rx available / interrupt
+* (R) Set bits indicate the device generated an interrupt in the past or an interrupt is pending
+* (W) Set bits clear the status. In hw im2 mode the status will continue to read as set until the
+ interrupt pending condition is cleared
+
+0xCB (203) => Reserved, write 0xFF
+
+--
+
+0xCC (204) => DMA INT EN 0
+(R/W) (soft reset = 0)
+ bit 7 = NMI
+ bit 1 = Line
+ bit 0 = ULA
+* Set bits indicate the corresponding interrupt will interrupt a dma operation when in hw im2 mode
+
+0xCD (205) => DMA INT EN 1
+(R/W) (soft reset = 0)
+ bit 7 = ctc channel 7 zc/to
+ bit 6 = ctc channel 6 zc/to
+ bit 5 = ctc channel 5 zc/to
+ bit 4 = ctc channel 4 zc/to
+ bit 3 = ctc channel 3 zc/to
+ bit 2 = ctc channel 2 zc/to
+ bit 1 = ctc channel 1 zc/to
+ bit 0 = ctc channel 0 zc/to
+* Set bits indicate the corresponding interrupt will interrupt a dma operation when in hw im2 mode
+
+0xCE (206) => DMA INT EN 2
+(R/W) (soft reset = 0)
+ bit 7 = Reserved must be zero
+ bit 6 = UART1 Tx empty
+ bit 5 = UART1 Rx half full \ shared
+ bit 4 = UART1 Rx available / interrupt
+ bit 3 = Reserved must be zero
+ bit 2 = UART0 Tx empty
+ bit 1 = UART0 Rx half full \ shared
+ bit 0 = UART0 Rx available / interrupt
+* Set bits indicate the corresponding interrupt will interrupt a dma operation when in hw im2 mode
+
+0xCF (207) => Reserved, write 0
+
+Because interrupts are only sampled at the end of an instruction
+by the Z80, each time the dma is interrupted one instruction of
+progress is made in the main program.
+
+--
+
+0xD8 (216) => I/O Traps (experimental)
+(R/W) (soft reset = 0)
+ bits 7:1 = Reserved must be zero
+ bit 0 = 1 to enable +3 FDC traps on ports 0x2ffd and 0x3ffd
+* An i/o trap generates a multiface nmi and is indicated in nextreg 0x02
+* Traps cannot be triggered by the dma or while the multiface, divmmc or external nmi is active
+
+0xD9 (217) => I/O Trap Write (experimental)
+(R/W)
+ Holds byte written during trapped i/o write cycle
+
+0xDA (218) => I/O Trap Cause (experimental)
+ 0 = none (zero at the same time nextreg 0x02 bit 4 is 0)
+ 1 = port_2ffd read
+ 2 = port_3ffd read
+ 3 = port_3ffd write
+* If nextreg 0x02 bit 4 indicates an i/o cycle was trapped, this register indicates the cause
+
+--
+
+0xF0 (240) => XDEV CMD
+(R/W Issue 4 Only) (soft reset = 0x80)
+ * Select Mode
+ (R)
+ bit 7 = 1 if in select mode
+ bits 1:0 indicate currently selected device
+ 00 = none
+ 01 = Xilinx DNA
+ 10 = Xilinx XADC
+ (W)
+ bit 7 = 1 to enter select mode, 0 to enter selected device mode (no other bits have effect)
+ bit 6 = 1 to change selected device
+ bits 1:0 selected device
+ 00 = none
+ 01 = Xilinx DNA
+ 10 = Xilinx XADC
+ * Xilinx DNA Mode
+ (R)
+ bit 0 = dna bit (serial stream shifts left)
+ the first eight bits read will indicate the length of the following dna bits
+ (W)
+ bit 7 = 1 to enter select mode (write has no other effect)
+ otherwise causes dna string to reload, ready for fresh read
+ * Xilinx XADC Mode (Documented in Xilinx Series 7 UG480)
+ (R)
+ bit 6 = 1 if XADC is busy with conversion (BUSY)
+ bit 1 = 1 if XADC conversion completed since last read (EOC, read clears)
+ bit 0 = 1 if XADC conversion sequence completed since last read (EOS, read clears)
+ (W)
+ bit 7 = 1 to enter select mode (write has no other effect)
+ bit 6 = 1 to reset XADC (RESET)
+ bit 0 = 1 to start conversion (CONVST)
+* Re-enter select mode at any time by writing to the register with bit 7 set
+* Select a device to communicate with by writing to the register with bits 6 & 7 set
+* Exit select mode by writing zero to bit 7; thereafter the particular device is attached to the nextreg
+
+0xF8 (248) => XADC REG
+(R/W Issue 4 Only) (hard reset = 0)
+ bit 7 = 1 to write to XADC DRP port, 0 to read from XADC DRP port **
+ bits 6:0 = XADC DRP register address DADDR
+* An XADC register read or write is initiated by writing to this register
+* There must be at least six 28 MHz cycles after each r/w to this register
+** Reads as 0
+
+0xF9 (249) => XADC D0
+(R/W Issue 4 Only) (hard reset = 0)
+ bits 7:0 = LSB data connected to XADC DRP data bus D7:0
+* DRP reads store result here, DRP writes take value from here
+
+0xFA (250) => XADC D1
+(R/W Issue 4 Only) (hard reset = 0)
+ bits 7:0 = MSB data connected to XADC DRP data bus D15:8
+DRP reads store result here, DRP writes take value from here
+
+--
+
+0xFF (255) => Reserved for internal use
diff --git a/data/nextreg_bare.txt b/data/nextreg_bare.txt
new file mode 100644
index 0000000..187bff6
--- /dev/null
+++ b/data/nextreg_bare.txt
@@ -0,0 +1,1239 @@
+0x00 (00) => Machine ID
+(R)
+ 0000 1000 = EMULATORS
+
+ 0000 1010 = ZX Spectrum Next
+ 1111 1010 = ZX Spectrum Next Anti-brick
+
+ 1001 1010 = ZX Spectrum Next Core on UnAmiga Reloaded
+ 1010 1010 = ZX Spectrum Next Core on UnAmiga
+ 1011 1010 = ZX Spectrum Next Core on SiDi
+ 1100 1010 = ZX Spectrum Next Core on MIST
+ 1101 1010 = ZX Spectrum Next Core on MiSTer
+ 1110 1010 = ZX Spectrum Next Core on ZX-DOS
+
+0x01 (01) => Core Version
+(R)
+ bits 7:4 = Major version number
+ bits 3:0 = Minor version number
+ (see register 0x0E for sub minor version number)
+
+0x02 (02) => Reset
+(R)
+ bit 7 = 1 if the reset signal to the expansion bus and esp is asserted
+ bits 6:5 = Reserved
+ bit 4 = 1 if multiface nmi was generated by an i/o trap (experimental, see nextreg 0xda)
+ bit 3 = 1 if multiface nmi was generated by this nextreg
+ bit 2 = 1 if divmmc nmi was generated by this nextreg
+ bit 1 = 1 if the last reset was a hard reset
+ bit 0 = 1 if the last reset was a soft reset
+ * Only one of bits 1:0 will be set
+(W)
+ bit 7 = Assert and hold reset to the expansion bus and the esp wifi (hard reset = 0)
+ bits 6:5 = Reserved must be zero
+ bit 4 = Clear i/o trap (write zero to clear) (experimental) **
+ bit 3 = Generate multiface nmi (write zero to clear) **
+ bit 2 = Generate divmmc nmi (write zero to clear) **
+ bit 1 = Generate a hard reset (reboot) *
+ bit 0 = Generate a soft reset *
+ * Hard reset has precedence
+ ** These signals are ignored if the multiface, divmmc, dma or external nmi master is active
+ ** Copper cannot clear these bits
+ ** An i/o trap could occur at the same time as mf / divmmc cause; always check this bit in nmi isr if important
+
+0x03 (03) => Machine Type
+(R)
+ bit 7 = nextreg 0x44 second byte indicator
+ bits 6:4 = Display timing
+ bit 3 = User lock on display timing applied
+ bits 2-0 = Machine type
+(W)
+ A write to this register disables the bootrom
+ bit 7 = 1 to allow changes to bits 6:4
+ bits 6:4 = Selects display timing
+ affects port decoding and contention
+ 000 = Internal Use
+ 001 = ZX 48K display timing
+ 010 = ZX 128K/+2 display timing
+ 011 = ZX +2A/+2B/+3 display timing
+ 100 = Pentagon display timing (changes to 50 Hz)
+ bit 3 = 1 to toggle user lock on display timing (hard reset = 0)
+ bits 2:0 = Selects machine type (config mode only)
+ determines roms loaded
+ 000 = Configuration mode
+ 001 = ZX 48K
+ 010 = ZX 128K/+2
+ 011 = ZX +2A/+2B/+3
+ 100 = Pentagon
+
+0x04 (04) => Config Mapping (config mode only, bootrom disabled)
+(W)
+ bit 7 = Reserved, must be 0
+ bits 6:0 = 16K SRAM bank mapped to 0x0000-0x3FFF (hard reset = 0)
+ ** Even multiplies of 256K are unreliable if storing data in sram for the next core started.
+
+0x05 (05) => Peripheral 1 Setting
+(R/W)
+ bits 7:6 = Joystick 1 mode (LSB)
+ bits 5:4 = Joystick 2 mode (LSB)
+ bit 3 = Joystick 1 mode (MSB)
+ bit 2 = 50/60 Hz mode (0 = 50Hz, 1 = 60Hz, Pentagon forces 50Hz)
+ bit 1 = Joystick 2 mode (MSB)
+ bit 0 = Enable scandoubler (1 = enabled for vga, 0 for crt)
+Joystick modes:
+ 000 = Sinclair 2 (12345)
+ 001 = Kempston 1 (port 0x1F)
+ 010 = Cursor (56780)
+ 011 = Sinclair 1 (67890)
+ 100 = Kempston 2 (port 0x37)
+ 101 = MD 1 (3 or 6 button joystick port 0x1F)
+ 110 = MD 2 (3 or 6 button joystick port 0x37)
+ 111 = User Defined Keys Joystick
+ * Joysticks can be placed in i/o mode via nextreg 0x0B.
+ * Programming the user defined keys joystick is done through the ps2 keymap interface
+ on nextreg 0x28, 0x29 and 0x2B:
+ 1. Write 128 to nextreg 0x28
+ 2. Write 0 (left joystick) or 16 (right joystick) to nextreg 0x29
+ 3. Write twelve bytes to nextreg 0x2B in order. The bytes correspond to the twelve
+ buttons on an md pad (MODE=11 X Z Y START A C B U D L R=0)
+ 4. Each byte written identifies a key in the 8x7 membrane; bits 5:3 select the row
+ and bits 2:0 select the column with 111 meaning no action
+ * In kempston and md modes, excess buttons on a controller not read via ports will
+ generate key input if so programmed
+
+0x06 (06) => Peripheral 2 Setting
+(R/W)
+ bit 7 = Enable F8 cpu speed hotkey and F5/F6 expansion bus hotkeys (soft reset = 1)
+ bit 6 = Divert BEEP only to internal speaker (hard reset = 0)
+ bit 5 = Enable F3 50/60 Hz hotkey (soft reset = 1)
+ bit 4 = Enable divmmc nmi by DRIVE button (hard reset = 0)
+ bit 3 = Enable multiface nmi by M1 button (hard reset = 0)
+ bit 2 = PS/2 mode (0 = keyboard primary, 1 = mouse primary; config mode only)
+ bits 1-0 = Audio chip mode (00 = YM, 01 = AY, 10 = ZXN-8950, 11 = Hold all AY in reset)
+
+0x07 (07) => CPU Speed
+(R)
+ bits 7:6 = Reserved
+ bits 5:4 = Current actual cpu speed
+ bits 3:2 = Reserved
+ bits 1:0 = Programmed cpu speed
+(W)
+ bits 7:2 = Reserved, must be 0
+ bits 1:0 = Set cpu speed (soft reset = 00)
+ 00 = 3.5 MHz
+ 01 = 7 MHz
+ 10 = 14 MHz
+ 11 = 28 MHz
+
+0x08 (08) => Peripheral 3 Setting
+(R/W)
+ bit 7 = Unlock port 0x7ffd (read 1 indicates port 0x7ffd is not locked)
+ bit 6 = Disable ram and port contention (soft reset = 0)
+ bit 5 = AY stereo mode (0 = ABC, 1 = ACB) (hard reset = 0)
+ bit 4 = Enable internal speaker (hard reset = 1)
+ bit 3 = Enable 8-bit DACs (A,B,C,D) (hard reset = 0)
+ bit 2 = Enable port 0xff Timex video mode read (hides floating bus on 0xff) (hard reset = 0)
+ bit 1 = Enable turbosound (currently selected AY is frozen when disabled) (hard reset = 0)
+ bit 0 = Implement issue 2 keyboard (hard reset = 0)
+
+0x09 (09) => Peripheral 4 Setting
+(R/W)
+ bit 7 = Place AY 2 in mono mode (hard reset = 0)
+ bit 6 = Place AY 1 in mono mode (hard reset = 0)
+ bit 5 = Place AY 0 in mono mode (hard reset = 0)
+ bit 4 = Sprite id lockstep (nextreg 0x34 and port 0x303B are in lockstep) (soft reset = 0)
+ bit 3 = Reset divmmc mapram bit (port 0xe3 bit 6) (read returns 0)
+ bit 2 = 1 to silence hdmi audio (hard reset = 0)
+ bits 1:0 = Scanline weight
+ 00 = scanlines off
+ 01 = scanlines 50%
+ 10 = scanlines 25%
+ 11 = scanlines 12.5%
+
+0x0A (10) => Peripheral 5 Setting
+(R/W)
+ bit 7:6 = Multiface type (hard reset = 00) (config mode only)
+ 00 = Multiface +3 (enable port 0x3F, disable port 0xBF)
+ 01 = Multiface 128 v87.2 (enable port 0xBF, disable port 0x3F)
+ 10 = Multiface 128 v87.12 (enable port 0x9F, disable port 0x1F)
+ 11 = Multiface 1 (enable port 0x9F, disable port 0x1F)
+ bit 5 = Reserved, must be zero
+ bit 4 = Enable divmmc automap (hard reset = 0)
+ bit 3 = 1 to reverse left and right mouse buttons (hard reset = 0)
+ bit 2 = Reserved, must be zero
+ bits 1:0 = mouse dpi (hard reset = 01)
+ 00 = low dpi
+ 01 = default
+ 10 = medium dpi
+ 11 = high dpi
+
+0x0B (11) => Joystick I/O Mode
+(R/W) (soft reset = 0x01)
+ bit 7 = 1 to enable i/o mode
+ bit 6 = Reserved, must be 0
+ bits 5:4 = I/O Mode
+ 00 = bit bang
+ 01 = clock
+ 10 = uart on left joystick port
+ 11 = uart on right joystick port
+ bits 3:1 = Reserved, must be 0
+ bit 0 = Parameter
+ bit bang : copied to pin 7
+ clock : 0 = hold high when clock becomes high, 1 = run *
+ uart : 0 = redirect esp uart0 to joystick, 1 = redirect pi uart1 to joystick
+ (Tx out on pin 7, Rx in from pin 9, CTS_n in from pin 6 **)
+ The state of output pin 7 is stored internally in a register and is retained across changing
+ modes and while i/o mode is disabled. While in i/o mode, keyboard joystick types (Sinclair,
+ Cursor, etc) produce no readings but the current state of pins can still be read via the
+ Kempston ports. When leaving i/o mode, joystick operation resumes after ~64 scan lines
+ have passed.
+ * CTC channel 3 is currently used to drive pin 7 in clock mode. Freq = Fctc3 / 2.
+ ** CTS_n is only active if the seleced uart is in hw flow control mode.
+
+0x0E (14) => Core Version (sub minor number)
+(R)
+ (see register 0x01 for the major and minor version number)
+
+0x0F (15) => Board ID
+(R)
+ bits 7:4 = Reserved, 0
+ bits 3:0 = Board ID
+ 0000 = ZXN Issue 2, XC6SLX16-2FTG256, 128Mbit W25Q128JV, 24bit spi, 64K*8 core size
+ 0001 = ZXN Issue 3, XC6SLX16-2FTG256, 128Mbit W25Q128JV, 24bit spi, 64K*8 core size
+ 0010 = ZXN Issue 4, XC7A15T-1CSG324, 256Mbit MX25L25645G, 32bit spi, 64K*34 core size
+
+0x10 (16) => Core Boot
+(R)
+ bit 7 = Reserved
+ bits 6:2 = Cored ID
+ bit 1 = Button DRIVE (divmmc) is pressed
+ bit 0 = Button M1 (multiface) is pressed
+(W)
+ bit 7 = Start selected core
+ bits 6:5 = Reserved, must be 0
+ bits 4:0 = Core ID 0-31 (config mode only) *
+ * A write of an out of range core id is ignored; this is the preferred way to determine max id
+
+0x11 (17) => Video Timing (writable in config mode only)
+(R/W)
+ bits 7:3 = Reserved, must be 0
+ bits 2:0 = Mode (VGA = 0..6, HDMI = 7)
+ 000 = Base VGA timing, clk28 = 28000000 \ HDMI compatible
+ 001 = VGA setting 1, clk28 = 28571429 / HDMI compatible
+ 010 = VGA setting 2, clk28 = 29464286
+ 011 = VGA setting 3, clk28 = 30000000
+ 100 = VGA setting 4, clk28 = 31000000
+ 101 = VGA setting 5, clk28 = 32000000
+ 110 = VGA setting 6, clk28 = 33000000
+ * 50/60Hz selection depends on bit 2 of nextreg 0x05
+
+0x12 (18) => Layer 2 Active RAM bank
+(R/W)
+ bit 7 = Reserved, must be 0
+ bits 6:0 = Starting 16K RAM bank (soft reset = 8)
+
+0x13 (19) => Layer 2 Shadow RAM bank
+(R/W)
+ bit 7 = Reserved, must be 0
+ bits 6:0 = Starting 16K RAM bank (soft reset = 11)
+
+0x14 (20) => Global Transparency Colour
+(R/W)
+ bits 7:0 = Transparency colour value (soft reset = 0xe3)
+ * Note: This value is 8-bit, so the transparency colour is compared against
+ the MSB bits of the final 9-bit colour only.
+ * Note: This colour only applies to Layer 2, ULA and LoRes.
+ Sprites use nextreg 0x4B and the tilemap uses nextreg 0x4C for transparency except in text mode
+
+0x15 (21) => Sprite and Layers System
+(R/W)
+ bit 7 = Enable lores mode (soft reset = 0)
+ bit 6 = Sprite priority (1 = sprite 0 on top, 0 = sprite 127 on top) (soft reset = 0)
+ bit 5 = Enable sprite clipping in over border mode (soft reset = 0)
+ bits 4:2 = Set layer priority (eg SLU = sprites over layer 2 over ula) (soft reset = 000)
+ 000 - S L U
+ 001 - L S U
+ 010 - S U L
+ 011 - L U S
+ 100 - U S L
+ 101 - U L S
+ 110 - (U|T)S(T|U)(B+L) Blending layer and Layer 2 combined, colours clamped to [0,7]
+ 111 - (U|T)S(T|U)(B+L-5) Blending layer and Layer 2 combined, colours clamped to [0,7]
+ bit 1 = Enable sprites over border (soft reset = 0)
+ bit 0 = Enable sprites (soft reset = 0)
+
+0x16 (22) => Layer2 X Scroll LSB
+(R/W)
+ bits 7:0 = X Offset (0-255) (soft reset = 0)
+
+0x17 (23) => Layer2 Y Scroll
+(R/W)
+ bits 7:0 = Y Offset (limited to 0-191 when vertical resolution is 192 pixels) (soft reset = 0)
+
+0x18 (24) => Clip Window Layer 2
+(R/W)
+ bits 7:0 = Clip window coordinate (inclusive)
+ 1st write - X1 position (soft reset = 0)
+ 2nd write - X2 position (soft reset = 255)
+ 3rd write - Y1 position (soft reset = 0)
+ 4rd write - Y2 position (soft reset = 191)
+ Reads do not advance the clip position
+
+0x19 (25) => Clip Window Sprites
+(R/W)
+ bits 7:0 = Clip window coordinate (inclusive)
+ 1st write - X1 position (soft reset = 0)
+ 2nd write - X2 position (soft reset = 255)
+ 3rd write - Y1 position (soft reset = 0)
+ 4rd write - Y2 position (soft reset = 191)
+ Reads do not advance the clip position
+ When the clip window is enabled for sprites in "over border" mode,
+ the X coords are internally doubled and the clip window origin is
+ moved to the sprite origin inside the border.
+
+0x1A (26) => Clip Window ULA (and LoRes, see note)
+(R/W)
+ bits 7:0 = Clip window coordinate (inclusive)
+ 1st write = X1 position (soft reset = 0)
+ 2nd write = X2 position (soft reset = 255)
+ 3rd write = Y1 position (soft reset = 0)
+ 4rd write = Y2 position (soft reset = 191)
+ Reads do not advance the clip position
+ LoRes may get a separate clip window in the future
+
+0x1B (27) => Clip Window Tilemap
+(R/W)
+ bits 7:0 = Clip window coordinate (inclusive)
+ 1st write = X1 position (soft reset = 0)
+ 2nd write = X2 position (soft reset = 159)
+ 3rd write = Y1 position (soft reset = 0)
+ 4rd write = Y2 position (soft reset = 255)
+ Reads do not advance the clip position
+ The X coordinates are internally doubled.
+
+0x1C (28) => Clip Window control
+(R) (may change)
+ bits 7:6 = Tilemap clip index
+ bits 5:4 = ULA/Lores clip index
+ bits 3:2 = Sprite clip index
+ bits 1:0 = Layer 2 clip index
+(W) (may change)
+ bits 7:4 = Reserved, must be 0
+ bit 3 = Reset the tilemap clip index
+ bit 2 = Reset the ULA/LoRes clip index
+ bit 1 = Reset the sprite clip index
+ bit 0 = Reset the Layer 2 clip index
+
+0x1E (30) => Active video line (MSB)
+(R)
+ bits 7:1 = Reserved
+ bit 0 = Active line MSB
+
+0x1F (31) => Active video line (LSB)
+(R)
+ bits 7:0 = Active line LSB
+
+0x20 (32) => Generate Maskable Interrupt
+(R/W)
+ bit 7 = line
+ bit 6 = ula
+ bits 5:4 = reserved
+ bits 3:0 = ctc 3:0
+ * Set bits on R indicate whether an interrupt occurred or is pending (alias of bits in NR 0xC8 - 0xCA)
+ * Set bits on W always generate a maskable interrupt ignoring enables (NR 0xC4 - 0xC6)
+
+0x22 (34) => Line Interrupt control
+(R/W)
+ bit 7 = (R) Indicates if the ula is asserting an interrupt (even if disabled)
+ bits 7:3 = Reserved, must be 0
+ bit 2 = Disables ula interrupt (soft reset = 0) **
+ bit 1 = Enables line Interrupt (soft reset = 0) **
+ bit 0 = MSB of line interrupt value (soft reset = 0)
+ ** Aliases of interrupt enable bits in nextreg 0xC4
+
+0x23 (35) => Line Interrupt Value LSB
+(R/W)
+ bits 7:0 = Line Interrupt value LSB (soft reset = 0)
+
+0x24 (36) => Reserved
+ Protection against "OUT (0x3B),A", see Disciple Disk Interface for example
+ In legacy modes set selected nextreg to 0x24
+
+0x26 (38) => ULA X Scroll
+(R/W)
+ bits 7:0 = X Offset (0-255) (soft reset = 0)
+
+0x27 (39) => ULA Y Scroll
+(R/W)
+ bits 7:0 = Y Offset (0-191) (soft reset = 0)
+
+0x28 (40) => PS/2 Keymap Address MSB
+(R)
+ bits 7:0 = Stored palette value from nextreg 0x44
+(W)
+ bit 7 = 0 to select ps2 keymap, 1 to select key joystick
+ bits 6:1 = Reserved, must be 0
+ bit 0 = MSB address
+
+0x29 (41) => PS/2 Keymap Address LSB
+(W)
+ bits 7:0 = LSB adress
+
+0x2A (42) => PS/2 Keymap Data MSB
+(W)
+ bits 7:1 = Reserved, must be 0
+ bit 0 = MSB data
+ * Not currently used by hardware, write 0
+
+0x2B (43) => PS/2 Keymap Data LSB
+(W) (write causes the data to be written and auto-increments the keymap address)
+ bits 7:0 = LSB data
+
+0x2C (44) => DAC B Mirror (left)
+(R)
+ bits 7:0 = MSB of current I2S (pi) left side sample
+ the LSB is latched and can be read from nextreg 0x2D later
+(W)
+ bits 7:0 = 8-bit sample written to left side DAC B (soft reset = 0x80)
+
+0x2D (45) => DAC A+D Mirror (mono)
+(R)
+ bits 7:0 = LSB of last I2S (pi) sample read from nextreg 0x2C or nextreg 0x2E
+(W)
+ bits 7:0 = 8-bit sample written to DACs A and D (soft reset = 0x80)
+
+0x2E (46) => DAC C Mirror (right)
+(R)
+ bits 7:0 = MSB of current I2S (pi) right side sample
+ the LSB is latched and can be read from nextreg 0x2D later
+(W)
+ bits 7:0 = 8-bit sample written to right side DAC C (soft reset = 0x80)
+
+0x2F (47) => Tilemap X Scroll MSB
+(R/W)
+ bits 7:2 = Reserved, must be 0
+ bits 1:0 = MSB X Offset (soft reset = 0)
+ Meaningful Range is 0-319 in 40 char mode, 0-639 in 80 char mode
+
+0x30 (48) => Tilemap X Scroll LSB
+(R/W)
+ bits 7:0 = LSB X Offset (soft reset = 0)
+ Meaningful range is 0-319 in 40 char mode, 0-639 in 80 char mode
+
+0x31 (49) => Tilemap Offset Y
+(R/W)
+ bits 7:0 = Y Offset (0-255) (soft reset = 0)
+
+0x32 (50) => LoRes X Scroll
+(R/W)
+ bits 7:0 = X Offset (0-255) (soft reset = 0)
+ LoRes scrolls in "half-pixels" at the same resolution and smoothness as Layer 2.
+
+0x33 (51) => LoRes Y Scroll
+(R/W)
+ bits 7:0 = Y Offset (0-191) (soft reset = 0)
+ LoRes scrolls in "half-pixels" at the same resolution and smoothness as Layer 2.
+
+0x34 (52) => Sprite Number
+(R/W)
+ If the sprite number is in lockstep with port 0x303B (nextreg 0x09 bit 4 is set)
+ bit 7 = Pattern address offset (add 128 to pattern address)
+ bits 6:0 = Sprite number 0-127, Pattern number 0-63
+ Selects which sprite has its attributes connected to the following registers.
+ Effectively performs an out to port 0x303B with the same value
+ Otherwise
+ bit 7 = Ignored
+ bits 6:0 = Sprite number 0-127
+ Selects which sprite has its attributes connected to the following registers.
+ Bit 7 always reads back as zero.
+
+0x35 (53) => Sprite Attribute 0
+0x75 (117) => Sprite Attribute 0 with automatic post increment of Sprite Number
+(W)
+ See documentation at https://www.specnext.com/sprites/
+
+0x36 (54) => Sprite Attribute 1
+0x76 (118) => Sprite Attribute 1 with automatic post increment of Sprite Number
+(W)
+ See documentation at https://www.specnext.com/sprites/
+
+0x37 (55) => Sprite Attribute 2
+0x77 (119) => Sprite Attribute 2 with automatic post increment of Sprite Number
+(W)
+ See documentation at https://www.specnext.com/sprites/
+
+0x38 (56) => Sprite Attribute 3
+0x78 (120) => Sprite Attribute 3 with automatic post increment of Sprite Number
+(W)
+ See documentation at https://www.specnext.com/sprites/
+
+0x39 (57) => Sprite Attribute 4
+0x79 (121) => Sprite Attribute 4 with automatic post increment of Sprite Number
+(W)
+ See documentation at https://www.specnext.com/sprites/
+
+0x40 (64) => Palette Index
+(R/W)
+ bits 7:0 = Select the palette index to change the associated colour. (soft reset = 0)
+ For the ULA only, INKs are mapped to indices 0-7, Bright INKS to indices 8-15,
+ PAPERs to indices 16-23 and Bright PAPERs to indices 24-31.
+ In ULANext mode, INKs come from a subset of indices 0-127 and PAPERs come from
+ a subset of indices 128-255. The number of active indices depends on the number
+ of attribute bits assigned to INK and PAPER out of the attribute byte.
+ In ULA+ mode, the top 64 entries hold the ula+ palette.
+ The ULA always takes border colour from paper for standard ULA and ULAnext.
+
+0x41 (65) => Palette Value (8 bit colour)
+(R/W)
+ bits 7:0 = Colour for the palette index selected by nextreg 0x40.
+ The format is RRRGGGBB - the lower blue bit of the 9-bit colour will be the logical
+ OR of blue bits 1 and 0 of this 8-bit value.
+ After the write, the palette index is auto-incremented to the next index if the
+ auto-increment is enabled in nextreg 0x43. Reads do not auto-increment.
+ Any other bits associated with the index will be zeroed.
+
+0x42 (66) => ULANext Attribute Byte Format
+(R/W)
+ bits 7:0 = Mask indicating which bits of an attribute byte are used to represent INK.
+ Other bits represent PAPER. (soft reset = 0x07)
+ The mask can only indicate a solid sequence of bits on the right side of an attribute
+ byte (1, 3, 7, 15, 31, 63, 127 or 255).
+ INKs are mapped to base index 0 in the palette and PAPERs and border are
+ mapped to base index 128 in the palette.
+ The 255 value enables the full ink colour mode making all the palette entries INK.
+ In this case PAPER and border are both taken from the fallback colour in nextreg 0x4A.
+ If the mask is not one of those listed above, the INK is taken as the logical AND of
+ the mask with the attribute byte and the PAPER and border colour are again both taken
+ from the fallback colour in nextreg 0x4A.
+
+0x43 (67) => Palette Control
+(R/W)
+ bit 7 = Disable palette write auto-increment (soft reset = 0)
+ bits 6-4 = Select palette for reading or writing (soft reset = 000)
+ 000 = ULA first palette
+ 100 = ULA second palette
+ 001 = Layer 2 first palette
+ 101 = Layer 2 second palette
+ 010 = Sprites first palette
+ 110 = Sprites second palette
+ 011 = Tilemap first palette
+ 111 = Tilemap second palette
+ bit 3 = Select Sprites palette (0 = first palette, 1 = second palette) (soft reset = 0)
+ bit 2 = Select Layer 2 palette (0 = first palette, 1 = second palette) (soft reset = 0)
+ bit 1 = Select ULA palette (0 = first palette, 1 = second palette) (soft reset = 0)
+ bit 0 = Enabe ULANext mode (soft reset = 0)
+
+0x44 (68) => Palette Value (9 bit colour)
+(R/W)
+ Two consecutive writes are needed to write the 9 bit colour
+ 1st write:
+ bits 7:0 = RRRGGGBB
+ 2nd write:
+ bits 7:1 = Reserved, must be 0
+ bit 0 = lsb B
+ If writing to an L2 palette
+ bit 7 = 1 for L2 priority colour, 0 for normal.
+ An L2 priority colour moves L2 above all layers. If you need the same
+ colour in both priority and normal modes, you will need to have two
+ different entries with the same colour one with and one without priority.
+ After two consecutive writes the palette index is auto-incremented if
+ auto-increment is enabled in nextreg 0x43.
+ Reads only return the 2nd byte and do not auto-increment.
+ Writes to nextreg 0x40, 0x41, 0x43 reset to the 1st write.
+
+0x4A (74) => Fallback Colour
+(R/W)
+ bits 7:0 = 8-bit colour used if all layers are transparent (soft reset = 0xe3)
+
+0x4B (75) => Sprite Transparency Index
+(R/W)
+ bits 7:0 = Sprite colour index treated as transparent (soft reset = 0xe3)
+ For 4-bit sprites only the bottom 4-bits are used
+
+0x4C (76) => Tilemap Transparency Index
+(R/W)
+ bits 7-4 = Reserved, must be 0
+ bits 3-0 = Tilemap colour index treated as transparent (soft reset = 0xf)
+
+0x50 (80) => MMU slot 0
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0x0000 - 0x1FFF (soft reset = 255)
+ Pages range from 0 to 223 on a fully expanded Next.
+ A 255 value causes the ROM to become visible.
+
+0x51 (81) => MMU slot 1
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0x2000 - 0x3FFF (soft reset = 255)
+ Pages range from 0 to 223 on a fully expanded Next.
+ A 255 value causes the ROM to become visible.
+
+0x52 (82) => MMU slot 2
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0x4000 - 0x5FFF (soft reset = 10)
+ Pages range from 0 to 223 on a fully expanded Next.
+
+0x53 (83) => MMU slot 3
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0x6000 - 0x7FFF (soft reset = 11)
+ Pages range from 0 to 223 on a fully expanded Next.
+
+0x54 (84) => MMU slot 4
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0x8000 - 0x9FFF (soft reset = 4)
+ Pages range from 0 to 223 on a fully expanded Next.
+
+0x55 (85) => MMU slot 5
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0xA000 - 0xBFFF (soft reset = 5)
+ Pages range from 0 to 223 on a fully expanded Next.
+
+0x56 (86) => MMU slot 6
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0xC000 - 0xDFFF (soft reset = 0)
+ Pages range from 0 to 223 on a fully expanded Next.
+
+0x57 (87) => MMU slot 7
+(R/W)
+ bits 7:0 = 8K RAM page occupying address 0xE000 - 0xFFFF (soft reset = 1)
+ Pages range from 0 to 223 on a fully expanded Next.
+
+0x60 (96) => Copper Data 8-bit Write
+(W)
+ bits 7:0 = Byte to write to copper instruction memory
+ Note that each copper instruction is two bytes long
+ After a write, the copper address is auto-incremented to the next memory position
+
+0x61 (97) => Copper Address LSB
+(R/W)
+ bits 7:0 = Copper instruction memory address LSB (soft reset = 0)
+ (Copper addresses range over 0 - 0x7FF = 2K)
+
+0x62 (98) => Copper Control
+(R/W)
+ bits 7:6 = Start control (soft reset = 00)
+ 00 = Copper fully stopped
+ 01 = Copper start, execute the list from index 0, and loop to the start
+ 10 = Copper start, execute the list from last point, and loop to the start
+ 11 = Copper start, execute the list from index 0, and restart the list
+ when the raster reaches position (0,0)
+ bits 2:0 = Copper instruction memory address MSB (soft reset = 0)
+ (Copper addresses range over 0 - 0x7FF = 2K)
+ Writing the same start control value does not reset the copper
+
+0x63 (99) => Copper Data 16-bit Write
+(W)
+ The 16-bit value is written in pairs. The first 8-bits are the MSB and
+ are destined for an even copper instruction address. The second 8-bits are
+ the LSB and are destined for an odd copper instruction address.
+ After each write, the copper address is auto-incremented to the next memory position
+ After a write to an odd address, the entire 16-bits is written to copper memory at once
+
+0x64 (100) => Vertical Line Count Offset
+(R/W)
+ bits 7:0 = Offset added to the vertical line counter affects copper, line interrupt and active line count.
+ Normally the ula's pixel row 0 aligns with vertical line count 0. With a non-zero
+ offset, the ula's pixel row 0 will align with the vertical line offset. Eg, if the offset is 32
+ then vertical line 32 will correspond to the first pixel row in the ula and vertical line 0
+ will align with the first pixel row of the tilemap and sprites.
+ * Since a change in offset takes effect when the ula reaches row 0, the change can take up to
+ one frame to occur.
+
+0x68 (104) => ULA Control
+(R/W)
+ bit 7 = Disable ULA output (soft reset = 0)
+ bits 6:5 = Blending in SLU modes 6 & 7 (soft reset = 0)
+ = 00 for ula as blend colour
+ = 10 for ula/tilemap mix result as blend colour
+ = 11 for tilemap as blend colour
+ = 01 for no blending
+ bit 4 = Cancel entries in 8x5 matrix for extended keys
+ bit 3 = ULA+ enable (soft reset = 0)
+ bit 2 = ULA half pixel scroll (may change) (soft reset = 0)
+ bit 1 = Reserved, must be 0
+ bit 0 = Enable stencil mode when both the ULA and tilemap are enabled (soft reset = 0)
+ (if either are transparent the result is transparent otherwise the result is a logical AND of both colours)
+
+0x69 (105) => Display Control 1
+(R/W)
+ bit 7 = Enable layer 2 (alias port 0x123B bit 1)
+ bit 6 = Enable ULA shadow display (alias port 0x7FFD bit 3)
+ bits 5:0 = Port 0xFF bits 5:0 alias (Timex display modes)
+
+0x6A (106) => LoRes Control
+(R/W)
+ bits 7-6 = Reserved, must be 0
+ bit 5 = LoRes is Radastan mode (128x96x4, 6144 bytes) (soft reset = 0)
+ bit 4 = LoRes Radastan timex display file xor (soft reset = 0)
+ bits 3:0 = LoRes palette offset (bits 1:0 apply in ula+ mode) (soft reset = 0)
+
+0x6B (107) => Tilemap Control
+(R/W)
+ bit 7 = 1 Enable the tilemap (soft reset = 0)
+ bit 6 = 0 for 40x32, 1 for 80x32 (soft reset = 0)
+ bit 5 = Eliminate the attribute entry in the tilemap (soft reset = 0)
+ bit 4 = Palette select (soft reset = 0)
+ bit 3 = Select textmode (soft reset = 0)
+ bit 2 = Reserved, must be 0
+ bit 1 = Activate 512 tile mode (soft reset = 0)
+ bit 0 = Force tilemap on top of ULA (soft reset = 0)
+
+0x6C (108) => Default Tilemap Attribute
+(R/W)
+ Active if nextreg 0x6B bit 5 is set
+ bits 7:4 = Palette offset (soft reset = 0)
+ bit 3 = X mirror (soft reset = 0)
+ bit 2 = Y mirror (soft reset = 0)
+ bit 1 = Rotate (soft reset = 0)
+ bit 0 = ULA over tilemap (soft reset = 0)
+ (or bit 8 of the tile number if 512 tile mode is enabled)
+
+0x6E (110) => Tilemap Base Address
+(R/W) (soft reset = 0x6c00)
+ bit 7 = 1 to select bank 7, 0 to select bank 5
+ bit 6 = Reserved, must be 0
+ bits 5:0 = MSB of address of the tilemap in Bank 5
+ The value written into bits 5:0 is an offset into 16K bank 5 or 8K bank 7
+ allowing the tilemap to be placed at any multiple of 256 bytes. The value
+ written here can be thought of as the MSB of an address in bank 5 0x40-0x7f
+ or bank 7 0xc0-0xff. Because bank 7 is only 8K in size, addresses wrap
+ across the 8K boundary instead of the 16K boundary.
+
+0x6F (111) => Tile Definitions Base Address
+(R/W) (soft reset = 0x4c00)
+ bit 7 = 1 to select bank 7, 0 to select bank 5
+ bit 6 = Reserved, must be 0
+ bits 5:0 = MSB of address of tile definitions in Bank 5
+ The value written into bits 5:0 is an offset into 16K bank 5 or 8K bank 7
+ allowing the tile definitions to be placed at any multiple of 256 bytes. The
+ value written here can be thought of as the MSB of an address in bank 5
+ 0x40-0x7f or bank 7 0xc0-0xff. Because bank 7 is only 8K in size, addresses
+ wrap across the 8K boundary instead of the 16K boundary.
+
+0x70 (112) => Layer 2 Control
+(R/W)
+ bits 7:6 = Reserved, must be 0
+ bits 5:4 = Layer 2 resolution (soft reset = 0)
+ 00 = 256x192x8
+ 01 = 320x256x8
+ 10 = 640x256x4
+ bits 3:0 = Palette offset (soft reset = 0)
+
+0x71 (113) => Layer 2 X Scroll MSB
+(R/W)
+ bits 7:1 = Reserved, must be 0
+ bit 0 = MSB of scroll amount
+
+0x75 (117) => Sprite Attribute 0 with automatic post increment of Sprite Number
+(W)
+ see nextreg 0x35
+
+0x76 (118) => Sprite Attribute 1 with automatic post increment of Sprite Number
+(W)
+ see nextreg 0x36
+
+0x77 (119) => Sprite Attribute 2 with automatic post increment of Sprite Number
+(W)
+ see nextreg 0x37
+
+0x78 (120) => Sprite Attribute 3 with automatic post increment of Sprite Number
+(W)
+ see nextreg 0x38
+
+0x79 (121) => Sprite Attribute 4 with automatic post increment of Sprite Number
+(W)
+ see nextreg 0x39
+
+0x7F (127) => User Register 0
+(R/W)
+ bits 7:0 = Unused storage available to the user (soft reset = 0xff)
+
+0x80 (128) => Expansion Bus Enable
+(R/W) (hard reset = 0)
+ IMMEDIATE
+ bit 7 = 1 to enable the expansion bus
+ bit 6 = 1 to enable romcs rom replacement from divmmc banks 14/15
+ bit 5 = 1 to disable i/o cycles & ignore iorqula
+ bit 4 = 1 to disable memory cycles & ignore romcs
+ AFTER SOFT RESET (copied into bits 7-4)
+ bit 3 = 1 to enable the expansion bus
+ bit 2 = 1 to enable romcs rom replacement from divmmc banks 14/15
+ bit 1 = 1 to disable i/o cycles & ignore iorqula
+ bit 0 = 1 to disable memory cycles & ignore romcs
+
+0x81 (129) => Expansion Bus Control
+(R/W) (hard reset = 0)
+ bit 7 = 1 if ROMCS is asserted on the expansion bus (read only)
+ bit 6 = 1 to allow peripherals to override the ULA on some even port reads (rotronics wafadrive)
+ bit 5 = 1 to disable expansion bus nmi debounce (opus discovery)
+ bit 4 = 1 to propagate the max cpu clock at all times including when the expansion bus is off
+ bits 1-0 = max cpu speed when the expansion bus is on (currently fixed at 00 = 3.5MHz)
+
+0x85,0x84,0x83,0x82 (133-130) => Internal Port Decoding Enables (0x85 is MSB) (soft reset if bit 31 = 1, hard reset if bit 31 = 0 : all 1)
+0x89,0x88,0x87,0x86 (137-134) => Expansion Bus Decoding Enables (0x89 is MSB) (soft reset if bit 31 = 0, hard reset if bit 31 = 1 : all 1)
+(R/W)
+ bit 0 = port ff
+ bit 1 = port 7ffd
+ bit 2 = port dffd
+ bit 3 = port 1ffd
+ bit 4 = +3 floating bus
+ bit 5 = port 6b zxn dma
+ bit 6 = port 1f kempston / md1
+ bit 7 = port 37 kempston 2 / md2
+ -----
+ bit 8 = port e3 divmmc control
+ bit 9 = multiface (two variable ports)
+ bit 10 = port 103b,113b i2c
+ bit 11 = port e7,eb spi
+ bit 12 = port 133b,143b,153b,163b uart
+ bit 13 = port fadf,fbdf,ffdf mouse (also disables kempston alias on port df)
+ bit 14 = port 57,5b,303b sprites
+ bit 15 = port 123b layer2
+ -----
+ bit 16 = port fffd,bffd ay
+ bit 17 = port 0f,1f,4f,5f dac soundrive mode 1
+ bit 18 = port f1,f3,f9,fb dac soundrive mode 2
+ bit 19 = port 3f,5f dac stereo profi covox
+ bit 20 = port 0f,4f dac stereo covox
+ bit 21 = port fb dac mono pentagon/atm (sd mode 2 off)
+ bit 22 = port b3 dac mono gs covox
+ bit 23 = port df dac mono specdrum, port 1f kempston alias
+ -----
+ bit 24 = port bf3b,ff3b ula+
+ bit 25 = port 0b z80 dma
+ bit 26 = port eff7 pentagon 1024 memory
+ bit 27 = port 183b,193b,1a3b,1b3b,1c3b,1d3b,1e3b,1f3b z80 ctc
+ ...
+ bit 31 = register reset mode (soft or hard reset selection)
+ -----
+ The internal port decoding enables always apply.
+ When the expansion bus is on, the expansion port decoding enables are logically ANDed with the internal enables.
+ A zero bit indicates the internal device is disabled. If the expansion bus is on, this allows io cycles for
+ disabled ports to propagate to the expansion bus, otherwise corresponding io cycles to the expansion bus are filtered.
+
+0x8A (138) => Expansion Bus IO Propagate
+(R/W)
+ bits 7:6 = Reserved, must be 0
+ bit 5 = Propagate port 0xeff7 io cycles (hard reset = 0)
+ bit 4 = Propagate port 0xff io cycles (hard reset = 0)
+ bit 3 = Propagate port 0x1ffd io cycles (hard reset = 0)
+ bit 2 = Propagate port 0xdffd io cycles (hard reset = 0)
+ bit 1 = Propagate port 0x7ffd io cycles (hard reset = 0)
+ bit 0 = Propagate port 0xfe io cycles (hard reset = 0)
+ If any of the bits are set, io cycles for the corresponding ports are propagated to the expansion bus when
+ the expansion bus is on. If the internal port decode is still active, any response sent by devices on the
+ expansion bus will be ignored. The purpose here is to allow external peripherals to monitor changes in state
+ inside the zx next.
+ Port 0xfe is treated specially so that external keyboards can be attached. When its propagate bit is set,
+ the value read from the bus will be mixed into keyboard reads on port 0xfe.
+
+0x8C (140) => Alternate ROM
+(R/W) (hard reset = 0)
+ IMMEDIATE
+ bit 7 = 1 to enable alt rom
+ bit 6 = 1 to make alt rom visible only during writes, otherwise replaces rom during reads
+ bit 5 = 1 to lock ROM1 (48K rom)
+ bit 4 = 1 to lock ROM0 (128K rom)
+ AFTER SOFT RESET (copied into bits 7-4)
+ bit 3 = 1 to enable alt rom
+ bit 2 = 1 to make alt rom visible only during writes, otherwise replaces rom during reads
+ bit 1 = 1 to lock ROM1 (48K rom)
+ bit 0 = 1 to lock ROM0 (128K rom)
+ The locking mechanism also applies if the alt rom is not enabled. For the +3 and zx next, if the two lock bits are not
+ zero, then the corresponding rom page is locked in place. Other models use the bits to preferentially lock the corresponding
+ 48K rom or the 128K rom.
+
+0x8E (142) => Spectrum 128K Memory Mapping
+(R/W)
+ bit 7 = port 0xdffd bit 0 \ RAM
+ bits 6:4 = port 0x7ffd bits 2:0 / bank 0-15
+ R bit 3 = 1
+ W bit 3 = 1 to change RAM bank, 0 = no change to mmu6 / mmu7 / RAM bank in ports 0x7ffd, 0xdffd
+ bit 2 = port 0x1ffd bit 0 paging mode
+ If bit 2 = paging mode = 0 (normal)
+ bit 1 = port 0x1ffd bit 2 \ ROM
+ bit 0 = port 0x7ffd bit 4 / select
+ If bit 2 = paging mode = 1 (special allRAM)
+ bit 1 = port 0x1ffd bit 2 \ all
+ bit 0 = port 0x1ffd bit 1 / RAM
+ Writes can affect all ports 0x7ffd, 0xdffd, 0x1ffd
+ Writes always change the ROM / allRAM mapping
+ Writes immediately change the current mmu mapping as if by port write
+
+0x8F (143) => Memory Mapping Mode
+(R/W) (hard reset = 0)
+ bits 7:2 = Reserved, must be zero
+ bits 1:0 = Mapping mode applied
+ 00 = Standard ZX 128k +3
+ 01 = Reserved
+ 10 = Pentagon 512K
+ 11 = Pentagon 1024K (limited to 768K on 1MB machines)
+ * Standard ZX 128K +3 = principally ports 0x7ffd, 0xdffd, 0x1ffd
+ * Pentagon 512K = principally port 0x7ffd
+ * Pentagon 1024K = principally ports 0x7ffd, 0xeff7
+ ** The mapping modes affect how ports 0x7ffd, 0xdffd, 0x1ffd and 0xeff7 carry out memory paging, see ports.txt
+
+0x93,0x92,0x91,0x90 (147-144) => PI GPIO Output Enable (0x93 is MSB)
+(R/W)
+ bits 27:0 Set bits enable GPIO output on the corresponding GPIO pin (soft reset = all 0)
+ (GPIO pins 1:0 cannot be enabled)
+
+0x9B,0x9A,0x99,0x98 (155-152) => PI GPIO (0x9B is MSB)
+(R/W)
+ bits 27:0 Read / Write the GPIO pin state (soft reset = 0x00001ff)
+ (writes only propagate when the corresponding pin has its output enabled)
+
+0xA0 (160) => PI Peripheral Enable
+(R/W)
+ bits 7:6 = Reserved, must be 0
+ bit 5 = Enable UART on GPIO 14,15 (overrides gpio)* (soft reset = 0)
+ bit 4 = 0 to connect Rx to GPIO 15, Tx to GPIO 14 (for comm with pi hats) (soft reset = 0)
+ = 1 to connect Rx to GPIO 14, Tx to GPIO 15 (for comm with pi)
+ bit 3 = Enable I2C on GPIO 2,3 (override gpio) (soft reset = 0)
+ bits 2:1 = Reserved, must be 0
+ bit 0 = Enable SPI on GPIO 7,8,9,10,11 (overrides gpio) (soft reset = 0)
+ * GPIO 16,17 will function as rtr_n and cts_n if the uart is in hw flow control mode
+
+0xA2 (162) => PI I2S Audio Control
+(R/W)
+ bits 7:6 = I2S enable (soft reset = 00)
+ 00 = i2s off
+ 01 = i2s is mono source right
+ 10 = i2s is mono source left
+ 11 = i2s is stereo
+ bit 5 = Reserved, must be 0
+ bit 4 = 0 PCM_DOUT to pi, PCM_DIN from pi (hats) (soft reset = 0)
+ = 1 PCM_DOUT from pi, PCM_DIN to pi (pi)
+ bit 3 = Mute left side (soft reset = 0)
+ bit 2 = Mute right side (soft reset = 0)
+//bit 1 = Slave mode (PCM_CLK, PCM_FS supplied externally) (soft reset = 0)
+ bit 1 = Reserved must be 1
+ bit 0 = Direct i2s audio to EAR on port 0xFE (soft reset = 0)
+
+// 0xA3 (163) => PI I2S Clock Divide (Master Mode)
+// (R/W)
+// bits 7:0 = Clock divide sets sample rate when in master mode (soft reset = 11)
+// clock divider = 538461 / SampleRateHz - 1
+
+0xA8 (168) => ESP Wifi GPIO Output Enable
+(R/W) (soft reset = 0)
+ bit 2 = GPIO2 output enable (fixed at 0, GPIO2 is read-only)
+ bit 0 = GPIO0 output enable
+
+0xA9 (169) => ESP Wifi GPIO
+(R/W)
+ bit 2 = Read / Write ESP GPIO2 (soft reset = 1)
+ bit 0 = Read / Write ESP GPIO0 (soft reset = 1)
+
+0xB0 (176) => Extended Keys 0
+(R)
+ bit 7 = 1 if ; pressed
+ bit 6 = 1 if " pressed
+ bit 5 = 1 if , pressed
+ bit 4 = 1 if . pressed
+ bit 3 = 1 if UP pressed
+ bit 2 = 1 if DOWN pressed
+ bit 1 = 1 if LEFT pressed
+ bit 0 = 1 if RIGHT pressed
+ * Nextreg 0x68 bit 4 stops extended keys from making entries in the 8x5 matrix
+
+0xB1 (177) => Extended Keys 1
+(R)
+ bit 7 = 1 if DELETE pressed
+ bit 6 = 1 if EDIT pressed
+ bit 5 = 1 if BREAK pressed
+ bit 4 = 1 if INV VIDEO pressed
+ bit 3 = 1 if TRUE VIDEO pressed
+ bit 2 = 1 if GRAPH pressed
+ bit 1 = 1 if CAPS LOCK pressed
+ bit 0 = 1 if EXTEND pressed
+ * Nextreg 0x68 bit 4 stops extended keys from making entries in the 8x5 matrix
+
+0xB2 (178) => Extended MD Pad Buttons
+(R)
+ bit 7 = 1 if Right Pad X pressed
+ bit 6 = 1 if Right Pad Z pressed
+ bit 5 = 1 if Right Pad Y pressed
+ bit 4 = 1 if Right Pad MODE pressed
+ bit 3 = 1 if Left Pad X pressed
+ bit 2 = 1 if Left Pad Z pressed
+ bit 1 = 1 if Left Pad Y pressed
+ bit 0 = 1 if Left Pad MODE pressed
+
+0xB8 (184) => Divmmc Entry Points 0
+(R/W) (soft reset = 0x83)
+ bit 7 = 1 to enable automap on address 0x0038 (instruction fetch)
+ bit 6 = 1 to enable automap on address 0x0030 (instruction fetch)
+ bit 5 = 1 to enable automap on address 0x0028 (instruction fetch)
+ bit 4 = 1 to enable automap on address 0x0020 (instruction fetch)
+ bit 3 = 1 to enable automap on address 0x0018 (instruction fetch)
+ bit 2 = 1 to enable automap on address 0x0010 (instruction fetch)
+ bit 1 = 1 to enable automap on address 0x0008 (instruction fetch)
+ bit 0 = 1 to enable automap on address 0x0000 (instruction fetch)
+
+0xB9 (185) => Divmmc Entry Points Valid 0
+(R/W) (soft reset = 0x01)
+ bit 7 = 1 for always else only when rom3 is present (0x0038)
+ bit 6 = 1 for always else only when rom3 is present (0x0030)
+ bit 5 = 1 for always else only when rom3 is present (0x0028)
+ bit 4 = 1 for always else only when rom3 is present (0x0020)
+ bit 3 = 1 for always else only when rom3 is present (0x0018)
+ bit 2 = 1 for always else only when rom3 is present (0x0010)
+ bit 1 = 1 for always else only when rom3 is present (0x0008)
+ bit 0 = 1 for always else only when rom3 is present (0x0000)
+
+0xBA (186) => Divmmc Entry Points Timing 0
+(R/W) (soft reset = 0x00)
+ bit 7 = 1 for instant mapping else delayed (0x0038)
+ bit 6 = 1 for instant mapping else delayed (0x0030)
+ bit 5 = 1 for instant mapping else delayed (0x0028)
+ bit 4 = 1 for instant mapping else delayed (0x0020)
+ bit 3 = 1 for instant mapping else delayed (0x0018)
+ bit 2 = 1 for instant mapping else delayed (0x0010)
+ bit 1 = 1 for instant mapping else delayed (0x0008)
+ bit 0 = 1 for instant mapping else delayed (0x0000)
+
+0xBB (187) => Divmmc Entry Points 1
+(R/W) (soft reset = 0xCD)
+ bit 7 = 1 to enable automap on addresses 0x3DXX (instruction fetch, instant, ROM3) > TRDOS
+ bit 6 = 1 to disable automap on addresses 0x1FF8-0x1FFF (instruction fetch, delayed)
+ bit 5 = 1 to enable automap on address 0x056A (instruction fetch, delayed, ROM3) \ tape traps
+ bit 4 = 1 to enable automap on address 0x04D7 (instruction fetch, delayed, ROM3) / nextzxos (better compatibility)
+ bit 3 = 1 to enable automap on address 0x0562 (instruction fetch, delayed, ROM3) \ tape traps
+ bit 2 = 1 to enable automap on address 0x04C6 (instruction fetch, delayed, ROM3) / esxdos + original divmmc
+ bit 1 = 1 to enable automap on address 0x0066 (instruction fetch + button, instant)
+ bit 0 = 1 to enable automap on address 0x0066 (instruction fetch + button, delayed)
+
+// INTERRUPTS
+
+0xC0 (192) => Interrupt Control
+(R/W) (soft reset = 0)
+ bits 7:5 = Programmable portion of im2 vector*
+ bit 4 = Reserved must be 0
+ bit 3 = Enable stackless nmi response**
+ bits 2:1 = Current Z80 interrupt mode 0,1,2 (read only, write ignored)
+ bit 0 = Maskable interrupt mode: pulse (0) or hw im2 mode (1)
+ * In hw im2 mode the interrupt vector generated is:
+ bits 7:5 = nextreg 0xC0 bits 7:5
+ bits 4:1 = 0 line interrupt (highest priority)
+ = 1 uart0 Rx
+ = 2 uart1 Rx
+ = 3-10 ctc channels 0-7
+ = 11 ula
+ = 12 uart0 Tx
+ = 13 uart1 Tx (lowest priority)
+ bit 0 = 0
+ * In hw im2 mode the expansion bus is the lowest priority interrupter
+ and if no vector is supplied externally then 0xFF is generated.
+ ** The return address pushed during an nmi acknowledge cycle will
+ be written to nextreg instead of memory (the stack pointer will
+ be decremented) and the first RETN after the acknowledge will
+ take its return address from nextreg instead of memory (the stack
+ pointer will be incremented). If bit 3 = 0 and in other
+ circumstances, RETN functions normally.
+
+0xC2 (194) => NMI Return Address LSB
+(R/W) (soft reset = 0)
+
+0xC3 (195) => NMI Return Address MSB
+(R/W) (soft reset = 0)
+ The return address written during an nmi acknowledge cycle is
+ always stored in these registers.
+
+--
+
+0xC4 (196) => INT EN 0
+(R/W) (soft reset = 0x81)
+ bit 7 = Expansion bus /INT
+ bits 6:2 = Reserved must be 0
+ bit 1 = Line **
+ bit 0 = ULA **
+ * If a device interrupt is disabled, it enters a polled mode
+ ** Aliases of interrupt enable bits in nextreg 0x22
+
+0xC5 (197) => INT EN 1
+(R/W) (soft reset = 0)
+ bit 7 = ctc channel 7 zc/to
+ bit 6 = ctc channel 6 zc/to
+ bit 5 = ctc channel 5 zc/to
+ bit 4 = ctc channel 4 zc/to
+ bit 3 = ctc channel 3 zc/to
+ bit 2 = ctc channel 2 zc/to
+ bit 1 = ctc channel 1 zc/to
+ bit 0 = ctc channel 0 zc/to
+ * If a device interrupt is disabled, it enters a polled mode
+
+
+0xC6 (198) => INT EN 2
+(R/W) (soft reset = 0)
+ bit 7 = Reserved must be zero
+ bit 6 = UART1 Tx empty
+ bit 5 = UART1 Rx near full \ shared
+ bit 4 = UART1 Rx available / interrupt
+ bit 3 = Reserved must be zero
+ bit 2 = UART0 Tx empty
+ bit 1 = UART0 Rx near full \ shared
+ bit 0 = UART0 Rx available / interrupt
+ * Rx near full overrides Rx available
+ * If a device interrupt is disabled, it enters a polled mode
+
+0xC7 (199) => Reserved, write 0
+
+--
+
+0xC8 (200) => INT Status 0
+(R/W)
+ bits 7:2 = Reserved must be 0
+ bit 1 = Line
+ bit 0 = ULA
+ * (R) Set bits indicate the device generated an interrupt in the past or an interrupt is pending
+ * (W) Set bits clear the status. In hw im2 mode the status will continue to read as set until the
+ interrupt pending condition is cleared
+
+0xC9 (201) => INT Status 1
+(R/W)
+ bit 7 = ctc channel 7 zc/to
+ bit 6 = ctc channel 6 zc/to
+ bit 5 = ctc channel 5 zc/to
+ bit 4 = ctc channel 4 zc/to
+ bit 3 = ctc channel 3 zc/to
+ bit 2 = ctc channel 2 zc/to
+ bit 1 = ctc channel 1 zc/to
+ bit 0 = ctc channel 0 zc/to
+ * (R) Set bits indicate the device generated an interrupt in the past or an interrupt is pending
+ * (W) Set bits clear the status. In hw im2 mode the status will continue to read as set until the
+ interrupt pending condition is cleared
+
+0xCA (202) => INT Status 2
+(R/W)
+ bit 7 = Reserved must be zero
+ bit 6 = UART1 Tx empty
+ bit 5 = UART1 Rx half full \ shared
+ bit 4 = UART1 Rx available / interrupt
+ bit 3 = Reserved must be zero
+ bit 2 = UART0 Tx empty
+ bit 1 = UART0 Rx half full \ shared
+ bit 0 = UART0 Rx available / interrupt
+ * (R) Set bits indicate the device generated an interrupt in the past or an interrupt is pending
+ * (W) Set bits clear the status. In hw im2 mode the status will continue to read as set until the
+ interrupt pending condition is cleared
+
+0xCB (203) => Reserved, write 0xFF
+
+--
+
+0xCC (204) => DMA INT EN 0
+(R/W) (soft reset = 0)
+ bit 7 = NMI
+ bit 1 = Line
+ bit 0 = ULA
+ * Set bits indicate the corresponding interrupt will interrupt a dma operation when in hw im2 mode
+
+0xCD (205) => DMA INT EN 1
+(R/W) (soft reset = 0)
+ bit 7 = ctc channel 7 zc/to
+ bit 6 = ctc channel 6 zc/to
+ bit 5 = ctc channel 5 zc/to
+ bit 4 = ctc channel 4 zc/to
+ bit 3 = ctc channel 3 zc/to
+ bit 2 = ctc channel 2 zc/to
+ bit 1 = ctc channel 1 zc/to
+ bit 0 = ctc channel 0 zc/to
+ * Set bits indicate the corresponding interrupt will interrupt a dma operation when in hw im2 mode
+
+0xCE (206) => DMA INT EN 2
+(R/W) (soft reset = 0)
+ bit 7 = Reserved must be zero
+ bit 6 = UART1 Tx empty
+ bit 5 = UART1 Rx half full \ shared
+ bit 4 = UART1 Rx available / interrupt
+ bit 3 = Reserved must be zero
+ bit 2 = UART0 Tx empty
+ bit 1 = UART0 Rx half full \ shared
+ bit 0 = UART0 Rx available / interrupt
+ * Set bits indicate the corresponding interrupt will interrupt a dma operation when in hw im2 mode
+
+0xCF (207) => Reserved, write 0
+
+Because interrupts are only sampled at the end of an instruction
+by the Z80, each time the dma is interrupted one instruction of
+progress is made in the main program.
+
+--
+
+0xD8 (216) => I/O Traps (experimental)
+(R/W) (soft reset = 0)
+ bits 7:1 = Reserved must be zero
+ bit 0 = 1 to enable +3 FDC traps on ports 0x2ffd and 0x3ffd
+ * An i/o trap generates a multiface nmi and is indicated in nextreg 0x02
+ * Traps cannot be triggered by the dma or while the multiface, divmmc or external nmi is active
+
+0xD9 (217) => I/O Trap Write (experimental)
+(R/W)
+ Holds byte written during trapped i/o write cycle
+
+0xDA (218) => I/O Trap Cause (experimental)
+ 0 = none (zero at the same time nextreg 0x02 bit 4 is 0)
+ 1 = port_2ffd read
+ 2 = port_3ffd read
+ 3 = port_3ffd write
+ * If nextreg 0x02 bit 4 indicates an i/o cycle was trapped, this register indicates the cause
+
+--
+
+0xF0 (240) => XDEV CMD
+(R/W Issue 4 Only) (soft reset = 0x80)
+ * Select Mode
+ (R)
+ bit 7 = 1 if in select mode
+ bits 1:0 indicate currently selected device
+ 00 = none
+ 01 = Xilinx DNA
+ 10 = Xilinx XADC
+ (W)
+ bit 7 = 1 to enter select mode, 0 to enter selected device mode (no other bits have effect)
+ bit 6 = 1 to change selected device
+ bits 1:0 selected device
+ 00 = none
+ 01 = Xilinx DNA
+ 10 = Xilinx XADC
+ * Xilinx DNA Mode
+ (R)
+ bit 0 = dna bit (serial stream shifts left)
+ the first eight bits read will indicate the length of the following dna bits
+ (W)
+ bit 7 = 1 to enter select mode (write has no other effect)
+ otherwise causes dna string to reload, ready for fresh read
+ * Xilinx XADC Mode (Documented in Xilinx Series 7 UG480)
+ (R)
+ bit 6 = 1 if XADC is busy with conversion (BUSY)
+ bit 1 = 1 if XADC conversion completed since last read (EOC, read clears)
+ bit 0 = 1 if XADC conversion sequence completed since last read (EOS, read clears)
+ (W)
+ bit 7 = 1 to enter select mode (write has no other effect)
+ bit 6 = 1 to reset XADC (RESET)
+ bit 0 = 1 to start conversion (CONVST)
+ * Re-enter select mode at any time by writing to the register with bit 7 set
+ * Select a device to communicate with by writing to the register with bits 6 & 7 set
+ * Exit select mode by writing zero to bit 7; thereafter the particular device is attached to the nextreg
+
+0xF8 (248) => XADC REG
+(R/W Issue 4 Only) (hard reset = 0)
+ bit 7 = 1 to write to XADC DRP port, 0 to read from XADC DRP port **
+ bits 6:0 = XADC DRP register address DADDR
+ * An XADC register read or write is/ initiated by writing to this register
+ * There must be at least six 28 MHz cycles after each r/w to this register
+ ** Reads as 0
+
+0xF9 (249) => XADC D0
+(R/W Issue 4 Only) (hard reset = 0)
+ bits 7:0 = LSB data connected to XADC DRP data bus D7:0
+ * DRP reads store result here, DRP writes take value from here
+
+0xFA (250) => XADC D1
+(R/W Issue 4 Only) (hard reset = 0)
+ bits 7:0 = MSB data connected to XADC DRP data bus D15:8
+ * DRP reads store result here, DRP writes take value from here
+
+--
+
+0xFF (255) => Reserved for internal use
diff --git a/package.json b/package.json
index 624374a..eb8e011 100644
--- a/package.json
+++ b/package.json
@@ -9,17 +9,19 @@
"lint": "eslint"
},
"dependencies": {
+ "bootstrap": "^5.3.8",
+ "next": "15.5.4",
"react": "19.1.0",
- "react-dom": "19.1.0",
- "next": "15.5.4"
+ "react-bootstrap": "^2.10.10",
+ "react-dom": "19.1.0"
},
"devDependencies": {
- "typescript": "^5",
+ "@eslint/eslintrc": "^3",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "15.5.4",
- "@eslint/eslintrc": "^3"
+ "typescript": "^5"
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1c73117..f275093 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -8,12 +8,18 @@ importers:
.:
dependencies:
+ bootstrap:
+ specifier: ^5.3.8
+ version: 5.3.8(@popperjs/core@2.11.8)
next:
specifier: 15.5.4
version: 15.5.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react:
specifier: 19.1.0
version: 19.1.0
+ react-bootstrap:
+ specifier: ^2.10.10
+ version: 2.10.10(@types/react@19.2.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react-dom:
specifier: 19.1.0
version: 19.1.0(react@19.1.0)
@@ -42,6 +48,10 @@ importers:
packages:
+ '@babel/runtime@7.28.4':
+ resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==}
+ engines: {node: '>=6.9.0'}
+
'@emnapi/core@1.5.0':
resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==}
@@ -304,6 +314,31 @@ packages:
resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
engines: {node: '>=12.4.0'}
+ '@popperjs/core@2.11.8':
+ resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
+
+ '@react-aria/ssr@3.9.10':
+ resolution: {integrity: sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==}
+ engines: {node: '>= 12'}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1
+
+ '@restart/hooks@0.4.16':
+ resolution: {integrity: sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==}
+ peerDependencies:
+ react: '>=16.8.0'
+
+ '@restart/hooks@0.5.1':
+ resolution: {integrity: sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q==}
+ peerDependencies:
+ react: '>=16.8.0'
+
+ '@restart/ui@1.9.4':
+ resolution: {integrity: sha512-N4C7haUc3vn4LTwVUPlkJN8Ach/+yIMvRuTVIhjilNHqegY60SGLrzud6errOMNJwSnmYFnt1J0H/k8FE3A4KA==}
+ peerDependencies:
+ react: '>=16.14.0'
+ react-dom: '>=16.14.0'
+
'@rtsao/scc@1.1.0':
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
@@ -328,14 +363,25 @@ packages:
'@types/node@20.19.19':
resolution: {integrity: sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg==}
+ '@types/prop-types@15.7.15':
+ resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==}
+
'@types/react-dom@19.2.1':
resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==}
peerDependencies:
'@types/react': ^19.2.0
+ '@types/react-transition-group@4.4.12':
+ resolution: {integrity: sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==}
+ peerDependencies:
+ '@types/react': '*'
+
'@types/react@19.2.2':
resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==}
+ '@types/warning@3.0.3':
+ resolution: {integrity: sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==}
+
'@typescript-eslint/eslint-plugin@8.46.0':
resolution: {integrity: sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -568,6 +614,11 @@ packages:
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ bootstrap@5.3.8:
+ resolution: {integrity: sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==}
+ peerDependencies:
+ '@popperjs/core': ^2.11.8
+
brace-expansion@1.1.12:
resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
@@ -601,6 +652,9 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
+ classnames@2.5.1:
+ resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
+
client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
@@ -664,6 +718,10 @@ packages:
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
engines: {node: '>= 0.4'}
+ dequal@2.0.3:
+ resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
+ engines: {node: '>=6'}
+
detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
@@ -672,6 +730,9 @@ packages:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'}
+ dom-helpers@5.2.1:
+ resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
+
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
@@ -982,6 +1043,9 @@ packages:
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
engines: {node: '>= 0.4'}
+ invariant@2.2.4:
+ resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
+
is-array-buffer@3.0.5:
resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}
engines: {node: '>= 0.4'}
@@ -1289,6 +1353,11 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
+ prop-types-extra@1.1.1:
+ resolution: {integrity: sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==}
+ peerDependencies:
+ react: '>=0.14.0'
+
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
@@ -1299,6 +1368,16 @@ packages:
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ react-bootstrap@2.10.10:
+ resolution: {integrity: sha512-gMckKUqn8aK/vCnfwoBpBVFUGT9SVQxwsYrp9yDHt0arXMamxALerliKBxr1TPbntirK/HGrUAHYbAeQTa9GHQ==}
+ peerDependencies:
+ '@types/react': '>=16.14.8'
+ react: '>=16.14.0'
+ react-dom: '>=16.14.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
react-dom@19.1.0:
resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==}
peerDependencies:
@@ -1307,6 +1386,15 @@ packages:
react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+ react-lifecycles-compat@3.0.4:
+ resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==}
+
+ react-transition-group@4.4.5:
+ resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
+ peerDependencies:
+ react: '>=16.6.0'
+ react-dom: '>=16.6.0'
+
react@19.1.0:
resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
engines: {node: '>=0.10.0'}
@@ -1518,6 +1606,16 @@ packages:
resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}
engines: {node: '>= 0.4'}
+ uncontrollable@7.2.1:
+ resolution: {integrity: sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==}
+ peerDependencies:
+ react: '>=15.0.0'
+
+ uncontrollable@8.0.4:
+ resolution: {integrity: sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==}
+ peerDependencies:
+ react: '>=16.14.0'
+
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
@@ -1527,6 +1625,9 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ warning@4.0.3:
+ resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==}
+
which-boxed-primitive@1.1.1:
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
engines: {node: '>= 0.4'}
@@ -1558,6 +1659,8 @@ packages:
snapshots:
+ '@babel/runtime@7.28.4': {}
+
'@emnapi/core@1.5.0':
dependencies:
'@emnapi/wasi-threads': 1.1.0
@@ -1771,6 +1874,37 @@ snapshots:
'@nolyfill/is-core-module@1.0.39': {}
+ '@popperjs/core@2.11.8': {}
+
+ '@react-aria/ssr@3.9.10(react@19.1.0)':
+ dependencies:
+ '@swc/helpers': 0.5.15
+ react: 19.1.0
+
+ '@restart/hooks@0.4.16(react@19.1.0)':
+ dependencies:
+ dequal: 2.0.3
+ react: 19.1.0
+
+ '@restart/hooks@0.5.1(react@19.1.0)':
+ dependencies:
+ dequal: 2.0.3
+ react: 19.1.0
+
+ '@restart/ui@1.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@popperjs/core': 2.11.8
+ '@react-aria/ssr': 3.9.10(react@19.1.0)
+ '@restart/hooks': 0.5.1(react@19.1.0)
+ '@types/warning': 3.0.3
+ dequal: 2.0.3
+ dom-helpers: 5.2.1
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+ uncontrollable: 8.0.4(react@19.1.0)
+ warning: 4.0.3
+
'@rtsao/scc@1.1.0': {}
'@rushstack/eslint-patch@1.13.0': {}
@@ -1794,14 +1928,22 @@ snapshots:
dependencies:
undici-types: 6.21.0
+ '@types/prop-types@15.7.15': {}
+
'@types/react-dom@19.2.1(@types/react@19.2.2)':
dependencies:
'@types/react': 19.2.2
+ '@types/react-transition-group@4.4.12(@types/react@19.2.2)':
+ dependencies:
+ '@types/react': 19.2.2
+
'@types/react@19.2.2':
dependencies:
csstype: 3.1.3
+ '@types/warning@3.0.3': {}
+
'@typescript-eslint/eslint-plugin@8.46.0(@typescript-eslint/parser@8.46.0(eslint@9.37.0)(typescript@5.9.3))(eslint@9.37.0)(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.1
@@ -2056,6 +2198,10 @@ snapshots:
balanced-match@1.0.2: {}
+ bootstrap@5.3.8(@popperjs/core@2.11.8):
+ dependencies:
+ '@popperjs/core': 2.11.8
+
brace-expansion@1.1.12:
dependencies:
balanced-match: 1.0.2
@@ -2095,6 +2241,8 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
+ classnames@2.5.1: {}
+
client-only@0.0.1: {}
color-convert@2.0.1:
@@ -2155,6 +2303,8 @@ snapshots:
has-property-descriptors: 1.0.2
object-keys: 1.1.1
+ dequal@2.0.3: {}
+
detect-libc@2.1.2:
optional: true
@@ -2162,6 +2312,11 @@ snapshots:
dependencies:
esutils: 2.0.3
+ dom-helpers@5.2.1:
+ dependencies:
+ '@babel/runtime': 7.28.4
+ csstype: 3.1.3
+
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
@@ -2623,6 +2778,10 @@ snapshots:
hasown: 2.0.2
side-channel: 1.1.0
+ invariant@2.2.4:
+ dependencies:
+ loose-envify: 1.4.0
+
is-array-buffer@3.0.5:
dependencies:
call-bind: 1.0.8
@@ -2937,6 +3096,12 @@ snapshots:
prelude-ls@1.2.1: {}
+ prop-types-extra@1.1.1(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+ react-is: 16.13.1
+ warning: 4.0.3
+
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
@@ -2947,6 +3112,26 @@ snapshots:
queue-microtask@1.2.3: {}
+ react-bootstrap@2.10.10(@types/react@19.2.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@restart/hooks': 0.4.16(react@19.1.0)
+ '@restart/ui': 1.9.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ '@types/prop-types': 15.7.15
+ '@types/react-transition-group': 4.4.12(@types/react@19.2.2)
+ classnames: 2.5.1
+ dom-helpers: 5.2.1
+ invariant: 2.2.4
+ prop-types: 15.8.1
+ prop-types-extra: 1.1.1(react@19.1.0)
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+ react-transition-group: 4.4.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+ uncontrollable: 7.2.1(react@19.1.0)
+ warning: 4.0.3
+ optionalDependencies:
+ '@types/react': 19.2.2
+
react-dom@19.1.0(react@19.1.0):
dependencies:
react: 19.1.0
@@ -2954,6 +3139,17 @@ snapshots:
react-is@16.13.1: {}
+ react-lifecycles-compat@3.0.4: {}
+
+ react-transition-group@4.4.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+ dependencies:
+ '@babel/runtime': 7.28.4
+ dom-helpers: 5.2.1
+ loose-envify: 1.4.0
+ prop-types: 15.8.1
+ react: 19.1.0
+ react-dom: 19.1.0(react@19.1.0)
+
react@19.1.0: {}
reflect.getprototypeof@1.0.10:
@@ -3251,6 +3447,18 @@ snapshots:
has-symbols: 1.1.0
which-boxed-primitive: 1.1.1
+ uncontrollable@7.2.1(react@19.1.0):
+ dependencies:
+ '@babel/runtime': 7.28.4
+ '@types/react': 19.2.2
+ invariant: 2.2.4
+ react: 19.1.0
+ react-lifecycles-compat: 3.0.4
+
+ uncontrollable@8.0.4(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+
undici-types@6.21.0: {}
unrs-resolver@1.11.1:
@@ -3281,6 +3489,10 @@ snapshots:
dependencies:
punycode: 2.3.1
+ warning@4.0.3:
+ dependencies:
+ loose-envify: 1.4.0
+
which-boxed-primitive@1.1.1:
dependencies:
is-bigint: 1.1.0
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 84af2cb..627d25d 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -18,6 +18,9 @@ export default function Home() {
Get started by editing src/app/page.tsx.
{register.description}
+