18 KiB
Table of Contents
- Audio & Video
- Video
- Audio
- Interrupts
- The Sentinel 65X A/V Port
- VERA Memory
- Hardware Registers
- ADDRx_L
- ADDRx_M
- ADDRx_H
- DATA0
- DATA1
- CTRL
- IEN
- ISR
- IRQLINE_L / SCANLINE_L
- DC_VIDEO / DC_HSTART
- DC_HSCALE / DC_HSTOP
- DC_VSCALE / DC_VSTART
- DC_BORDER / DC_VSTOP
- L0_CONFIG
- L0_MAPBASE
- L0_TILEBASE
- L0_HSCROLL_L / L0_HSCROLL_H
- L0_VSCROLL_L / L0_VSCROLL_H
- Layer 1 Registers
- AUDIO_CTRL
- AUDIO_RATE
- AUDIO_DATA
- SPI_DATA
- SPI_CTRL
- Colour Palette
- 16-Bit Reads/Writes
Audio & Video
The VERA FPGA core, implemented on an iCE40 UltraPlus 5K FPGA, is used to generate all audio and video signals produced by Sentinel 65X. This core, developed for the Commander X16 project by Frank van den Hoef, is licensed under the MIT license. It has been modified by Brian Swetland for Sentinel 65X, including porting it to be built using the Yosys open-source FPGA toolchain.
Video
The VERA video generator outputs a fixed 640x480, 60Hz digital RGB signal, with a total of 4,096 possible colours, using a 12-bit R4G4B4 colour space.
The video generation is done using two independent tile/bitmap layers, and a third layer composed of 128 sprites. VERA supports a single palette of 256 colours, freely chosen from the 4,096 possible colours available. An approximation of this colour gamut of 4,096 colours can be seen below:
Audio
The VERA FPGA core produces audio output in i2S format, which is fed to the A/V port for conversion into an analog or digital format suitable for the target display device.
Audio is generated using a 16-voice stereo programmable sound generator, with each voice able to generate sounds independently, with the waveform for each chosen freely from among Pulse, Sawtooth, Triangle, and Noise.
VERA also generates sampled 48KHz 16-bit stereo audio from a 4KB on-chip memory buffer.
Interrupts
The VERA implementation in Sentinel 65X has a dedicated vectored interrupt line to the CPU, which can be triggered by any or all of four conditions: Sprite collision, line number, PCM buffer status, or VSYNC.
The Sentinel 65X A/V Port
Audio and video output in Sentinel 65X is directed to a pin header, which is connected to a small daughterboard which actually generates the final audio and video output signals, using electronics and connectors appropriate to the target display.
Pinout
The A/V port is a 24-pin female pin header, with a pin and row pitch of 2.54mm. The pinout of the port, as seen from above, is shown in the following table:
Pin | Label | Label | Pin | |
---|---|---|---|---|
1 | +3.3V | +5V | 2 | |
3 | HSYNC | VSYNC | 4 | |
5 | RGB_R0 | RGB_R1 | 6 | |
7 | RGB_R2 | RGB_R3 | 8 | |
9 | RGB_G0 | RGB_G1 | 10 | |
11 | RGB_G2 | RGB_G3 | 12 | |
13 | RGB_B0 | RGB_B1 | 14 | |
15 | RGB_B2 | RGB_B3 | 16 | |
17 | LRCK | BCK | 18 | |
19 | ADATA | SYSCLK | 20 | |
21 | SCL | SDA | 22 | |
23 | GND | GND | 24 |
VERA Memory
VERA implements 128KB of internal memory, which exists in its own independent address space, connected to the CPU's address space through address and data registers. This RAM's address space is numbered from 0x00000
to 0x1FFFF
, and is organized as in the following table:
Address Range | Description |
---|---|
0x00000 - 0x1F9BF |
Video RAM |
0x1F9C0 - 0x1F9FF |
Sound Registers |
0x1FA00 - 0x1FBFF |
Colour Palette |
0x1FC00 - 0x1FFFF |
Sprite Attributes |
Hardware Registers
VERA is configured and controlled using a series of 32 memory-mapped I/O registers, located in the address space from 0x00DF00
to 0x00DF1F
.
ADDRx_L
The ADDRx_L
register is actually two registers, the ADDR0_L
and ADDR1_L
registers. Which of the two is accessed at memory address 0x00DF00
depends on the contents of ADDRSEL
, which is bit 0 of the CTRL
register, located at 0x00DF05
.
The ADDR0_L
and ADDR1_L
registers control the low byte of the selected address in VERA memory for reading or writing with the DATA0
and DATA1
registers, located at 0x00DF03
and 0x00DF04
respectively.
ADDRx_M
The ADDRx_M
register is actually two registers, the ADDR0_M
and ADDR1_M
registers. Which of the two is accessed at memory address 0x00DF01
depends on the contents of ADDRSEL
, which is bit 0 of the CTRL
register, located at 0x00DF05
.
The ADDR0ML
and ADDR1_M
registers control the middle byte of the selected address in VERA memory for reading or writing with the DATA0
and DATA1
registers, located at 0x00DF03
and 0x00DF04
respectively.
ADDRx_H
The ADDRx_H
register is actually two registers, the ADDR0_H
and ADDR1_H
registers. Which of the two is accessed at memory address 0x00DF00
depends on the contents of ADDRSEL
, which is bit 0 of the CTRL
register, located at 0x00DF05
.
The ADDR0_H
and ADDR1_H
registers control the low byte of the selected address in VERA memory for reading or writing with the DATA0
and DATA1
registers, located at 0x00DF03
and 0x00DF04
respectively.
Bit 0 of the ADDRx_H
is bit 16 of the address of the data port selected by ADDRSEL
. Bits 1 and 2 of ADDRx_H
are unused. Bit 3 is called DECR0
or DECR1
; when this bit is clear, the address of the selected data port will increment by the amount set with bits 4-7, called INCR0
or INCR1
, according to the table below. When DECR0
or DECR1
is set, then the address will decrement by the same amount when the matching data register is read from or written to.
INCR value |
Address Increment |
---|---|
0 | 0 |
1 | 1 |
2 | 2 |
3 | 4 |
4 | 8 |
5 | 16 |
6 | 32 |
7 | 64 |
8 | 128 |
9 | 256 |
10 | 512 |
11 | 40 |
12 | 80 |
13 | 160 |
14 | 320 |
15 | 640 |
DATA0
The DATA0
register, located at 0x00DF03
, is the first of two data registers available from VERA. It reads or writes the address in VERA's internal memory set in ADDR0_L
, ADDR0_M
, and ADDR0_H
.
If the value in INCR0
is nonzero, then after reading or writing from or to DATA0
, the address stored in ADDR0_L
, ADDR0_M
, and ADDR0_H
will be incremented by the number of addresses in the table above. If DECR0
is set, then the address will decrement by that amount instead.
DATA1
DATA1
, located at 0x00DF04
, is identical in function to DATA0
, but uses the address and increment settings stored in ADDR1_H
instead of ADDR0_H
.
CTRL
The CTRL
register, located at 0x00DF05
, contains three significant bits: bit 0, called ADDRSEL
, determines which DATAx
register the ADDRx
registers refer to. Bit 1, called DCSEL
, controls which set of registers are accessed at addresses 0x00DF09
through 0x00DF0C
. Bit 7, called RESET
, will reset VERA to the initial power-on state when a 1
value is written to it.
IEN
The IEN
register, located at 0x00DF06
, has six bits which relate to the generation of VERA interrupts:
- Bit 0, called
IEN_VSYNC
, enables the VSYNC interrupt when set. - Bit 1, called
IEN_LINE
, enables the raster-line interrupt when set. - Bit 2, called
IEN_SPRCOL
, enables the sprite collision interrupt when set. - Bit 3, called
IEN_AFLOW
, enables the interrupt triggered when the PCM sample buffer is less than 1/4 full. - Bit 6 contains the high-order bit of the 9-bit value of the
SCANLINE
register, located at0x00DF08
. Both this bit and theSCANLINE
register are read-only. - Bit 7 contains the high-order bit of the 9-bit value of the
IRQLINE
register, located at0x00DF08
. Both this bit and theIRQLINE
register are write-only.
ISR
The ISR
register, located at 0x00DF07
, contains flag bits which identify the source of the active VERA interrupt:
- Bit 0, called
ISR_VSYNC
, identifies a VSYNC interrupt condition when set. - Bit 1, called
ISR_LINE
, identifies a raster line interrupt condition when set. - Bit 2, called
ISR_SPRCOL
, identifies a sprite collision interrupt condition when set. - Bit 3, called
ISR_AFLOW
, identifies a PCM sample buffer low interrupt condition when set. - Bits 4-7 store the sprite collision data.
Writing a 1
value to bits 0, 1, or 2 will clear the interrupt state of the relevant interrupt source. Bit 3 can only be cleared by filling the PCM sample buffer to at least 1/4 of its capacity.
IRQLINE_L / SCANLINE_L
The low order 8 bits of the current scanline and the scanline which is set to trigger the scanline interrupt share the address 0x00DF08
-- IRQLINE_L
is write-only, and SCANLINE_L
is read-only, so there is no conflict.
DC_VIDEO / DC_HSTART
The DC_Video
and DC_HSTART
registers share the address 0x00DF09
; which one is accessed at that address is determined by the DCSEL
flag bit in the CTRL register -- a 0
value in DCSEL
will enable the DC_VIDEO
register, and a 1
value the DC_HSTART
register.
DC_VIDEO
stores three flag bits:
- Bit 4 enables tile/bitmap layer 0 when set to
1
. - Bit 5 enables tile/bitmap layer 1 when set to
1
. - Bit 6 enables sprites when set to
1
.
DC_HSTART
controls the first active column of the screen, relative to the 640x480 display area. The value is the top 8 bits of a 10-bit number, the low order 2 bits of which are implied to be 0 -- that is, the value is an 8 bit number which will be multiplied by 4.
DC_HSCALE / DC_HSTOP
The DC_HSCALE
and DC_HSTOP
registers share the address 0x00DF0A
; which one is accessed at that address is determined by the DCSEL
flag bit in the CTRL register -- a 0
value in DCSEL
will enable the DC_HSCALE
register, and a 1
value the DC_HSTOP
register.
DC_HSCALE
sets a fractional horizontal scaling factor of the active part of the screen; a value of 128 will output one pixel for each input pixel, and a value of 64 will output two pixels for each input pixel.
DC_HSTOP
controls the last active column of the screen, relative to the 640x480 display area. The value is the top 8 bits of a 10-bit number, the low order 2 bits of which are implied to be 0 -- that is, the value is an 8 bit number which will be multiplied by 4.
DC_VSCALE / DC_VSTART
The DC_VSCALE
and DC_VSTART
registers share the address 0x00DF0B
; which one is accessed at that address is determined by the DCSEL
flag bit in the CTRL register -- a 0
value in DCSEL
will enable the DC_VSCALE
register, and a 1
value the DC_VSTART
register.
DC_VSCALE
sets a fractional vertical scaling factor of the active part of the screen; a value of 128 will output one pixel for each input pixel, and a value of 64 will output two pixels for each input pixel.
DC_VSTART
controls the first active row of the screen, relative to the 640x480 display area. The value is the top 8 bits of a 9-bit number, the low order bit of which is implied to be 0 -- that is, the value is an 8 bit number which will be multiplied by 2.
DC_BORDER / DC_VSTOP
The DC_BORDER
and DC_VSTOP
registers share the address 0x00DF0B
; which one is accessed at that address is determined by the DCSEL
flag bit in the CTRL register -- a 0
value in DCSEL
will enable the DC_BORDER
register, and a 1
value the DC_VSTOP
register.
DC_BORDER
stores the 8-bit pallette index of the colour used to fill the "inactive" region of the screen, as determined by the DC_HSTART
, DC_HSTOP
, DC_VSTART
, and DC_VSTOP
registers.
DC_VSTOP
controls the last active row of the screen, relative to the 640x480 display area. The value is the top 8 bits of a 9-bit number, the low order bit of which is implied to be 0 -- that is, the value is an 8 bit number which will be multiplied by 2.
L0_CONFIG
The L0_CONFIG
register, located at 0x00DF0D
, controls the configuration of tile/bitmap layer 0.
Bits 0-1 store the colour depth of the layer; that is, the number of bits used per pixel in the tile or bitmap data used to render the layer:
Value | Depth |
---|---|
0 | 1 bpp |
1 | 2 bpp |
2 | 4 bpp |
3 | 8 bpp |
Bit 2 sets the layer to use tiles mode when set to 0
; a value of 1
will set the layer to use bitmap mode.
Bit 3, called T256C
, is used with tiles modes to enable or disable 256-colour 1bpp mode.
Bits 4-5 encode the tile map width, while bits 6-7 encode the tile map height, according to the values in the following table:
Value | Map Width / Height |
---|---|
0 | 32 tiles |
1 | 64 tiles |
2 | 128 tiles |
3 | 256 tiles |
L0_MAPBASE
The L0_MAPBASE
register, located at 0x00DF0DE
, encodes the high 8 bits of the 17-bit address in VERA memory where the map data for layer 0 can be found; since the bottom 9 bits are implicitly 0
, this means the map data must always begin on a 512-byte alignment boundary.
L0_TILEBASE
The L0_TILEBASE
register, located at 0x00DF0F
, encodes the following data:
- Bit 0 controls the pixel width of tiles in layer 0; a
0
value means that a tile is 8 pixels wide, while a1
value means that tile is 16 pixels wide. - Bit 1 controls the pixel height of tiles in layer 0; a
0
value means that a tile is 8 pixels tall, while a1
value means that tile is 16 pixels tall. - Bits 2-7 hold the top six bits of the 17-bit address in VERA memory where the tile data can be found; as bits 0-10 are implicitly
0
, this means that tile data is always aligned on a 2,048-byte boundary.
L0_HSCROLL_L / L0_HSCROLL_H
The L0_HSCROLL_L
and L0_HSCROLL_H
registers, located at addresses 0x00DF10
and 0x00DF11
, encode the low order byte and high order 4 bits, respectively, of the layer 0 horizontal scroll value; this value ranges from 0 to 4,095, and is defined in terms of pixels.
L0_VSCROLL_L / L0_VSCROLL_H
The L0_VSCROLL_L
and L0_VSCROLL_H
registers, located at addresses 0x00DF12
and 0x00DF13
, encode the low order byte and high order 4 bits, respectively, of the layer 0 vertical scroll value; this value ranges from 0 to 4,095, and is defined in terms of pixels.
Layer 1 Registers
The layer 1 control registers function exactly the same as their equivalents for layer 0:
L1_CONFIG
is located at0x00DF14
L1_MAPBASE
is located at0x00DF15
L1_TILEBASE
is located at0x00DF16
L1_HSCROLL_L
is located at0x00DF17
L1_HSCROLL_H
is located at0x00DF18
L1_VSCROLL_L
is located at0x00DF19
L1_VSCROLL_H
is located at0x00DF1A
AUDIO_CTRL
The AUDIO_CTRL
register at 0x00DF1B
controls several aspects of the PCM audio subsystem:
- Bits 0-3 control the volume of the PCM sample playback.
- Bit 4 controls whether the PCM audio will be monaural (
0
value) or stereo (1
value). - Bit 5 controls whether PCM audio sample data is 8-bit (
0
value) or 16-bit (1
value). - Bit 6 is a read-only flag bit which indicates that the PCM sample buffer is empty when it is set to
1
. - Bit 7 encodes two values; when read, this bit will be a
1
when the PCM sample buffer is full. In that case, writes to the buffer are silently ignored. When a1
value is written to this bit, the PCM sample buffer will be cleared.
AUDIO_RATE
The AUDIO_RATE
register at 0x00D1C
controls the sample rate of the PCM audio playback:
Value | Description |
---|---|
128 | 48828.125Hz |
64 | 24414Hz |
32 | 12207Hz |
0 | No playback |
An intentional mismatch between the actual recorded sample rate and the sample rate of the playback can be used to speed up or slow down the PCM sample.
AUDIO_DATA
The AUDIO_DATA
register at 0x00DF1D
is a write-only register which accepts byte writes to the PCM audio buffer.
SPI_DATA
The SPI_DATA
register at 0x00DF1E
is used to read and write data from the selected SPI device a byte at a time.
SPI_CTRL
The SPI_CTRL
register at 0x00DF1F
is used to control the SPI subsystem:
- Bit 0 is used to assert the SPI select line with a
1
value, and deassert it with a0
value. - Bit 1 controls the clock rate of the SPI data clock; when set to
0
this will be approximately 12.5MHz, while when set to1
the clock will run at approximately 390KHz, which can be useful with slow SPI devices or when an SD card requires a slower clock during initialization. - Bit 2 controls the "auto-transmit" function, which begins reading a new byte from SPI (sending the value
0xFF
) automatically when theSPI_DATA
register is read. This can be used to simplify and speed up SPI reads. - Bit 7 will read as a
1
value as long as a byte is being transferred over SPI.
Colour Palette
VERA supports a single, shared palette of 256 colours, each of which is freely chosen from among the 4,096 possible colours the hardware can generate.
The palette is stored in VERA memory beginning at VERA address 0x1FA00
, and consists of 256 entries with the following format:
Byte | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
---|---|---|---|---|---|---|---|---|
0 | G3 | G2 | G1 | G0 | B3 | B2 | B1 | B0 |
0 | R3 | R2 | R1 | R0 |
16-Bit Reads/Writes
With appropriate configuration of registers, it is possible to perform sequential 16-bit reads and writes to VERA address space:
- Set
ADDR0
to the lowest address to read or write in VERA memory, and clearDECR0
. - Set
ADDR1
to a value exactly one address higher thanADDR0
, and clearDECR1
. - Set both
INCR0
andINCR1
to a value of0
or2
. - Set the CPU register to be used to read from or write to VERA memory to be 16 bits wide.
- Read or write to
DATA0
using a 16-bit load or store instruction. This will implicitly readDATA1
. - If
INCR0
andINCR1
are both set to0
, then the address will not increment at all; if they are set to2
, then the address of bothDATA0
andDATA1
will be incremented by2
addresses.
Such 16-bit reads and writes are almost twice as cycle-efficient as reading or writing in 8-bit increments, as the extra byte takes only a single extra CPU cycle.
The SDK will provide a C function pair vera_memcpy_read()
and vera_memcpu_write()
handle bulk data transfers; it will use this mode of reading and writing without futher intervention by the programmer.