From 863db68b8f354cd9c260f0b30fa8bc832b5b33ea Mon Sep 17 00:00:00 2001 From: rej Date: Sat, 13 Sep 2025 09:01:03 +0200 Subject: [PATCH 1/3] Update AY8913 peripheral 20 docs --- docs/user_peripherals/20_AY8913.md | 57 +++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/docs/user_peripherals/20_AY8913.md b/docs/user_peripherals/20_AY8913.md index 03ade2c..8a71471 100644 --- a/docs/user_peripherals/20_AY8913.md +++ b/docs/user_peripherals/20_AY8913.md @@ -19,13 +19,27 @@ Peripheral index: 20 ## What it does -This is a replica of 8-bit classic **[AY-3-8913](https://en.wikipedia.org/wiki/General_Instrument_AY-3-8910)** 3-voice programmable sound generator (PSG) chip from General Instruments. The AY-3-8913 is a smaller variant of AY-3-8910 or its analog YM2149. +This is a replica of 8-bit classic **[AY-3-8910/AY-3-8912/AY-3-8913](https://en.wikipedia.org/wiki/General_Instrument_AY-3-8910)** 3-voice programmable sound generator (PSG) integrated into a modern RISC-V as a peripheral. +The AY-3-891x family of programmable sound generators was introduced by General Instrument in 1978. Variants of the AY-3-891x were broadly used in: + +- home computers: Amstrad CPC, Atari ST, Oric-1, Sharp X1, MSX, ZX Spectrum 128/+2/+3 +- game consoles: Intellivision, Vectrex +- and many arcade machines + +### Technical capabilities + +- **3 square wave** tone generators +- A single **white noise** generator +- A single **envelope** generator able to produce 10 different shapes +- Chip is capable to produce a range of waves from a **30 Hz** to **125 kHz**, defined by **12-bit** registers. +- **16** different volume levels on a logarithmic scale ## Register map -The behavior of the AY-3-891x is defined by 14 registers. All registers are READ ONLY! +The behavior of the AY-3-891x is defined by 14 registers. The register map matches the original AY-3-891x and should be able to play the original tunes without modifications. +All registers are **read only** in this peripheral and start in **unknown** uninitialised state upon reset! | Address | Access | Bits used | Function | Description | |---------|--------|----------------|------------------|------------------------| @@ -44,10 +58,45 @@ The behavior of the AY-3-891x is defined by 14 registers. All registers are READ | 12 | R | ```xxxxxxxx``` | ---//--- | 8-bit coarse frequency | | 13 | R | ```....xxxx``` | Envelope Shape | 4-bit shape control | +### Square wave tone generators + +Square waves are produced by counting down the 12-bit counters. Counter counts up from 0. Once the corresponsding register value is reached, counter is reset and +the output bit of the channel is flipped producing square waves. + +### Noise generator + +Noise is produced with 17-bit [Linear-feedback Shift Register (LFSR)](https://en.wikipedia.org/wiki/Linear-feedback_shift_register) that flips the output bit pseudo randomly. +The shift rate of the LFSR register is controller by the 5-bit counter. + +### Envelope + +The envelope shape is controlled with 4-bit register, but can take only 10 distinct patterns. The speed of the envelope is controlled with 16-bit counter. Only a single envelope is produced that can be shared by any combination of the channels. + +### Volume +Each of the three AY-3-891x channels have dedicated DAC that converts 16 levels of volume to analog output. Volume levels are 3 dB apart in AY-3-891x. + +## IO pins + +There is a single PWM output signal that is connected to all the output pins uo_out[7:0]. +The input pins are not used. + ## How to test -TODO: Explain how to use your project +All register state are in **unknown** uninitialised state upon reset. The very first thing you should do is to set them to zero! + +In order to play a standard pitch A440 note you have to enable Channel A tone in the mixer: + + register[7] = 0b00_001_000 + +Set volume loud: + + register[8] = 0b0000_1111 + +Set A440 tone using the formulas: + + register[0] = (2_000_000 // (16 * 440)) & 0xFF + register[1] = (2_000_000 // (16 * 440)) >> 8 ## External hardware -Tiny Tapeout Audio PMOD \ No newline at end of file +(Tiny Tapeout Audio PMOD)[https://store.tinytapeout.com/products/Audio-Pmod-p716541601] From 7fae4469e402969d5783cdeb7773c150f3d94f59 Mon Sep 17 00:00:00 2001 From: rej Date: Sat, 13 Sep 2025 09:12:51 +0200 Subject: [PATCH 2/3] Update AY8913 peripheral 20 docs --- docs/user_peripherals/20_AY8913.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/user_peripherals/20_AY8913.md b/docs/user_peripherals/20_AY8913.md index 8a71471..3db02e0 100644 --- a/docs/user_peripherals/20_AY8913.md +++ b/docs/user_peripherals/20_AY8913.md @@ -63,6 +63,10 @@ All registers are **read only** in this peripheral and start in **unknown** unin Square waves are produced by counting down the 12-bit counters. Counter counts up from 0. Once the corresponsding register value is reached, counter is reset and the output bit of the channel is flipped producing square waves. +The audio chip is internally clocked at 2 MHz which was the most common timing used during the 8-bit era for AY-3-891x and the following formula can be used to calculate the tone period: + + 2 MHz / 16 * note frequency + ### Noise generator Noise is produced with 17-bit [Linear-feedback Shift Register (LFSR)](https://en.wikipedia.org/wiki/Linear-feedback_shift_register) that flips the output bit pseudo randomly. @@ -73,7 +77,7 @@ The shift rate of the LFSR register is controller by the 5-bit counter. The envelope shape is controlled with 4-bit register, but can take only 10 distinct patterns. The speed of the envelope is controlled with 16-bit counter. Only a single envelope is produced that can be shared by any combination of the channels. ### Volume -Each of the three AY-3-891x channels have dedicated DAC that converts 16 levels of volume to analog output. Volume levels are 3 dB apart in AY-3-891x. +Each of the three AY-3-891x channels have dedicated DAC that converts 16 levels of volume to a logarithmic scale roughly 3 dB apart. ## IO pins From 8b0a770863072d9b349a4bc30d3d6d10facb7506 Mon Sep 17 00:00:00 2001 From: rej Date: Sat, 13 Sep 2025 15:35:17 +0200 Subject: [PATCH 3/3] Update VGA peripheral 12 docs --- docs/user_peripherals/12_vga.md | 80 +++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/docs/user_peripherals/12_vga.md b/docs/user_peripherals/12_vga.md index 9d959da..21257b3 100644 --- a/docs/user_peripherals/12_vga.md +++ b/docs/user_peripherals/12_vga.md @@ -11,7 +11,7 @@ You can also include images in this folder and reference them in the markdown. E 512 kb in size, and the combined size of all images must be less than 1 MB. --> -# VGA adapter for TinyQV +# 4 color flexible resolution VGA adapter for TinyQV Author: ReJ aka Renaldas Zioma @@ -19,7 +19,57 @@ Peripheral index: 12 ## What it does -TODO: Explain what your peripheral does and how it works +Flexible VGA framebuffer that allows multiple resolutions, up to 4 colors per scanline, 64 unique colors per frame and provides 1024x768 60Hz video signal (64 MHz pixel clock) suitable for a [TinyVGA PMOD](https://github.com/mole99/tiny-vga). + +By default it is configured to display **20 x 16 pixels** choosing colors from a 2 entrees palette. Each pixel is 1 bit where 0 selects background and 1 foreground color. In this configuration CPU is completely free to attend to other tasks. + +### Racing the Beam + +This peripheral is inspired by the 8-bit era designs when Video RAM (VRAM) was prohibitively expensive and there was not enough memory worth of the whole screen resolution - frankly the situation is similar with Tiny Tapeout and TinyQV peripherals where the amount of memory bits is very limited. + +Instead of large framebuffers, **Racing the Beam** technique was utilised to synchronize CPU with video signal and allow CPU to modify pixels in VRAM immediately after they have been displayed, forming the image of high resolution line by line. + +**Racing the Beam** means that CPU has to run in tandem with video signal: +- **interrupts** can be used for a coarse wait - for the start of the frame or scanline, +- **blocking reads** for precise syncronisation - for scanline or even in the middle of the scanline. + +Racing the Beam requires high CPU utilisation to support high screen resolutions. In the case of game, CPU could be processing game-pad inputs and executing gameplay logic only during the vertical blanking. The vertical blanking happens between scanlines 768 and 804 - roughly just 5% of the whole frame. + +Of course sacrifice up to 95% of CPU time is significant, but it might be worth for games or graphical demos. With this peripheral, it is up to you to decide! + +### Technical capabilities + +A very wide range of possible resolutions: +- from 16 x 10 4-color to 1024 x 768 2-color modes, +- vertical and horizontal counters define the size of the pixel, +- visible portion of the horizontal line can be set to 960 or 1024 clock cycles. + +The resolution of the screen, as well as 2 or 4 color mode can be changed at any point of the frame providing extra flexibility. + +Video RAM and color palette: +- **320 bit** of Video RAM worth of 320 or 160 pixels depending on the color mode, +- configurable stride in bits for each new row of visible pixels, +- up to 4 color palette, can be modified at any point of the frame. + +**Coarse** and **precise** syncronisation primitives: +- interrupts, +- cycle accurate blocking of the CPU, +- register to read out the current scanline number of the video signal. + +### Syncronisation primitives + +Syncronisation between CPU and video signal can be used either to update + +User interrupts can be triggered by: +- end of the frame, +- end of the visible portion of the scanline, +- end of the row of pixels + +CPU can be blocked with cycle level precision until: +- end of the visible portion of the scanline and start of the horizontal blanking is reached - `WAIT_HBLANK` +- the first pixel of the Video RAM was visualized and can be safely be modified by CPU again - `WAIT_PIXEL0` + +Read-only register to access the current scanline number - `SCANLINE`. ## Register map @@ -45,8 +95,30 @@ TODO: Explain what your peripheral does and how it works ## How to test -TODO: Explain how to use your project +### Default 20 x 16 pixels + +By default VGA peripheral is configured to display screen resolution of 20 x 16 pixels. +Write to `PIXELS` register to change the pixels. Each pixel is 1 bit and CPU is free to attend to other tasks. + +### 4-color 160 x 192 + +By default VGA peripheral will count 1024 cycles per visible line, however 1024 is not divisible by intended resolution of 160 pixels. You can shorten the screen width to 960 clocks instead since 960 are nicely divisible by 320. This is achieved by setting the **5th bit** of `MODE` register. + +4 colors mode is enabled by setting the **6th bit** of `MODE` register. + +The whole 160 pixel row nicely fits into the 320-bit VRAM and every new row of pixels will start from the very beginning of VRAM, therefore `VRAM_STRIDE` will be 0 (-1 will have the same effect reseting VRAM address to 0 at every row). + +Finally, calculated pixel horizontal and vertical counters dividing 960x768 the visible VGA resolution by the inteded frame resolution 160x192 and subtract 1. Write counter values in `PIXEL_SIZE` register. + + register[MODE] = 0b0011_0000 + register[VRAM_STRIDE] = 0 + register[PIXEL_SIZE] = (960 // 320 - 1) | ((768 // 192 - 1) << 16) + +To **Race the Beam** block CPU until the next horizontal blank reading from `WAIT_HBLANK` registe, then write into the `PIXELS` as fast you can! + + y = register[WAIT_HBLANK] + register[PIXELS] = ... ## External hardware -Tiny VGA Pmod +[TinyVGA PMOD](https://github.com/mole99/tiny-vga)