From 50190d002dd97dcd22851bb8914fb5d8cd48a53f Mon Sep 17 00:00:00 2001 From: "D. Rimron-Soutter" Date: Tue, 7 Oct 2025 13:32:22 +0100 Subject: [PATCH] First version of app, by GPT5 --- data/nextreg.txt | 1232 ++++++++++++++++++++++++ data/nextreg_bare.txt | 1239 +++++++++++++++++++++++++ package.json | 10 +- pnpm-lock.yaml | 212 +++++ src/app/page.tsx | 3 + src/app/registers/RegisterBrowser.tsx | 45 + src/app/registers/page.tsx | 87 ++ src/app/registers/types.ts | 21 + 8 files changed, 2845 insertions(+), 4 deletions(-) create mode 100644 data/nextreg.txt create mode 100644 data/nextreg_bare.txt create mode 100644 src/app/registers/RegisterBrowser.tsx create mode 100644 src/app/registers/page.tsx create mode 100644 src/app/registers/types.ts 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.
  • Save and see your changes instantly.
  • +
  • + Explore the Spectrum Next Registers. +
  • diff --git a/src/app/registers/RegisterBrowser.tsx b/src/app/registers/RegisterBrowser.tsx new file mode 100644 index 0000000..d6b6e97 --- /dev/null +++ b/src/app/registers/RegisterBrowser.tsx @@ -0,0 +1,45 @@ +'use client'; + +import { useState } from 'react'; +import { Register } from './types'; +import { Form, Card, Container, Row, Col } from 'react-bootstrap'; + +interface RegisterBrowserProps { + registers: Register[]; +} + +export default function RegisterBrowser({ registers }: RegisterBrowserProps) { + const [searchTerm, setSearchTerm] = useState(''); + + const filteredRegisters = registers.filter(register => + register.name.toLowerCase().includes(searchTerm.toLowerCase()) || + register.description.toLowerCase().includes(searchTerm.toLowerCase()) + ); + + return ( + + + setSearchTerm(e.target.value)} + /> + + + {filteredRegisters.map(register => ( + + + + {register.name} ({register.hex_address} / {register.dec_address}) + + +
    {register.description}
    +
    +
    + + ))} +
    +
    + ); +} diff --git a/src/app/registers/page.tsx b/src/app/registers/page.tsx new file mode 100644 index 0000000..8d35f32 --- /dev/null +++ b/src/app/registers/page.tsx @@ -0,0 +1,87 @@ +import { promises as fs } from 'fs'; +import path from 'path'; +import RegisterBrowser from './RegisterBrowser'; +import { Register } from './types'; + +async function parseNextReg(fileContent: string): Promise { + const registers: Register[] = []; + const paragraphs = fileContent.split(/\n\s*\n/); + + for (const paragraph of paragraphs) { + if (!paragraph.trim()) { + continue; + } + + const lines = paragraph.trim().split('\n'); + processRegisterBlock(lines, registers); + } + + return registers; +} + +function processRegisterBlock(lines: string[], registers: Register[]) { + const firstLine = lines[0]; + const restOfLines = lines.slice(1); + + const multiRegisterMatch = firstLine.match(/([0-9a-fA-F,x]+)\s*\(.*?\)\s*=>\s*(.*)/); + + if (multiRegisterMatch) { + const hexAddresses = multiRegisterMatch[1].trim(); + const decAddresses = multiRegisterMatch[2].trim(); + const name = multiRegisterMatch[3] ? multiRegisterMatch[3].trim() : ''; + const description = restOfLines.join('\n').trim(); + + const hexList = hexAddresses.split(',').map(h => h.trim()); + const decList = decAddresses.includes('-') ? decAddresses.split('-') : decAddresses.split(',').map(d => d.trim()); + + if (hexList.length > 1) { + for (let i = 0; i < hexList.length; i++) { + const hexAddr = hexList[i]; + const decAddr = decList[i] || decAddresses; + registers.push({ + hex_address: hexAddr, + dec_address: isNaN(parseInt(decAddr, 10)) ? decAddr : parseInt(decAddr, 10), + name: `${name} (${hexAddr})`, + description: description, + }); + } + } else { + registers.push({ + hex_address: hexAddresses, + dec_address: isNaN(parseInt(decAddresses, 10)) ? decAddresses : parseInt(decAddresses, 10), + name: name, + description: description, + }); + } + return; + } + + const singleRegisterMatch = lines[0].match(/(0x[0-9a-fA-F]{2})\s+(\d+)\s+=>\s+(.*)/); + if(singleRegisterMatch) { + const description = lines.slice(1).join('\n').trim(); + const hexAddr = singleRegisterMatch[1].trim(); + const decAddr = singleRegisterMatch[2].trim(); + const name = singleRegisterMatch[3].trim(); + + registers.push({ + hex_address: hexAddr, + dec_address: parseInt(decAddr, 10), + name: name, + description: description, + }); + } +} + + +export default async function RegistersPage() { + const filePath = path.join(process.cwd(), 'data', 'nextreg_bare.txt'); + const fileContent = await fs.readFile(filePath, 'utf8'); + const registers = await parseNextReg(fileContent); + + return ( +
    +

    Spectrum Next Registers

    + +
    + ); +} diff --git a/src/app/registers/types.ts b/src/app/registers/types.ts new file mode 100644 index 0000000..4e2f6dd --- /dev/null +++ b/src/app/registers/types.ts @@ -0,0 +1,21 @@ +export interface BitwiseOperation { + bits: string; + description: string; + value?: string; + notes?: string[]; +} + +export interface RegisterAccess { + description?: string; + operations: BitwiseOperation[]; +} + +export interface Register { + hex_address: string; + dec_address: number | string; + name: string; + description: string; + read?: RegisterAccess; + write?: RegisterAccess; + notes?: string[]; +}