Skip to content

Commit

Permalink
Use only bold and italic for pseudo heading to be consistent in the s…
Browse files Browse the repository at this point in the history
…eparate and combined datasheet.

Made doc slightly shorter and to the point.
  • Loading branch information
rejunity committed Nov 9, 2023
1 parent aed8c49 commit 690eaec
Showing 1 changed file with 83 additions and 107 deletions.
190 changes: 83 additions & 107 deletions info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,40 +32,28 @@ documentation:
how_it_works: |
This Verilog implementation is a replica of the classical **[SN76489](https://en.wikipedia.org/wiki/Texas_Instruments_SN76489)** programmable sound generator.
With roughly a 1400 logic gates this design fits on a **single tile** of the TinyTapeout.
### Modern replica of a classic
The main goals of this project are:
**The main goals of this project**
1. closely replicate the behavior and eventually the complete **design of the original** SN76489
2. provide a readable and well documented code for educational and hardware **preservation** purposes
3. leverage the **modern fabrication** process
A significant effort was put into a thorough **test suite** for regression testing and validation against the original chip behavior.
### Module parametrization
The module is parameterized and can match variants from the SN76489 family. The following parametrization options are provided:
- noise tapped bits
- tone counter and noise LFSR shift register size
- variable clock divider
### The future work
**The future work**
The next step is to incorporate analog elements into the design to match the original SN76489 - DAC for each channel and an analog OpAmp for channel summation.
# Chip technical capabilities
**Chip technical capabilities**
- **3 square wave** tone generators
- **1 noise** generator
- 2 types of noise: *white* and *periodic*
- Capable to produce a range of waves typically from **122 Hz** to **125 kHz**, defined by **10-bit** registers.
- **16** different volume levels
#### Registers
The behavior of the SN76489 is defined with 8 "registers" - 4 x 4 bit volume registers, 3 x 10 bit tone registers and 1 x 3 bit noise configuration register.
___Registers___ The behavior of the SN76489 is defined with 8 "registers" - 4 x 4 bit volume registers, 3 x 10 bit tone registers and 1 x 3 bit noise configuration register.
| Channel | Volume registers | Tone & noise registers |
|---------|------------------------|--------------------------|
Expand All @@ -74,24 +62,21 @@ documentation:
| 2 | Channel #2 attenuation | Tone #2 frequency |
| 3 | Channel #3 attenuation | Noise type and frequency |
#### Square wave tone generators
Square waves are produced by counting down the 10-bit counters. Each time the counter reaches the 0 it is reloaded with the corresponding value from the configuration register and
___Square wave tone generators___ Square waves are produced by counting down the 10-bit counters. Each time the counter reaches the 0 it is reloaded with the corresponding value from the configuration register and
the output bit of the channel is flipped producing square waves.
#### Noise generator
Noise is produced with 15-bit [Linear-feedback Shift Register (LFSR)](https://en.wikipedia.org/wiki/Linear-feedback_shift_register) that flips the output bit pseudo randomly.
___Noise generator___ Noise is produced with 15-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 either by one of the 3 hardcoded power-of-two dividers or output from the channel #2 tone generator is used.
#### Attenuation
Each of the four SN76489 channels have dedicated attenuation modules. The SN76489 has 16 steps of attenuation, each step is 2 dB and maximum possible attenuation is 28 dB.
___Attenuation___ Each of the four SN76489 channels have dedicated attenuation modules. The SN76489 has 16 steps of attenuation, each step is 2 dB and maximum possible attenuation is 28 dB.
Note that the attenuation definition is the opposite of volume / loudness. Attenuation of 0 means maximum volume.
Finally, all the 4 attenuated signals are summed up and are sent to the output pin of the chip.
# Historical use of the SN76489
**Historical use of the SN76489**
The SN76489 family of programmable sound generators was introduced by Texas Instruments in 1980. Variants of the SN76489 were used in a number of home computers, game consoles and arcade boards:
Expand All @@ -101,7 +86,7 @@ documentation:
The SN76489 chip family competed with the similar [General Instrument AY-3-8910](https://en.wikipedia.org/wiki/General_Instrument_AY-3-8910).
### The original pinout of the SN76489AN
**The original pinout of the SN76489AN**
```
,--._.--.
Expand All @@ -118,48 +103,37 @@ documentation:
```
# Difference from the original hardware
** Difference from the original hardware **
This Verilog implementation is a completely digital and synchronous design that differs from the original SN76489 design which incorporated analog parts.
#### Audio signal output
While the original chip had integrated OpAmp to sum generated channels in analog fashion, this implementation does digital signal summation and digital output.
___Audio signal output___ While the original chip had integrated OpAmp to sum generated channels in analog fashion, this implementation does digital signal summation and digital output.
The module provides two alternative outputs for the generated audio signal:
1. digital 8-bit audio output suitable for external Digital to Analog Converter (DAC)
2. pseudo analog output with Pulse Width Modulation (PWM)
#### Separate 4 channel output
Outputs of all 4 channels are exposed along with the master output. This allows to validate and mix signals externally.
___Separate 4 channel output___ Outputs of all 4 channels are exposed along with the master output. This allows to validate and mix signals externally.
In contrast the original chip was limited to a single audio output pin due to the PDIP-16 package.
#### No DC offset
This implementation produces unsigned output waveforms without DC offset.
___No DC offset___ This implementation produces unsigned output waveforms without DC offset.
#### **/CE** and **READY** pins are omitted for simplicity
**/CE**, chip enable control pin is omitted in this design. The behavior is the same as if **/CE** is tied *low* and the chip is considered always enabled.
___**/CE** and **READY** pins are omitted for simplicity___ **/CE**, chip enable control pin is omitted in this design. The behavior is the same as if **/CE** is tied *low* and the chip is considered always enabled.
Unlike the original SN76489 which took 32 cycles to update registers, this implementation handles register writes in a single cycle and chip behaves as always **READY**.
#### Synchronous reset and single phase clock
The original design employed 2 phases of the clock for the operation of the registers. The original chip had no reset pin and would wake up to a random state.
___Synchronous reset and single phase clock___ The original design employed 2 phases of the clock for the operation of the registers. The original chip had no reset pin and would wake up to a random state.
To make it easier to synthesize and test on FPGAs this implementation uses single clock phase and synchronous reset for registers.
#### Externally configurable clock divider
A configurable clock divider was introduced in this implementation. Clock divider can be controlled through **SEL0** and **SEL1** control pins and allows to select between 3 chip variants:
___A configurable clock divider___ was introduced in this implementation.
1. the original SN76489 with the master clock internally divided by 16. This classical chip was intended for PAL and NTSC frequencies. However in [BBC Micro](https://en.wikipedia.org/wiki/BBC_Micro) 4 MHz clock was employed.
2. SN94624/SN76494 variants without internal clock divider. These chips were intended for use with 250 to 500 KHz clocks.
3. high frequency clock configuration for TinyTapeout, suitable for a range between 25 MHz and 50 Mhz. In this configuration the master clock is internally divided by 128.
### The reverse engineered SN76489
** The reverse engineered SN76489 **
This implementation is based on the results from these reverse engineering efforts:
Expand All @@ -169,56 +143,34 @@ documentation:
# Instructions on how someone could test your project, include things like what buttons do what and how to set the clock if needed
how_to_test: |
### Test-suite
First of all, run the test suite:
```
$ cd src
$ make
```
There are a number of useful functions in [test.py](https://github.com/rejunity/tt05-psg-sn76489/blob/main/src/test.py) that simplify communication with the sound generator.
The following example sets up 440Hz (A4) note at the full volume on the 1st channel and white noise at the half volume:
```
await reset(dut)
# Set `Channel 1` to maximum volume
await set_volume(dut, channel='1', 15)
# Play 440 Hz note on `Channel 1`
await set_tone(dut, channel='1', frequency=440)
# Set `Channel 4` (noise channel) to half volume
await set_volume(dut, channel='4', 8)
# Use on the 3 hardcoded divider values for noise generator
# produces ~1 kHz white noise, if chip is clocked at 4 MHz
await set_noise(dut, white=True, divider=512)
```
### Record music from the Verilog simulated design
Simulated Verilog design can be fed with the stream of register values captured on a 8-bit computer in [Video Game Music (VGM)](https://vgmrips.net/wiki/VGM_Specification) format and
output converted to .wav file. This process is recommended for both testing and enjoying 8-bit era music!
```
$ make MODULE=record VGM=../music/CrazeeRider-title.bbc50hz.vgm
$ cd ../output
```
** Connect chip to the speaker **
For a reference you can find music recorded from the chip simulation:
- [https://www.youtube.com/watch?v=ghBGasckpSY](Crazee Rider BBC Micro game)
- [https://www.youtube.com/watch?v=HXLAdA02I-w](MISSION76496 tune for Sega Master System)
There are several ways to connect this chip to a microcontroller and speaker.
### Connect chip to the speaker
There are several ways to connect this chip to the microcontroller and speaker.
One option is to connect off the shelf data parallel Digital to Analog Converter (DAC)
___8-bit parallel output via DAC___ One option is to connect off the shelf data parallel Digital to Analog Converter (DAC)
for example [Digilent R2R Pmod](https://digilent.com/reference/pmod/pmodr2r/start) to the output pins and
route the resulting analog audio to piezo speaker or amplifier.
Another option is to use the Pulse Width Modulated (PWM) AUDIO OUT pin with OpAmp+capacitor based integrator or capacitor based low-pass filter and a speaker:
uController SN76489
,---------. ,---._.---.
| | 4 Mhz ->|CLK SEL0|<-- 0
| GPIOx|----------->|D0 SEL1|<-- 0
| GPIOx|----------->|D1 | ,----------.
| GPIOx|----------->|D2 OUT0|-------->|LSB |
| GPIOx|----------->|D3 OUT1|-------->| |
| GPIOx|----------->|D4 OUT2|-------->| pDAC | Headphones
| GPIOx|----------->|D5 OUT3|-------->| or | or
| GPIOx|----------->|D6 OUT4|-------->| RESISTOR | Buzzer
| GPIOx|----------->|D7 OUT5|-------->| ladder | /|
| GPIOx|----------->|/WE OUT6|-------->| | .--/ |
`---------' | OUT7|-------->|MSB |-----| |
`---------' `----------' `--` |
| `|
|
GND ---
___AUDIO OUT through RC filter___ Another option is to use the Pulse Width Modulated (PWM) AUDIO OUT pin that combines 4 channels with the Resistor-Capacitor based low-pass filter or better the Operation Amplifier (Op-amp) & Capacitor based integrator:
```
uController SN76489
Expand All @@ -230,7 +182,7 @@ documentation:
| GPIOx|----------->|D3 | C1
| GPIOx|----------->|D4 | ,----||----.
| GPIOx|----------->|D5 | | |
| GPIOx|----------->|D6 | | OpAmp | Speaker
| GPIOx|----------->|D6 | | Op-amp | Speaker
| GPIOx|----------->|D7 AUDIO| | |X | /|
| GPIOx|----------->|/WE OUT |-----.---|-X | C2 .--/ |
`---------' `---------' | }---.---||---| |
Expand All @@ -240,7 +192,29 @@ documentation:
GND --- GND ---
```
### Summary of commands to communicate with the chip
___Separate channels through the Op-amp___ The third option is to externally combine 4 channels with the Operational Amplifier and low-pass filter:
```
uController SN76489
,---------. ,---._.---.
| | 4 Mhz ->|CLK SEL0|<-- 0
| GPIOx|----------->|D0 SEL1|<-- 0
| GPIOx|----------->|D1 |
| GPIOx|----------->|D2 |
| GPIOx|----------->|D3 | C1
| GPIOx|----------->|D4 | ,----||----.
| GPIOx|----------->|D5 chan0|---. | |
| GPIOx|----------->|D6 chan1|---+ | OpAmp | Speaker
| GPIOx|----------->|D7 chan2|---+ | |X | /|
| GPIOx|----------->|/WE chan3|---+--.---|-X | C2 .--/ |
`---------' `---------' | }---.---||---| |
,--|+/ `--` |
| |/ | `|
| |
GND --- GND ---
```
** Summary of commands to communicate with the chip **
Once playback schematics of the SN76489 are established, the controller program has to send data to the chip. SN76489 is programmed by updating its internal registers via data bus.
Expand All @@ -261,26 +235,20 @@ documentation:
| 1 | 0 | Clock divided by 2048 |
| 1 | 1 | Use channel #2 tone frequency |
### Note frequency
** Note frequency **
Use the following formula to calculate the 10-bit value for a particular frequency:
```
n = clock_frequency / (32 * note_frequency)
```
$$ n = clock_frequency / (32 * note_frequency) $$
For example 10-bit value that plays 440 Hz note on a chip clocked at 4 MHz would be:
```
n = 4000000 / (32 * 400)
n = 284 = h11C
```
### Data bus
$$ n = 4000000 / (32 * 400) = 284 $$
#### An example sequence of writes to the data bus.
** An example sequence of data commands to produce sound **
Remember to hold **/WE** LOW while writing to the data bus.
Hold **/WE** low once data bus pins are set to the desired values.
Pull **/WE** high again before setting different value to data bus.
```
10001100 - Set channel #0 tone 4 low bits to hC
Expand All @@ -291,7 +259,7 @@ documentation:
11111000 - ---//--- volume to 50% (attenuation = 8)
```
### Timing diagram
** Timing diagram **
```
CLK ____ ____ ____ ____ ____ ____
__/ `____/ `____/ `____/ `____/ `____/ `___ ...
Expand All @@ -313,7 +281,10 @@ documentation:
there was a write to noise register
```
### Externally configurable clock divider
** Configurable clock divider **
Clock divider can be controlled through **SEL0** and **SEL1** control pins and allows to select between 3 chip variants.
| SEL1 | SEL0 | Description | Clock frequency|
|------|------|------------------------------------|----------------|
Expand All @@ -322,6 +293,11 @@ documentation:
| 0 | 1 | SN76494 mode, no clock divider | 250 .. 500 kHZ |
| 1 | 0 | New mode for TT05, clock div. 128 | 25 .. 50 MHz |
** Example music recorded from the chip simulation **
- [https://www.youtube.com/watch?v=ghBGasckpSY](Crazee Rider BBC Micro game)
- [https://www.youtube.com/watch?v=HXLAdA02I-w](MISSION76496 tune for Sega Master System)
# A description of what the inputs do
inputs:
Expand Down

0 comments on commit 690eaec

Please sign in to comment.