From 8714ce16898da7e1431083bf62029a613355361d Mon Sep 17 00:00:00 2001 From: Frank van den Hoef Date: Mon, 14 Mar 2022 18:09:37 +0100 Subject: [PATCH] Adding programmer's reference. --- .gitignore | 1 + doc/VERA Programmer's Reference.md | 748 +++++++++++++++++++++++++++++ 2 files changed, 749 insertions(+) create mode 100644 .gitignore create mode 100644 doc/VERA Programmer's Reference.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/doc/VERA Programmer's Reference.md b/doc/VERA Programmer's Reference.md new file mode 100644 index 0000000..dbe891f --- /dev/null +++ b/doc/VERA Programmer's Reference.md @@ -0,0 +1,748 @@ +# VERA Programmer's Reference + +Version 0.9 + +_Author: Frank van den Hoef_ + +**This is preliminary documentation and the specification can still change at any point.** + +This document describes the **V**ersatile **E**mbedded **R**etro **A**dapter or VERA. The VERA consists of: + +- Video generator featuring: + - Multiple output formats (VGA, NTSC Composite, NTSC S-Video, RGB video) at a fixed resolution of 640x480@60Hz + - Support for 2 layers, both supporting either tile or bitmap mode. + - Support for up to 128 sprites. + - Embedded video RAM of 128kB. + - Palette with 256 colors selected from a total range of 4096 colors. +- 16-channel Programmable Sound Generator with multiple waveforms (Pulse, Sawtooth, Triangle, Noise) +- High quality PCM audio playback from an 4kB FIFO buffer featuring up to 48kHz 16-bit stereo sound. +- SPI controller for SecureDigital storage. + +# Registers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddrNameBit 7Bit 6Bit 5 Bit 4Bit 3 Bit 2Bit 1 Bit 0
$9F20ADDRx_L (x=ADDRSEL)VRAM Address (7:0)
$9F21ADDRx_M (x=ADDRSEL)VRAM Address (15:8)
$9F22ADDRx_H (x=ADDRSEL)Address IncrementDECR-VRAM Address (16)
$9F23DATA0VRAM Data port 0
$9F24DATA1VRAM Data port 1
$9F25CTRLReset-DCSELADDRSEL
$9F26IENIRQ line (8)-AFLOWSPRCOLLINEVSYNC
$9F27ISRSprite collissionsAFLOWSPRCOLLINEVSYNC
$9F28IRQLINE_LIRQ line (7:0)
$9F29DC_VIDEO (DCSEL=0)Current FieldSprites EnableLayer1 EnableLayer0 Enable-Chroma DisableOutput Mode
$9F2ADC_HSCALE (DCSEL=0)Active Display H-Scale
$9F2BDC_VSCALE (DCSEL=0)Active Display V-Scale
$9F2CDC_BORDER (DCSEL=0)Border Color
$9F29DC_HSTART (DCSEL=1)Active Display H-Start (9:2)
$9F2ADC_HSTOP (DCSEL=1)Active Display H-Stop (9:2)
$9F2BDC_VSTART (DCSEL=1)Active Display V-Start (8:1)
$9F2CDC_VSTOP (DCSEL=1)Active Display V-Stop (8:1)
$9F2DL0_CONFIGMap HeightMap WidthT256CBitmap ModeColor Depth
$9F2EL0_MAPBASEMap Base Address (16:9)
$9F2FL0_TILEBASETile Base Address (16:11)Tile HeightTile Width
$9F30L0_HSCROLL_LH-Scroll (7:0)
$9F31L0_HSCROLL_H-H-Scroll (11:8)
$9F32L0_VSCROLL_LV-Scroll (7:0)
$9F33L0_VSCROLL_H-V-Scroll (11:8)
$9F34L1_CONFIGMap HeightMap WidthT256CBitmap ModeColor Depth
$9F35L1_MAPBASEMap Base Address (16:9)
$9F36L1_TILEBASETile Base Address (16:11)Tile HeightTile Width
$9F37L1_HSCROLL_LH-Scroll (7:0)
$9F38L1_HSCROLL_H-H-Scroll (11:8)
$9F39L1_VSCROLL_LV-Scroll (7:0)
$9F3AL1_VSCROLL_H-V-Scroll (11:8)
$9F3BAUDIO_CTRLFIFO Full / FIFO Reset-16-BitStereoPCM Volume
$9F3CAUDIO_RATEPCM Sample Rate
$9F3DAUDIO_DATAAudio FIFO data (write-only)
$9F3ESPI_DATAData
$9F3FSPI_CTRLBusy-Slow clockSelect
+ +## VRAM address space layout + +| Address range | Description | +| --------------- | ----------------- | +| $00000 - $1F9BF | Video RAM | +| $1F9C0 - $1F9FF | PSG registers | +| $1FA00 - $1FBFF | Palette | +| $1FC00 - $1FFFF | Sprite attributes | + +**_Important note: +Video RAM locations 1F9C0-1FFFF contain registers for the PSG/Palette/Sprite attributes. Reading anywhere in VRAM will always read back the 128kB VRAM itself (not the contents of the (write-only) PSG/Palette/Sprite attribute registers). Writing to a location in the register area will write to the registers in addition to writing the value also to VRAM. Since the VRAM contains random values at startup the values read back in the register area will not correspond to the actual values in the write-only registers until they are written to once. +Because of this it is highly recommended to initialize the area from 1F9C0-1FFFF at startup._** + +## Video RAM access + +The video RAM (VRAM) isn't directly accessible on the CPU bus. VERA only exposes an address space of 32 bytes to the CPU as described in the section [Registers](#registers). To access the VRAM (which is 128kB in size) an indirection mechanism is used. First the address to be accessed needs to be set (ADDRx_L/ADDRx_M/ADDRx_H) and then the data on that VRAM address can be read from or written to via the DATA0/1 register. To make accessing the VRAM more efficient an auto-increment mechanism is present. + +There are 2 data ports to the VRAM. Which can be accessed using DATA0 and DATA1. The address and increment associated with the data port is specified in ADDRx_L/ADDRx_M/ADDRx_H. These 3 registers are multiplexed using the ADDR_SEL in the CTRL register. When ADDR_SEL = 0, ADDRx_L/ADDRx_M/ADDRx_H become ADDR0_L/ADDR0_M/ADDR0_H. +When ADDR_SEL = 1, ADDRx_L/ADDRx_M/ADDRx_H become ADDR1_L/ADDR1_M/ADDR1_H. + +By setting the 'Address Increment' field in ADDRx_H, the address will be increment after each access to the data register. The increment register values and corresponding increment amounts are shown in the following table: + +| Register value | Increment amount | +| -------------: | ---------------: | +| 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 | + +Setting the **DECR** bit, will decrement instead of increment by the value set by the 'Address Increment' field. + +## Reset + +When **RESET** in **CTRL** is set to 1, the FPGA will reconfigure itself. All registers will be reset. The palette RAM will be set to its default values. + +## Interrupts + +Interrupts will be generated for the interrupt sources set in the lower 4 bits of **IEN**. +**ISR** will indicate the interrupts that have occurred. Writing a 1 to one of the lower 3 bits in **ISR** will clear that interrupt status. **AFLOW** can only be cleared by filling the audio FIFO for at least 1/4. + +**IRQ_LINE** specifies at which line the **LINE** interrupt will be generated. Note that bit 8 of this value is present in the **IEN** register. For interlaced modes the interrupt will be generated each field and the bit 0 of **IRQ_LINE** is ignored. + +The upper 4 (read-only) bits of the **ISR** register contain the [sprite collisions](#sprite-collisions) as determined by the sprite renderer. + +## Display composer + +The display composer is responsible of combining the output of the 2 layer renderers and the sprite renderer into the image that is sent to the video output. + +The video output mode can be selected using OUT_MODE in DC_VIDEO. + +| OUT_MODE | Description | +| -------: | -------------------------------------------------- | +| 0 | Video disabled | +| 1 | VGA output | +| 2 | NTSC composite | +| 3 | RGB interlaced, composite sync (via VGA connector) | + +Setting **'Chroma Disable'** disables output of chroma in NTSC composite mode and will give a better picture on a monochrome display. _(Setting this bit will also disable the chroma output on the S-video output.)_ + +**'Current Field'** is a read-only bit which reflects the active interlaced field in composite and RGB modes. (0: even, 1: odd) + +Setting **'Layer0 Enable'** / **'Layer1 Enable'** / **'Sprites Enable'** will respectively enable output from layer0 / layer1 and the sprites renderer. + +**DC_HSCALE** and **DC_VSCALE** will set the fractional scaling factor of the active part of the display. Setting this value to 128 will output 1 output pixel for every input pixel. Setting this to 64 will output 2 output pixels for every input pixel. + +**DC_BORDER** determines the palette index which is used for the non-active area of the screen. + +**DC_HSTART**/**DC_HSTOP** and **DC_VSTART**/**DC_VSTOP** determines the active part of the screen. The values here are specified in the native 640x480 display space. HSTART=0, HSTOP=640, VSTART=0, VSTOP=480 will set the active area to the full resolution. Note that the lower 2 bits of **DC_HSTART**/**DC_HSTOP** and the lower 1 bit of **DC_VSTART**/**DC_VSTOP** isn't available. This means that horizontally the start and stop values can be set at a multiple of 4 pixels, vertically at a multiple of 2 pixels. + +## Layer 0/1 registers + +**'Map Base Address'** specifies the base address of the tile map. _Note that the register only specifies bits 16:9 of the address, so the address is always aligned to a multiple of 512 bytes._ + +**'Tile Base Address'** specifies the base address of the tile data. _Note that the register only specifies bits 16:11 of the address, so the address is always aligned to a multiple of 2048 bytes._ + +**'H-Scroll'** specifies the horizontal scroll offset. A value between 0 and 4095 can be used. Increasing the value will cause the picture to move left, decreasing will cause the picture to move right. + +**'V-Scroll'** specifies the vertical scroll offset. A value between 0 and 4095 can be used. Increasing the value will cause the picture to move up, decreasing will cause the picture to move down. + +**'Map Width'**, **'Map Height'** specify the dimensions of the tile map: + +| Value | Map width / height | +| ----: | ------------------ | +| 0 | 32 tiles | +| 1 | 64 tiles | +| 2 | 128 tiles | +| 3 | 256 tiles | + +**'Tile Width'**, **'Tile Height'** specify the dimensions of a single tile: + +| Value | Tile width / height | +| ----: | ------------------- | +| 0 | 8 pixels | +| 1 | 16 pixels | + +In bitmap modes, the **'H-Scroll (11:8)'** register is used to specify the palette offset for the bitmap. + +### Layer display modes + +The features of the 2 layers are the same. Each layer supports a few different modes which are specified using **T256C** / **'Bitmap Mode'** / **'Color Depth'** in Lx_CONFIG. + +**'Color Depth'** specifies the number of bits used per pixel to encode color information: + +| Color Depth | Description | +| ----------: | ----------- | +| 0 | 1 bpp | +| 1 | 2 bpp | +| 2 | 4 bpp | +| 3 | 8 bpp | + +The layer can either operate in tile mode or bitmap mode. This is selected using the **'Bitmap Mode'** bit; 0 selects tile mode, 1 selects bitmap mode. + +The handling of 1 bpp tile mode is different from the other tile modes. Depending on the **T256C** bit the tiles use either a 16-color foreground and background color or a 256-color foreground color. Other modes ignore the **T256C** bit. + +### Tile mode 1 bpp (16 color text mode) + +**T256C** should be set to 0. + +**MAP_BASE** points to a tile map containing tile map entries, which are 2 bytes each: + + + + + + + + + + + + + + + + + + + + + + +
OffsetBit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0
0Character index
1Background colorForeground color
+ +**TILE_BASE** points to the tile data. + +Each bit in the tile data specifies one pixel. If the bit is set the foreground color as specified in the map data is used, otherwise the background color as specified in the map data is used. + +### Tile mode 1 bpp (256 color text mode) + +**T256C** should be set to 1. + +**MAP_BASE** points to a tile map containing tile map entries, which are 2 bytes each: + + + + + + + + + + + + + + + + + + + + + +
OffsetBit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0
0Character index
1Foreground color
+ +**TILE_BASE** points to the tile data. + +Each bit in the tile data specifies one pixel. If the bit is set the foreground color as specified in the map data is used, otherwise color 0 is used (transparent). + +### Tile mode 2/4/8 bpp + +**MAP_BASE** points to a tile map containing tile map entries, which are 2 bytes each: + + + + + + + + + + + + + + + + + + + + + + + + +
OffsetBit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0
0Tile index (7:0)
1Palette offsetV-flipH-flipTile index (9:8)
+ +**TILE_BASE** points to the tile data. + +Each pixel in the tile data gives a color index of either 0-3 (2bpp), 0-15 (4bpp), 0-255 (8bpp). This color index is modified by the palette offset in the tile map data using the following logic: + +- Color index 0 (transparent) and 16-255 are unmodified. +- Color index 1-15 is modified by adding 16 x palette offset. + +### Bitmap mode 1/2/4/8 bpp + +**MAP_BASE** isn’t used in these modes. **TILE_BASE** points to the bitmap data. + +**TILEW** specifies the bitmap width. TILEW=0 results in 320 pixels width and TILEW=1 results in 640 pixels width. + +The palette offset (in **'H-Scroll (11:8)'**) modifies the color indexes of the bitmap in the same way as in the tile modes. + +## SPI controller + +The SPI controller is connected to the SD card connector. The speed of the clock output of the SPI controller can be controlled by the **'Slow Clock'** bit. When this bit is 0 the clock is 12.5MHz, when 1 the clock is about 390kHz. The slow clock speed is to be used during the initialization phase of the SD card. Some SD cards require a clock less than 400kHz during part of the initialization. + +A transfer can be started by writing to **SPI_DATA**. While the transfer is in progress the BUSY bit will be set. After the transfer is done, the result can be read from the **SPI_DATA** register. + +The chip select can be controlled by writing the **SELECT** bit. Writing 1 will assert the chip-select (logic-0) and writing 0 will release the chip-select (logic-1). + +## Palette + +The palette translates 8-bit color indexes into 12-bit output colors. The palette has 256 entries, each with the following format: + + + + + + + + + + + + + + + + + + + + + + + +
OffsetBit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0
0GreenBlue
1-Red
+ +At reset, the palette will contain a predefined palette: + + 000,fff,800,afe,c4c,0c5,00a,ee7,d85,640,f77,333,777,af6,08f,bbb + 000,111,222,333,444,555,666,777,888,999,aaa,bbb,ccc,ddd,eee,fff + 211,433,644,866,a88,c99,fbb,211,422,633,844,a55,c66,f77,200,411 + 611,822,a22,c33,f33,200,400,600,800,a00,c00,f00,221,443,664,886 + aa8,cc9,feb,211,432,653,874,a95,cb6,fd7,210,431,651,862,a82,ca3 + fc3,210,430,640,860,a80,c90,fb0,121,343,564,786,9a8,bc9,dfb,121 + 342,463,684,8a5,9c6,bf7,120,241,461,582,6a2,8c3,9f3,120,240,360 + 480,5a0,6c0,7f0,121,343,465,686,8a8,9ca,bfc,121,242,364,485,5a6 + 6c8,7f9,020,141,162,283,2a4,3c5,3f6,020,041,061,082,0a2,0c3,0f3 + 122,344,466,688,8aa,9cc,bff,122,244,366,488,5aa,6cc,7ff,022,144 + 166,288,2aa,3cc,3ff,022,044,066,088,0aa,0cc,0ff,112,334,456,668 + 88a,9ac,bcf,112,224,346,458,56a,68c,79f,002,114,126,238,24a,35c + 36f,002,014,016,028,02a,03c,03f,112,334,546,768,98a,b9c,dbf,112 + 324,436,648,85a,96c,b7f,102,214,416,528,62a,83c,93f,102,204,306 + 408,50a,60c,70f,212,434,646,868,a8a,c9c,fbe,211,423,635,847,a59 + c6b,f7d,201,413,615,826,a28,c3a,f3c,201,403,604,806,a08,c09,f0b + +- Color indexes 0-15 contain the C64 color palette. +- Color indexes 16-31 contain a grayscale ramp. +- Color indexes 32-255 contain various hues, saturation levels, brightness levels. + +## Sprite attributes + +128 entries of the following format: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OffsetBit 7Bit 6Bit 5Bit 4Bit 3Bit 2Bit 1Bit 0
0Address (12:5)
1Mode-Address (16:13)
2X (7:0)
3-X (9:8)
4Y (7:0)
5-Y (9:8)
6Collision maskZ-depthV-flipH-flip
7Sprite heightSprite widthPalette offset
+ +| Mode | Description | +| ---- | ----------- | +| 0 | 4 bpp | +| 1 | 8 bpp | + +| Z-depth | Description | +| ------- | ------------------------------------- | +| 0 | Sprite disabled | +| 1 | Sprite between background and layer 0 | +| 2 | Sprite between layer 0 and layer 1 | +| 3 | Sprite in front of layer 1 | + +| Sprite width / height | Description | +| --------------------- | ----------- | +| 0 | 8 pixels | +| 1 | 16 pixels | +| 2 | 32 pixels | +| 3 | 64 pixels | + +**Rendering Priority** The sprite memory location dictates the order in which it is rendered. The sprite whose attributes are at the lowest location will be rendered in front of all other sprites; the sprite at the highest location will be rendered behind all other sprites, and so forth. + +**Palette offset** works in the same way as with the layers. + +## Sprite collisions + +At the start of the vertical blank **Collisions** in **ISR** is updated. This field indicates which groups of sprites have collided. If the field is non-zero the **SPRCOL** interrupt will be set. The interrupt is generated once per field / frame and can be cleared by making sure the sprites no longer collide. + +_Note that collisions are only detected on lines that are actually rendered. This can result in subtle differences between non-interlaced and interlaced video modes._ + +## Programmable Sound Generator (PSG) + +The audio functionality contains of 2 independent systems. The first is the PSG or Programmable Sound Generator. The second is the PCM (or Pulse-Code Modulation) playback system. + +16 entries (channels) of the following format: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OffsetBit 7Bit 6Bit 5Bit Bit 4Bit 3Bit 2Bit 1Bit 0
0Frequency word (7:0)
1Frequency word (15:8)
2RightLeftVolume
3WaveformPulse width
+ +**Frequency word** sets the frequency of the sound. +The formula for calculating the output frequency is: + + sample_rate = 25MHz / 512 = 48828.125 Hz + + output_frequency = sample_rate / (2^17) * frequency_word + +Thus the output frequency can be set in steps of about 0.373 Hz. + +_Example: to output a frequency of 440Hz (note A4) the **Frequency word** should be set to 440 / (48828.125 / (2^17)) = 1181_ + +**Volume** controls the volume of the sound with a logarithmic curve; 0 is silent, 63 is the loudest. +The **Left** and **Right** bits control to which output channels the sound should be output. + +**Waveform** controls the waveform of the sound: + +| Waveform | Description | +| -------: | ----------- | +| 0 | Pulse | +| 1 | Sawtooth | +| 2 | Triangle | +| 3 | Noise | + +**Pulse width** controls the duty cycle of the pulse waveform. A value of 63 will give a 50% duty cycle or square wave, 0 will give a very narrow pulse. + +Just like the other waveform types, the frequency of the noise waveform can be controlled using frequency. In this case a higher frequency will give brighter noise and a lower value will give darker noise. + +## PCM audio + +For PCM playback, VERA contains a 4kB FIFO buffer. This buffer needs to be filled in a timely fashion by the CPU. To facilitate this an **AFLOW** (Audio FIFO low) interrupt can be generated when the FIFO is less than 1/4 filled. + +### Audio registers + +**PCM Volume** controls the volume of the PCM playback, this has a logarithmic curve. A value of 0 is silence, 15 is the loudest. + +**Stereo** sets the data format to stereo. If this bit is 0 (mono), the same audio data is send to both channels. + +**16-bit** sets the data format to 16-bit. If this bit is 0, 8-bit data is expected. + +**FIFO Full** is a read-only flag that indicated if the FIFO is full. Any writes to the FIFO while this flag is 1 will be ignored. Writing a 1 to this register (**FIFO Reset**) will perform a FIFO reset, which will clear the contents of the FIFO buffer. + +**PCM sample rate** controls the speed at which samples are read from the FIFO. A few example values: + +| PCM sample rate | Description | +| --------------: | ----------------------------------------- | +| 128 | normal speed (25MHz / 512 = 48828.125 Hz) | +| 64 | half speed (24414 Hz) | +| 32 | quarter speed (12207 Hz) | +| 0 | stop playback | +| _>128_ | _invalid_ | + +Using a value of 128 will give the best quality (lowest distortion); at this value for every output sample, an input sample from the FIFO is read. Lower values will output the same sample multiple times to the audio DAC. Input samples are always read as a complete set (being 1/2/4 bytes). + +_NOTE: When setting up for PCM playback it is adviced to first set the sample rate at 0 to stop playback. First fill the FIFO buffer with some initial data and then set the desired sample rate. This can prevent undesired FIFO underruns._ + +### Audio data formats + +Audio data is two's complement signed. +Depending on the selected mode the data needs to be written to the FIFO in the following order: + +| Mode | Order in which to write data to FIFO | +| ------------- | ------------------------------------------------------------------------------------------- | +| 8-bit mono | \ | +| 8-bit stereo | \ \ | +| 16-bit mono | \ \ | +| 16-bit stereo | \ \ \ \ |