Sega System 24 Hardware Notes (2013-06-16)
From Sega Retro
This is a copy of an "unofficial" document containing original research, for use as a source on Sega Retro. This page likely exists for historical purposes - the contents should ideally be copy-edited and wikified to make better use of Sega Retro's software. Original source: https://web.archive.org/web/20140318183124/cgfm2.emuviews.com/new/s24hw.txt |
Sega System 24 Hardware Notes (C) 2013 Charles MacDonald [6/16/13] - Added ABSEL override mode description. - Added line scroll description. - Clarified I/O chip address connections. - Fixed some typos. [4/1/13] - Initial release. ---------------------------------------------------------------------------- System overview ---------------------------------------------------------------------------- Memory map Custom chip 315-5295 at IC5 does address decoding for both CPUs: 000000-07FFFF : BIOS ROM (CPU B DRAM if accessed by CPU B) 080000-0FFFFF : CPU A DRAM 100000-1FFFFF : BIOS ROM (accessible to both CPUs) 200000-3FFFFF : 315-5292 (Tilemap chip) 400000-5FFFFF : 315-5294 (Mixer chip and color RAM) 600000-7FFFFF : 315-5293 (Sprite chip) 800000-9FFFFF : 315-5296 (I/O chip) A00000-AFFFFF : 315-5295 (315-5295 at IC7, timer and interrupt controller) B00000-BFFFFF : Expansion (CN2, /EXCS0) C00000-CFFFFF : Expansion (CN2, /EXCS1) D00000-DFFFFF : Expansion (CN5, /EXCS2) E00000-EFFFFF : Expansion (To test point) F00000-F3FFFF : CPU B DRAM F40000-F7FFFF : CPU B DRAM F80000-FBFFFF : CPU A DRAM FC0000-FFFFFF : CPU A DRAM DRAM is 256K, mirrored twice in each 512K region it is mapped to. Some versions of the BIOS test to see if the DRAM is 512K or 256K. See the board revisions section for more details. ROM is 256K, mirrored repeatedly throughout the 1MB area it is assigned to. Bus structure The various components in the memory map are split across two independent busses in the system T-bus (CPU A) - CPU A DRAM - BIOS ROM - Interrupt controller and timer (IC7) ("INTC") - I/O chip - YM2151 - CN2 expansion connector (System 24 specific I/O, FDC, and ROM boards) - CN5 expansion connector (Compatible with earlier Sega I/O boards) P-bus (CPU B) - CPU B DRAM - Tilemap generator - Object generator - Mixer chip - Color RAM System timing Wait states for CPU A when accessing memory with CPU B held in the reset state (/RESP=L). BIOS ROM : No wait states. INTC registers : No wait states. Color RAM / Mixer regs : No wait states. CN5 expansion area : No wait states. Tilemap registers : No wait states. CN2 expansion areas : Subject to external DTACK pin connection. No wait states for the I/O, FDC, ROM boards. I/O chip : 1 clock added per access. Tilemap RAM (either) : 6 clocks added per access. This happens regardless of horizontal or vertical blanking or if layers are blanked. DRAM (CPU A work RAM) : Every 20us an access has 4 clocks added. DRAM (CPU B work RAM) : Every 20us an access has 4 clocks added. Sprite RAM : Variable. When rendering it ranges from 3 to 22 clocks added, when idle the minimum is 3 clocks added per access (e.g. 1st command is $C000). Wait states for CPU A when CPU B is running. CPU A accessing same : 4 clocks added per access. T-bus address as CPU B CPU A accessing same : 4 clocks added per access. P-bus address as CPU B CPU A accessing other : ? (Seems unclear, but different than above cases) T-bus than CPU B CPU A accessing other : ? (Seems unclear, but different than above cases) P-bus than CPU B The DRAM used for work RAM (MB81464) needs to be refreshed every 4ms, and it seems like the system refreshes it much faster than necessary. ---------------------------------------------------------------------------- Board revisions ---------------------------------------------------------------------------- 837-6442 Original board type. 837-6442-01 New board type. It has the following changes compared to the original board: - Added 7805 regulator which provides a +5V source derived from the +12V input from the edge connector. This is used for the audio section exclusively. - Added IC83 (74HC245) to buffer port H of the I/O chip and in turn drive the audio DAC's R-2R resistor array. This was needed now that the I/O chip and audio have their own +5V supplies and are no longer common. - IC77 has been replaced with a SOIC equivalent to free up room for newly added IC83. - Added IC84 (74HC04) to buffer the 10 MHz clock output of IC65 (74F74) which goes to both CPUs and the 315-5295 at IC5. Two gates are used to provide a non-inverted clock; the remaining four gates are unused. - Narrow DIP switches are used instead of the full size ones. - Sprite RAM is implemented with eight MB81464 DRAMs (64Kx4 each) soldered to the board like the original version, but now an array of four sockets (IC85-88) have been added for MB81C4256 DRAMs. Jumper J1 and resistors R64 and R65 have been added to enable one of the two DRAM banks. The MB81C4256 is 256Kx4 compared to the MB81464 which is 64Kx4, so if the MB81C4256s are installed and enabled, sprite RAM is 512K instead of 256K. When jumper J1 connects pins 2-3 ("256"), the MB81464 bank is enabled. When it connects pins 1-2 ("1M"), the MB81C4256 bank is enabled. If the jumper is left unconnected both banks are disabled. Disabled bank(s) respond to writes but not reads. While this change allowed the hardware to transition to MB81C4256 DRAMs as they became cheaper and/or more available, it seems unusual that they'd permanently install MB81464s and provide sockets for the MB81C4256s as well as have a circuit that supported both being installed and operating at the same time. In theory it might have been an option to support older software that wouldn't work with 512K of RAM being installed, but it isn't known if any games have such an issue. Other specifics for this revision: Jumper J1 1 - ("1M") - To ZIP sockets pin 1 (IC85-88) (MB81C4256 OE#) and R64 pullup. 2 - From 315-5293 pin 26 (/OE) 3 - ("256") - To ZIP sockets pin 5 (IC42-48) (MB81464 OE#) and R65 pullup. MB81C5256 address line connections: Pin 11 (A0) - Pin 31 (CGAD8) Pin 12 (A1) - Pin 33 (CGAD6) Pin 13 (A2) - Pin 34 (CGAD5) Pin 14 (A3) - Pin 35 (CGAD4) Pin 16 (A4) - Pin 32 (CGAD7) Pin 17 (A5) - Pin 36 (CGAD3) Pin 18 (A6) - Pin 37 (CGAD2) Pin 19 (A7) - Pin 38 (CGAD1) Pin 20 (A8) - Pin 39 (CGAD0) On the original board CGAD8 is unconnected and goes to a test point. 837-6442-02 Used by Quiz Ghost Hunter. Seems almost identical to revision 1 board. It uses four 2-pin DIP MB81C4256's for a total of 512K of sprite RAM. The old MB81464 ZIP array, MB81C4256 ZIP sockets, and DRAM selection jumper are removed. BIOS checks for board revisions The EPR-12186/12187 BIOS tests for 512K of CPU A work RAM by determining if RAM address $0C0000 is a mirror of $080000. Revisions 0 and 1 do not have extra CPU work RAM. It isn't known how much RAM the revision 2 board has, but it was produced much later after this BIOS was developed. This check that the BIOS performs may have been included to support a development system with more RAM, or for a planned board revision for more RAM that was never released. ---------------------------------------------------------------------------- I/O chip ---------------------------------------------------------------------------- Overview The 315-5296 I/O chip is similar in design to the Sony CXD1095Q I/O chip used on earlier boards. It has the following features: - Eight 8-bit I/O ports (A through H) - Three output-only pins (CNT2-0) - Chip select for a peripheral device (/FMCS) - Clock output for a peripheral device (CKOT) - Programmable clock divider Reset state After a reset, all I/O ports are configured as inputs. Address decoding The chip has a 6-bit address bus assigned as follows: $00-$1F : I/O chip internal locations $20-$3F : Unused by I/O chip; /FMCS asserted for this range. Of the first 32 locations, only the first 16 are used and the latter 16 have no function. Register map $00 : Port A data $01 : Port B data $02 : Port C data $03 : Port D data $04 : Port E data $05 : Port F data $06 : Port G data $07 : Port H data $08 : Identifier #1 $09 : Identifier #2 $0A : Identifier #3 $0B : Identifier #4 $0C : Mode control register #1 (mirror) $0D : Mode control register #2 (mirror) $0E : Mode control register #1 $0F : Mode control register #2 $10-$1F : Unused $20-$3F : /FMCS area Identifier These locations return the ASCII values "SEGA" when read. I/O ports Each I/O port consists of an 8-bit output latch and 8-bit input buffer. Regardless of the port direction, writing to a register loads the port's output latch. If the port is an input, reading returns the real-time state of the pins through the input buffer. If the port is an output, reading returns the current value of the output latch. Control register #1 MSB LSB dd-- ---- : CKOT clock divider (0= CLK/4, 1= CLK/8, 2= CLK/16, 3= CLK/2) --dd ---- : CNT2 clock divider (0= CLK/4, 1= CLK/8, 2= CLK/16, 3= CLK/2) ---- e--- : CNT2 output mode (1= Clock output, 0= Programmable output) ---- -210 : Output level of CNT2-0 pins (1= high, 0= low) This register defines how CNT2-0 operate, if CNT2 is a secondary clock output, and the frequency of the primary and secondary clock ouputs. When CNT2 is configured as clock output, bit 2 of this register has no effect on the output level of CNT2. Control register #2 MSB LSB h--- ---- : Direction of I/O port H (1= output, 0= input) -g-- ---- : Direction of I/O port G (1= output, 0= input) --f- ---- : Direction of I/O port F (1= output, 0= input) ---e ---- : Direction of I/O port E (1= output, 0= input) ---- d--- : Direction of I/O port D (1= output, 0= input) ---- -c-- : Direction of I/O port C (1= output, 0= input) ---- --b- : Direction of I/O port B (1= output, 0= input) ---- ---a : Direction of I/O port A (1= output, 0= input) This register defines the direction of each I/O port. System 24 specifics The 68000 address lines are connected to the chip in the following manner: I/O 68K A0 A1 A1 A2 A2 A3 A3 A4 A4 A5 A5 A8 This segments the 64-byte space into two regions: $800001-$80003F : I/O chip registers $800101-$80013F : /FMCS area Register map $800001 : Port A data $800003 : Port B data $800005 : Port C data $800007 : Port D data $800009 : Port E data $80000B : Port F data $80000D : Port G data $80000F : Port H data $800011 : Identifier #1 $800013 : Identifier #2 $800015 : Identifier #3 $800017 : Identifier #4 $800019 : Mode control register #1 (mirror) $80001B : Mode control register #2 (mirror) $80001D : Mode control register #1 $80001F : Mode control register #2 $800021-$80003F : Unused $800101-$80013F : /FMCS area, specifically: $800101 : YM2151 address 0 $800103 : YM2151 address 1 I/O port summary Port A : Optocoupled inputs from edge connector (active low). Port B : Optocoupled inputs from edge connector (active low). Port C : Connected via bus transceiver to edge connector pins. Output pin CNT0 controls the direction (0= input, 1= output). Port D : Output, bits 7-4 driven by LS367 to CN3 pins (digital outputs, TTL level) and bits 3-0 driven by ULN2003 to edge connector (open collector, high current outputs). Port E : Optocoupled inputs from edge connector (active-low). Port F : DIP switch #1 inputs. Port G : DIP switch #2 inputs. Port H : Output to 8-bit audio DAC. I/O chip pin connections - CLK driven at 16 MHz. - CNT2 connected to YM2151 /IC. (reset line) - CNT1 connected to 315-5295 (IC5) pin 81 (/RESP) This is the CPU B reset line, 0= reset, 1= running. - CNT0 connected to 74LS245 (IC77) DIR. - CKOT connected to YM2151 clock input. I/O chip initialization The BIOS initializes the I/O chip as follows: MOVE.B #$04,$0080001D MOVE.B #$00,$00800007 MOVE.B #$88,$0080001F This initializes the system as follows: - Ports D,H are outputs, remaining are inputs. - CNT2 is driven high, CNT1-0 are driven low. Meaning CPU B is held in a reset state (/RESP=L) and is inactive. - CNT2 is a programmable output and not a clock output. - CKOT outputs a an 8 MHz clock to the YM2151 (16 MHz / 2). - Port D outputs are driven low. ---------------------------------------------------------------------------- Timer and interrupt controller ---------------------------------------------------------------------------- Custom chip 315-5295 (IC7) has an interrupt controller and timer peripheral. It has four internal registers that are word-wide. Register overview $A00000 : ---- cccc cccc cccc : Timer reload count $A00002 : ---- ---- ---- --mm : Timer mode $A00004 : ---- ---- --65 432- : CPU A interrupt enable (1= enabled, 0=disabled) $A00006 : ---- ---- --65 432- : CPU B interrupt enable (1= enabled, 0=disabled) Reading any address returns the real time state of the timer count. Interrupt sources Level 2 : YM2151 /IRQ (/INT0) Level 3 : Timer Level 4 : Tilemap /XINT (/INT1) Level 5 : Sprite /DMAO and /DMAI tied together (/INT2) Level 6 : CN2 expansion connector (/INT3) Interrupt request behavior The timer interrupt request signal is asserted until the corresponding CPU interrupt enable register is read or written, either by byte or word access. Typically software will read that register and discard the value to acknowledge the interrupt as follows: __level3_irq: tst.w $A00004 rte One CPU can acknowledge an interrupt for the other one, for example CPU A can acknowledge a timer interrupt on CPU B by writing or reading $A00006. The V-Blank interrupt request signal from the tilemap chip is asserted for exactly one scanline, or 656 cycles. If the interrupt handler exits before that duration is over the interrupt will immediately be triggered again. The sprite interrupt request signal from the sprite chip is asserted for exactly one scanline, or 656 cycles. If the interrupt handler exits before that duration is over the interrupt will immediately be triggered again. Timer The timer is a 12-bit up-counter. The counter can be read back by reading any word offset in $A00000. When the counter overflows it is reloaded with the last value written to $A00000. Writing to that register while the timer is counting does not affect it until the next overflow and reload. The timer's clock source can be an 8 MHz clock that is synchronous to the 16 MHz pixel clock, and the HOUT signal generated by the tilemap chip that is pulsed once per scanline. The counter counts up on the positive edge of the selected clock signal. When the count is $0FFF and a positive edge is detected, the counter is loaded with the value of the reload register and an IRQ is requested. The timer continues to count even if the interrupt is not processed or not acknowledged. There are four timer modes as follows: 0 - Timer off. There is a bug in the hardware; if the reload count is $0FFF an interrupt is generated just like mode 1. E.g. one interrupt triggered on every scanline. 1 - Scanline timer The timer clock source is HOUT. If HOUT is not generated the counter state will not change. 2 - Pixel timer The timer behaves like mode 3, but the count is also reloaded on the rising edge of HOUT. This allows you to trigger an interrupt at a specific location within a scanline, specified in units of two pixels. The timer clock source is 8 MHz. If HOUT is not generated the counter state will behave exactly like mode 3. Valid reload count values in this mode are: 0000-0EB7 : No interrupts generated (counter reloaded before it expires) 0EB8 : 1 interrupt per scanline : 0F5B : 1 interrupt per scanline 0F5C : 2 interrupts per scanline : 0F92 : 2 interrupts per scanline 0FFF : Interrupt triggered at every 8 MHz clock As the counter reloads after each interrupt, using large counts will cause the interrupt to trigger multiple times in one scanline. Adjusting the position of HOUT shifts the location that the interrupt is triggered at on a given scanline. 3 : 8 MHz clock The counter increases on the rising edge of the 8 MHz clock. The CPU can't process interrupts fast enough at some of the highest timer counts. Comments in mode 2 The problem with mode 2 is that it does not function as a one-shot timer, so for large count values the timer will overflow multiple times per scanline and you'll get several interrupts on a single line. In theory mode 2 would allow for a positional interrupt, but because of this reload behavior you are limited to counts that position the interrupt in the right half of the screen only, unless you have a more complex interrupt handler that disables itself for other interrupts after the first one. For a true positional interrupt at the cost of distorting the sprites, you can use timer mode 1 and adjust the HOUT register. This gives very fine (16 MHz) positioning rather than the coarse positioning of mode 2 without the troublesome reload behavior. ---------------------------------------------------------------------------- Mixer chip and color RAM ---------------------------------------------------------------------------- The mixer chip combined the output of three pixel data busses (tilemap A, tilemap B, sprite framebuffer) and generates indices in color RAM specifying RGB color data to be displayed for each pixel on the screen. Address map 400000-403FFF : Color RAM, more specifically: 400000-401FFF : Tilemap palettes (256 palettes of 16 colors) 402000-4021FF : Sprite palette (256 colors) 402200-403FFF : Unused RAM 404000-407FFF : Mixer chip internal registers (16 locations) Color RAM format MSB LSB s--- ---- ---- ---- : Shadow (0) or highlight (1) select. -b-- bbbb ---- ---- : Blue component bits 0,4,3,2,1. --g- ---- gggg ---- : Green component bits 0,4,3,2,1. ---r ---- ---- rrrr : Red component bits 0,4,3,2,1. Registers Each register is 3 bits (D2-D0) and can be read and written. 404001 : Background A priority code for low priority tiles 404003 : Background A priority code for high priority tiles 404005 : Window A priority code for low priority tiles 404007 : Window A priority code for high priority tiles 404009 : Background B priority code for low priority tiles 40400B : Background B priority code for high priority tiles 40400D : Window B priority code for low priority tiles 40400F : Window B priority code for high priority tiles 404011 : Sprite priority code for pens $C0-$FF 404013 : Sprite priority code for pens $80-$BF 404015 : Sprite priority code for pens $40-$7F 404017 : Sprite priority code for pens $00-$3F 404019 : Control register #1 40401B : Control register #2 40401D : Control register #1 (mirror) 40401F : Control register #2 (mirror) Control register #1 D2 : ? D1 : ? D0 : ABSEL mode enable (1= on, 0= off) Control register #2 D2 : Unused (connects from pin 37 "EXT" to test point near C118) 0= Test point driven low, 1= Driven high. D1 : Screen flip (1= on, 0= off) (from pin 36 "EX0" labelled "2P") D0 : Screen blanking (1= on, 0= off) Priority ordering A priority of 0 is the lowest, 7 is the highest. If priority codes are equal the mixer chip uses a hardwired priority ordering. ---------------------------------------------------------------------------- Tilemap chip ---------------------------------------------------------------------------- Overview The 315-5292 generates two tilemap layers and all display timing signals for the system. Terminology Planes A, B - The two scrolling tilemaps generated by the chip. Background - The primary tilemap associated with a given plane. Window - The alternate tilemap associated with a given plane. Layer - Either the background or the window of a plane. Mask - A bitmap that selects if the background tilemap or window tilemap should be shown within a 8x1 pixel area of the display. Individual pixel data for planes A and B are fed to the mixer chip. This data includes the pixel value (4 bits), palette number (8 bits), priority flag (1 bit) and background/window indicator (1 bit). The mixer chip assigns a 3-bit priority code based on a pixel's priority flag, then evaluates the priority of pixel data from both planes to determine which plane appears on top. Bit 0 of mixer control register #2 enables use of the ABSEL signal, which the tilemap chip generates at a user-defined pixel position on every scanline. To the left of this point plane A is shown exclusively, to the right plane B is shown exclusively. If this mode is not used, the ABSEL signal position can still be freely defined but it has no impact on the display. Layer transparency Normal display mode (ABSEL=0) Zero value pixels from the topmost layer are considered transparent. Zero value pixels from the bottommost layer show color 0 of the specified palette. If the topmost layer is blanked, it is considered transparent. If the bottommost layer is blanked, it is filled with color 0 of palette 0. ABSEL display mode (ABSEL=1) Pixel 0 is not transparent, so color 0 of the associated palette is shown. If any layer is blanked, it is filled with color 0 of palette 0. Memory map 200000-20FFFF : VRAM (64K) 220000-23FFFF : ABSEL register (any word offset) 240000-25FFFF : HOUT register (any word offset) 260000-26FFFF : VOUT register (any word offset) 270000-27FFFF : Display mode register (any word offset) 280000-2FFFFF : Tile pattern RAM (512K; 128K present) VRAM memory map 200000-201FFF : Plane A background name table 202000-203FFF : Plane A window name table 204000-205FFF : Plane B background name table 206000-207FFF : Plane B window name table 208000-2083FF : Plane A background line scroll table 208400-2087FF : Plane A window line scroll table 208800-208BFF : Plane B background line scroll table 208C00-208FFF : Plane B window line scroll table 209000-209FFF : (Unused) 20A000-20A00F : Video registers ("soft" registers stored in RAM) 20A010-20BFFF : (Unused) 20C000-20CFFF : Plane A window mask 20D000-20DFFF : Plane B window mask 20E000-20FFFF : (Unused) 280000-29FFFF : Tile pattern RAM (128K) 2A0000-2BFFFF : Tile pattern RAM (mirror) 2C0000-2DFFFF : Tile pattern RAM (mirror) 2E0000-2FFFFF : Tile pattern RAM (mirror) Name table data MSB LSB p--- ---- ---- ---- : Priority bit (0= low, 1= high) -ccc cccc c--- ---- : Palette number (0-255) --nn nnnn nnnn nnnn : Tile number (0-16383) [Other hardware] ---- nnnn nnnn nnnn : Tile number (0-4095) [System 24] System 24 only has 128K of 512K RAM installed for tile patterns. The name field is 14 bits, but only the lower 12 bits select the tile to be displayed. The palette and tile number fields overlap so palette numbers and tile numbers cannot be freely defined in all cases. Video registers 20A000 : Background A horizontal scroll 20A002 : Window A horizontal scroll 20A004 : Background B horizontal scroll 20A006 : Window B horizontal scroll 20A008 : Background A vertical scroll 20A00A : Window A vertical scroll 20A00C : Background B vertical scroll 20A00E : Window B vertical scroll These registers are latched close to the negative edge of H-Sync on the last line of the frame (the scanline before the first line of the active display). While the specific timings aren't known, it seems the registers at $20A008 are read before $20A000. This latching behavior prevents mid-frame changes to the display from taking effect. One workaround is to use the line scroll table function. Horizontal scroll register MSB LSB s--- ---- ---- ---- : Line scroll enable (1= on, 0= off) ---- --xx xxxx xxxx : Horizontal scroll If line scrolling is enabled the scroll field has no effect on the display. Vertical scroll register MSB LSB e--- ---- ---- ---- : Layer enable (1= blanked, 0= shown) -ss- ---- ---- ---- : Playfield size (for backgrounds only, not windows) ---- --yy yyyy yyyy : Vertical scroll Line scrolling The line scroll tables consist of 512 entries of 16-bit words with the following format: MSB LSB e--- ---- ---- ---- : ABSEL override flag (Plane A window only) ---- --xx xxxx xxxx : Horizontal scroll If line scrolling is enabled the horizontal scroll value specified here is used instead of the one in the soft registers at $20A00x. ABSEL override function The plane A window line scroll table has a secondary function. When ABSEL mode is enabled and bit 15 of a particular line scroll entry is set, plane A is shown for the entire width of the corresponding scanline regardless of the ABSEL position. Plane B will not be visible on that line. This allows the screen to be split horizontally by the ABSEL register into two halves, and vertically into any number of segments on a line by line basis. This function works regardless of line scrolling being enabled or not, or the plane A window layer being enabled or not. So even if line scroll was disabled for all layers and the plane A window was disabled, this function still operates as described. From a hardwawre point of view, the state of bit 15 is output on the DSPABH pin to the mixer chip for a duration of one scanline (656 pixels). If consecutive lines have this bit set, the output remains high with no gaps. Since the tilemap chip doesn't know about the state of the ABSEL mode bit in the mixer chip it will control DSPABH even if ABSEL mode is disabled. Playfield size field The playfield size is defined as follows D14 D13 0 0 : 64x64 (Normal) A reset mask bit shows the background name table using background scroll registers. A set mask bit shows the window name table using window scroll registers. 0 1 : 64x128 (Tall playfield) The 64x128 playfield uses the background name table for the top 64x64 area, and the window name table for the bottom 64x64 area. This forms a composite 64x128 layer using both name tables. A reset mask bit shows the composite layer using background scroll registers. A set mask bit shows the composite layer using window scroll registers. If the background and window scroll registers are programmed identically you can't distinguish areas where the mask bits are set or reset. 1 0 : 128x64 (Wide playfield) The 128x64 playfield uses the background name table for the left 64x64 area, and the window name table for the right 64x64 area. This forms a composite 128x64 layer using both name tables. A reset mask bit shows the composite layer using background scroll registers. A set mask bit shows the composite layer using window scroll registers. If the background and window scroll registers are programmed identically you can't distinguish areas where the mask bits are set or reset. 1 1 : 64x64 (Window-only) A reset mask bit shows the window name table using background scroll registers. A set mask bit shows the window name table using window scroll registers. The background name table cannot be displayed in this mode. Display quirks The same hardware that is used to render the background layer is used for the window layer. This causes a problem when the lower 3 bits of the horizontal scroll are nonzero between tiles that are adjacent to each other and come from different layers as specified by the mask bit. The 8-pixel shift registers are only loaded once every 8 pixels. So in this case the shift register will still contain data from the left tile, which is shifted out into the right tile. If the layer to the left has a scroll value of zero, then the shift register is empty. Pixels 1-7 of the layer to the right are filled in with the background color of the left tile instead. For example if the background is displayed and the window is blanked, and the mask bit is set, a blank tile from the window is shown. However the hardware is still loading data from the window which was ultimately not displayed, and if the horizontal scroll is 1-7, you'll see the unblanked window data shifted out into the background until the shift registers reload with background tile data. Tilemap hardware registers Registers are write only. ABSEL register ($220000) MSB LSB ---- --xx xxxx xxxx : Pulse width of ABSEL signal. See the timing section below for specifics. HOUT register ($240000) MSB LSB ---- --xx xxxx xxxx : Horizontal position of HOUT pulse. VOUT register ($260000) MSB LSB ---- ---y yyyy yyyy : Vertical position of VOUT pulse. Mode register ($270000) MSB LSB ---- ---- ---- ---m : Sync mode (0= normal, 1= invalid) Tilemap signals Tilemap and mixer interface SA0-SA3 4-bit pixel data from tile pattern RAM. To mixer input SA3-0. (SB3-0) SA4-SA12 8-bit palette number from name table (bits 14-7). To mixer input SA12-4. (SB12-4) SA13 1-bit priority field from name table bit 15. To mixer input FA (FB). SKA Background/window indicator. To mixer input WA (WB). ABSEL Overlapping or side-by-side background indicator. To mixer input AXBV. DSPABH ABSEL override flag. Outputs the state of bit 15 of the current scanline in the Plane A Window line scroll table for one scanline (656 pixels). To mixer input AXBH. ---------------------------------------------------------------------------- System timing ---------------------------------------------------------------------------- Display timing 656 pixels per scanline: 69 pixels from /HSYNC high to /BLANK high (left border) 496 pixels from /BLANK high to /BLANK low (active display) 43 pixels from /BLANK low to /HSYNC low (right border) 48 pixels from /HSYNC low to /HSYNC high (horizontal sync. pulse) 424 scanlines per frame: 25 scanlines from /VSYNC high to /BLANK high (top border) 384 scanlines from /BLANK high to /BLANK low (active display) 11 scanlines from /BLANK low to /VSYNC low (bottom border) 4 scanlines from /VSYNC low to /VSYNC high (vertical sync. pulse) The pixel clock is 16 MHz, giving an effetive frame rate of 57.52 frames per second. In the invalid display mode, horizontal timings are the same, vertical timings are approximately as follows. 512 scanlines per frame: 64 scanlines blanked 35 scanlines visible 4 lines sync during active display 409 scanlines visible There are some other quirks in this mode such as positioning of the interrupts, two VOUT pulses per frame which retriggers the sprite rendering, etc. This mode is not useful. ABSEL timing Ranges for this 10-bit counter are: $0000 : Plane B fills the whole screen $0001 : 1 pixels plane A, 495 pixels plane B $00F8 : 248 pixels plane A, 248 pixels plane B $01EF : 495 pixels plane A, 1 pixel plane B $01F0-: Plane A fills the whole screen -$03FF : Plane A fills the whole screen ABSEL is generated ahead of the blanking and sync signals by the tilemap generator because the mixer chip needs a few pixel clock cycles to process the data. It leads those signals by 4 pixels. The actual pulse width is can be wider than the display, but only the ranges listed above have any impact on the screen. Interrupt timing The V-Blank interrupt is generated on line 383 of 424, the last visible scanline of the active display. The interrupt request line is asserted on the negative edge of H-Sync before blanking is disabled, and is held for one scanline (656 pixels) such that it is negated on the negative edge of H-Sync of the next scanline, line 384. The sprite interrupt is generated 15 scanlines after the line where VOUT is pulsed. On the scanline where it is going to trigger, the interrupt request line is asserted 35 pixels after the negative edge of HOUT, and is held for one scanline (656 pixels) such that it is negated 35 pixels after the negative edge of HOUT on the next scanline. Note that if the V-Blank or sprite interrupt handlers exit before one scanline's worth of time is up, the interrupt line will still be asserted and the interrupt will be triggered again on the same line. Typically the V-Blank interrupt will do enough processing for this time to elapse, but some care may be needed with the sprite interrupt handler which may not have much to do before returning. When the timer uses HOUT as the clock source, the interrupt request line is is asserted on the rising edge of HOUT (e.g. one pixel after HOUT is pulsed) and held until the corresponding CPU interrupt enable register is read or written. Example timings using the BIOS defaults: HOUT = FFC6 VOUT = FFF0 - V-Blank interrupt occurs on line 383 (last active line of display) - VOUT pulsed on line 409 - HOUT pulsed 39 pixels after the falling edge of HSYNC - Sprite interrupt occurs on line 424, 74 pixels after the falling edge of HSYNC (35 pixels after the falling edge of HOUT). ---------------------------------------------------------------------------- Sprites ---------------------------------------------------------------------------- Command list Each command is 16 bits. The command counter is 11 bits wide, so only 2048 commands starting at address zero can be processed. This restricts the command list to the first 32K of sprite RAM. Draw command 00 : 00z- -lll llll llll : Independent zoom enable, link 02 : wwww wwww hhhh hhhh : Horizontal zoom, vertical zoom 04 : --nn nnnn nnnn nnnn : Tile number 06 : pp-- cccc cccc cccc : Global pen modifier bits, CLUT address 08 : vhhh yyyy yyyy yyyy : Vertical flip, sprite height, Y-coordinate 0A : hwww xxxx xxxx xxxx : Horizontal flipp, sprite width, X-coordinate 0C : ---- ---- ---- ---- : Unused 0E : ---- ---- ---- ---- : Unused Color look-up tables (CLUTs) CLUTs are 16 bytes and can be positioned anywhere within the first 64K of sprite RAM. The sprite chip loads a CLUT into internal memory if the CLUT specified in drawing command is different from the one used by the last drawing command. The pen modifier function (see below) can also force a CLUT reload even if two sprites have identical CLUTs specified. For example you can force a reload of the CLUT on every sprite by alternating bit 0 of word #6 for each draw command. Sprite size The 3-bit size field is as follows: 0 : 8 pixels 1 : 16 pixels 2 : 32 pixels 3 : 64 pixels 4 : 128 pixels 5 : 256 pixels 6 : 512 pixels 7 : 1024 pixels Coordinates Sprites are positioned in a 4096x4096 virtual space. Position 0,0 is coordinate (0,0) of the framebuffer, $0FFF is one pixel to the left/ one pixel above off screen. Sprites drawn near the edges of that virtual space wrap around, so you can draw a 64x64 sprite at (4000,4000) and part of it will appear in the upper left corner of the display. Zooming Normally the horizontal zoom value specified the zoom value for both axes. If bit 13 is set, they can be independently specified. Zoom values are: 0F : 1/4 size 1F : 1/2 size 3F : Normal size as specified by width/height 7F : 2x size FF : 4x size A zoom word of $7B4E zooms a 256x256 sprite to exactly 496x384 pixels. Rendering timing There is enough time to process all 2048 commands. There is also enough time to render 2048 8x8 sprites, but it is near the upper limit of how much drawing time is available. There is also enough time to process 1024 clip commands and 1024 8x8 sprite draw commands when they are interleaved. Drawing time goes down sharply as larger sized sprites or scaled-up sprites are used. If a sprite is 1024 pixels wide and 512 or 1024 pixels tall, there is only enough time to draw about 272 rows of 1024 pixels across to the framebuffer. A scaled-down sprite takes the same amount of time to draw as a normal sized one. A scaled-up sprite takes more time to draw proportional to the final scaled size. Sprites that are off-screen take the same amount of time to draw as an on-screen sprite. Other comments on rendering For performance reasons it seems like end codes should have been added to this system. They were included in the similar sprite hardware of System 32 and the Saturn. Similarly there is little feedback about the rendering state and no way to manually control framebuffer updates. So you can't lower the rendering rate to 30 Hz and draw more objects in two passes. This limitation was accounted for in the Saturn. For a double buffered display, an ideal method of preparing sprites is to have two sprite command lists in RAM, and change the link field of the first entry to point to one or the other. This would allow you to completely modify one list while the hardware renders from the other. Even though there is enough time to draw 2048 sprites, the sprite chip can also only process 2048 commands. If you split the RAM into two lists you can have two lists of about 1024 entries each. This artificially halves the on-screen sprite count just because there aren't enough addressable commands left, even though there is sufficient drawing time. If the command list counter was 13 bits instead of 12 this limit would not exist. Given how large sprite RAM can be (256K to 512K) it seems unusual to limit the commands to the first 32K and CLUTs to the first 64K. Skip command 00 : 10-- ---- ---- ---- : Skip command 00 : ---- -lll llll llll : Link field 02 : ---- ---- ---- ---- : Unused 04 : ---- ---- ---- ---- : Unused 06 : ---- ---- ---- ---- : Unused 08 : ---- ---- ---- ---- : Unused 0A : ---- ---- ---- ---- : Unused 0C : ---- ---- ---- ---- : Unused 0E : ---- ---- ---- ---- : Unused The skip command provides a quick way to disable sprites by setting bit 15 of their lead entry. All other fields are unused, and processing continues with the next command specified by the link field. End command 00 : 11-- ---- ---- ---- : End command 02 : ---- ---- ---- ---- : Unused 04 : ---- ---- ---- ---- : Unused 06 : ---- ---- ---- ---- : Unused 08 : ---- ---- ---- ---- : Unused 0A : ---- ---- ---- ---- : Unused 0C : ---- ---- ---- ---- : Unused 0E : ---- ---- ---- ---- : Unused This command ends rendering. No more commands will be parsed until the next frame. Rendering can also end when you run out of drawing time (too many large objects rendered), or if the link fields create a loop. When this happens the loop is repeatedly processed until rendering time is over. Clip command 00 : 01-- ---- ---- ---- : Clip command 00 : ---- -lll llll llll : Link field 02 : hv-- ---- ---- ---- : Horizontal flip flag, vertical flip flag (1=on) 02 : --c- ---- ---- ---- : Clip mode (1=inclusive, 0=exclusive) 02 : ---- ---- ---- --pp : Global pen modifier bits 04 : ---- ---t tttt tttt : Top scanline of clipping rectangle 06 : ---- ---l llll llll : Left pixel column of clipping rectangle 08 : ---- ---b bbbb bbbb : Bottom scanline of clipping rectangle 0A : ---- ---r rrrr rrrr : Right pixel column of clipping rectangle 0C : ---- ---- ---- ---- : Unused 0E : ---- ---- ---- ---- : Unused Flip flags The flip flags affect how the framebuffer is addressed, it isn't related to the per-sprite flip flags. If the horizontal flip bit is set, the X position to draw at is 511-X. If the vertical flip bit is set, the Y position to draw at is 383-Y. For example if both flip bits are set, a sprite at (0,0) that would normally drawn to the right and downwards from that position is now drawn at (511,383) to the left and upwards from that new position. Clip mode If the clip mode is set to 0 (inclusive), the clipping rectangle defines an area where sprites can be drawn. Sprites outside that area are not drawn. If the clip mode is set to 1 (exclusive), the clipping rectangle defines an area where sprites cannot be drawn. Sprites outside that area are drawn. If the top coordinate is larger than the bottom coordinate, or if the left coordinate is larger than the right coordinate, the clipping function is disabled regardles of the clip mode. If the top coordinate is equal to the bottom coordinate, or if the left coordinate is equal to the right coordinate, clipping is enabled for a single pixel (point, column, or row) area. For example if all clip coordinates have the same value, the clip area is a single pixel at that coordinate. Clipping does not speed up sprite rendering, even if a sprite is partially or entirely clipped. There is only enough state for one clipping window; the hardware doesn't support two clip windows (e.g. an inclusive and exclusive window). Global pen modifier This function modifies bits 7,6 of the 8-bit pixel written to the framebuffer. It is controlled globally by the clip command and locally by the draw command as follows: - Clip command, word #4, bits 1,0 - Draw command, word #4, bits 15,14 The possible settings are: Clip Draw Function 0000 0000 No change 0000 4000 No change 0000 8000 No change 0000 C000 No change 0001 0000 Reset bit 6 0001 4000 Set bit 6 0001 8000 Reset bit 6 0001 C000 Set bit 6 0002 0000 Reset bit 7 0002 4000 Reset bit 7 0002 8000 Set bit 7 0002 C000 Set bit 7 0003 0000 Reset bits 7,6 0003 4000 Reset bit 7, set bit 6 0003 8000 Set bit 7, reset bit 6 0003 C000 Set bits 7,6 The processing flow is as follows: 1. Read pixel nibble from tile data, look up corresponding value in CLUT 2. If CLUT value is zero treat pixel as transparent 3. Modify CLUT index, look up value in CLUT 4. If CLUT value is zero treat pixel as transparent Because transparency is evaluated twice, this ensures a pixel that maps to a CLUT value of $00 is always transparent, even if the modification would have made it opaque. Conversely the modifications can make an opaque pen transparent; such as if the CLUT value was $C0 and the modifier to reset bits 7,6 was used. This function simplifies modifying the priority (or palette) for sprites without having to go through and modify multiple sprite attributes in RAM. Cache behavior Even if two sprites have the same CLUT specified in draw command word #4, if the pen modifier function changes the final CLUT used during rendering then the CLUT cache is reloaded. Issuing a clip command itself does not affect the last cached CLUT value. Framebuffer scanning When the sprite chip scans out the framebuffer data to be combined with the tilemap chip's pixel stream, this scanning operation needs to be synchronized to the display signals. To do this, the sprite chip inputs three signals from the tilemap chip: - 16 MHz pixel clock. - HOUT, a one pixel wide negative pulse. - VOUT, a one scanline (656 pixel) wide negative pulse. HOUT is generated by a comparator that compares the horizontal pixel counter to a 16-bit register at $240000. When the count matches the register contents, HOUT is asserted. This happens on every scanline of the display, or 424 times per frame VOUT is generated by a comparator that compares the vertical scanline counter to a 16-bit register at $260000. When the count matches the register contents, VOUT is asserted. This happens once per frame. If the HOUT and VOUT registers are programmed to have invalid values such that one or both signals are not pulsed, the sprite generator uses the last valid settings they were set to. This allows the sprite chip to continue to scan out the framebuffer with a complete absence of any video synchronization signals other than the pixel clock. To accomplish this, I can only assume it has its own internal pixel and scanline counters. By counting durations between HOUT and VOUT pulses it can determine the frame extents: - Two HOUT pulses are 656 pixels apart - Two VOUT pulses are 424 scanlines apart This allows it to continue to generate internal timing signals even when they aren't supplied externally. Using HOUT and VOUT Changing these values allow the framebuffer layer to be scrolled relative to the tilemap layer. However this also affects when the sprite chip interrupt is generated relative to the V-Blank interrupt. It seems to be more useful as a way to center the 512x384 framebuffer within the 496x384 visible display. Based on the display width and height as defined by the HOUT and VOUT pulses, which define an internal screen state, the sprite chip only outputs the 512x384 framebuffer for the upper left corner of the 656x424 frame. If the HOUT and VOUT registers are set up so that a non-visible portion of the framebuffer is shown in the active display, the sprite chip outputs a zero value on the pixel bus. You do not see any framebuffer data that is repeated within that area, nor is garbage shown. This would allow adjustment of HOUT and VOUT to "shake" the sprite layer for a game effect without revealing repeated data or garbage outside of the framebuffer extents. With the BIOS defaults of HOUT=$FFC6, VOUT=$FFF0, this aligns framebuffer position (8,0) with display position (0,0), which provides an 8-pixel wide off-screen area to the left of the visible portion of the framebuffer. To map framebuffer position (0,0) to display position (0,0) a value of $FFCE should be used for HOUT. HOUT can be changed per-scanline to change the framebuffer horizontal scroll on every scanline. VOUT seems to be latched at multiple points in a frame outside of the active display, but at least during the active display it cannot be used to adjust the vertical scrolling on a line by line basis. Settings for HOUT and VOUT ranges VOUT ranges This is a 9-bit register. Pulse locations: 0000 : Pulse triggered on first line of active display 017F : Pulse triggered on last line of active display 0180- 01D7 : No match 01D8 : Pulse triggered on first line of vertical blanking 01FF : Last line of vertical blanking 0200 : Pulse triggered on first line of active display HOUT ranges This is a 10-bit register. Pulse locations: 0000 : 97 pixels from falling edge of H-sync 0001 : 98 pixels from falling edge of H-sync 0014 : 117 pixels from falling edge of H-sync (synch. with +ve edge of BLANK) 0204 : 613 pixels from falling edge of H-sync (synch. with -ve edge of BLANK) 022E : 656 pixels from falling edge of H-sync 022F : 0 pixels from falling edge of H-sync (synch. with -ve edge of SYNC) 0230-: No match -039F : No match 03A0 : 1 pixels from falling edge of H-sync 03CF : 48 pixels from falling edge of H-sync (synch. with +ve edge of SYNC) 03FF : 96 pixels from falling edge of H-sync ---------------------------------------------------------------------------- End ----------------------------------------------------------------------------