710 Orion Iron Ion [TT10 demo competition]

710 : Orion Iron Ion [TT10 demo competition]

Design render

Intro

Curly / Medieval presents

my contribution to the Tiny Tapeout 10 demo competition (which unfortunately got cancelled due the Efabless shutdown). Code, graphics, and music by Curly (Toivo Henningsson) of Medieval.

The demo was originally written for the Sky130 process (see the sky130 branch), but was updated to the IHP process before submission.

The demo can be seen at https://youtu.be/VCQJCVPyYjU (captured from a Verilator simulation).

How it works

The demo code contains a few different parts, mainly:

  • Logo
  • Star field
  • Floating point unit; used for the twister and spiralling balls
  • Synthesizer and sequencer

The video output is produced in VGA mode 640x480 @60 Hz. The logic is clocked at 50.4 MHz, giving two clock cycles per pixel.

Logo

Just like in https://github.com/toivoh/tt08-demo, the logo is made of big pixels (32x32 this time vs 16x16 before), where each big pixel is split along the diagonal into two triangles. The title is chosen so that the logo should hopefully compress well (and also alludes to the space theme and the echo feeling in the music). The dimensions of the characters are chosen so that patterns should repeat at a scale of 4 pixels, to try to make them more visible to the tool's logic minimizer.

Star field

The star field keeps track of the current x and y coordinates with two extra subpixel bits of precision, increasing x or y by up to 4 units in each step. This is to allow the antialiasing effect where stars can move a fraction of a pixel per frame; since the output is RGB222, 2 subpixel position bits are enough. The size of the step to take to the next x or y value is taken from a coarse table that is made so that the resulting x and y curve should be similar to turning in space. The table entries have higher precision, so that they can cause a dithering between e g increments of 2 and 3 or 3 and 4.

The distribution of stars is computed using a pseudorandom function that depends on the current x and y value. This is inspired by the pseudorandom function used in the synth (see below). The algorithm can be described as

{r0, dr} = bitshuffle({jx, jy}, pattern1)
r = r0
for i=1:2
	r = bitshuffle(r, pattern2) + dr
	r = bitshuffle(r, pattern3)

intensity = r[5:4]
if intensity == 0: intensity = 1
if r[3:0] != 0: intensity = 0

where ix, iy are input bits for the current position where we should determine if there is a star, and its brightness. bitshuffle(x, pattern) permutes the bits of x using the fixed pattern. This can be done with only wires, so should be cheap. The combination of addition and bit shuffling means that the effects of input bits propagate in a quite unpredictable way to affect the output bits, creating a pseudorandom behavior. To find good star patterns, I simulated random bit shuffles with a script until I found a pattern that I liked.

The input to the random algorithm is not the full pixel positions ix and iy, but jx = ix>>2 and jy = iy>>1. Only every fourth x pixel position and every second y pixel position can hold a star, with black in between. This allows the random algorithm time to converge before the star's intensity is needed.

A typical way to do the antialiasing of the stars would be to calculate numbers px and py that described how well the star aligns with the current x and y position, and use px*py to modulate the intensity. To save on logic, min(px, py) is used instead. A small lookup table is then used to calculate the 2 bit pixel value from min(px, py) and the star's intensity.

Floating point unit - twister and spiralling balls effects

The demo contains a small floating point unit for approximate floating point calculations, with 5 exponent bits and 11 mantissa bits. The FPU implements addition and subtraction in a similar way to most FPUs. It also supports approximate operations for multiplication and square root (approximate division could be supported as well, but wasn't needed). The approximate operations assume that the concatenation of exponent and mantissa bits are a logarithmic representation of the floating point number: multiply adds {exponent, mantissa}, while square root shifts it right by one. The result is quite inaccurate, but good enough for the computations needed, and contributes some interesting jaggedness to the twister. These cheap approximations of multiply and square root were the motivation to use an FPU in the first place.

Conversion from fixed point to floating point is done by creating a floating point number with a fixed exponent and placing the fixed point number (with its sign bit inverted) in the mantissa, which produces a floating point number representation of fixed_point_number+bias. The bias is then subtracted. To convert in the other direction, the bias is added to a floating point number, and the fixed point result is read out from the mantissa.

The FPU code uses the approximation cos(0.5*pi*t) = 1 - t^2, abs(t) <= 1. There didn't seem to be a point in making a more accurate representation given the inaccuracy of the multiplication.

The ALU has a single accumulator register and 5 general purpose registers. One of the inputs to the ALU is always the accumulator, while the other can come from a register, constant, or time varying fixed point value from the outside. The result is always written to the accumulator, and the value in the accumulator can then be written to one of the other registers.

Twister and spiral of balls effects

These are implemented by running a short FPU program during horizontal blanking before each scan line starts (different programs for different effects). The program computes up to five x positions for the scan line, which are used to draw horizontal spans of light and dark blue. The x positions share space with the mantissas in the FPU registers. The programs are written in such a way that they use fewer and fewer FPU registers as they are being overwritten with x positions.

Breaking down FPU instructions into cycles

To save area, each FPU instruction is broken into up to 3 single-cycle micro-operations:

  • Add/sub:
    • Determine which argument has the largest magnitude
    • Add/Subtract
    • Normalize, calculating the correct exponent and shifting the mantissa to the right position
  • Multiply:
    • Calculate carry out from mantissa sum
    • Add {exponent, mantissa}
  • Single cycle instructions:
    • Load
    • Square root

The FPU code is stored as instructions rather than micro-operations, which should save some area. One instruction is executed every 4 cycles, which lets the program code be indexed by a running timer.

The logic that represents the program ROM for the FPU has quite high latency. A multicycle timing constraint is used to allow data paths that go through the program ROM to take two cycles. This means that no micro-operation is executed until the second cycle of running each instruction. (The multicycle constraint turned out not to be needed for the IHP version, and was removed.)

Synthesizer

The synthesizer produces output samples at 63 kHz, 10 bit resolution. This gives it 800 cycles (half a scan line) per sample, and the usable ouput range of PWM values is 0 - 800. One voice sample is calculated in 64 cycles, which gives time to calculate 12 voices at the same time, plus a little time to update for the next sample. On average, the voices need to have a peak amplitude <= 64 steps to fit into the output range; one step per cycle.

The voices are used as follows:

  • 4x2 melody/harmony voices: 4 channels with 2 voices per channel with detuning to get a fatter sound
    • The frequency is slightly higher for one of the voices in each pair than the other
  • Prenoise: the pedal tone with rhythmically changing timbre that runs throughout most of the demo
  • Bass drum
  • Hihat
  • Visualization voice - not heard, used to produce the visible waveforms on screen
    • Can calculate two waveforms per scan line
Aliasing considerations

The waveforms are designed to keep aliasing artifacts relatively low:

  • The melody/harmony waveforms use piecewise linear sections without a too steep slope, and avoid slopes of less than one unit per sample, which keeps aliasing down.
  • The bass drum has a similar approach, using a clipped triangle wave that gradually sinks in frequency.
  • The prenoise waveform is kept at a power of 2 frequency, since it would be hard to antialias. The music has been written around this limitation, with the prenoise as a pedal tone/ostinato.
    • Initially, the pedal tone is the tonic note.
    • After the music modulates down by a fifth towards the end, the pedal tone is now the fifth instead.
  • The hihat is pure noise and doesn't need any antialiasing considerations.

To gradually reduce the volume of each voice, it is clamped to a decreasing maximum amplitude. This simple method changes the waveform as the volume reduces, but keeps the slopes in their original range. If the volume had been reduced by multiplication, increasing aliasing artifacts would results as the effective range gets reduced.

ALU

The synthesizer is based around a small ALU, with a small set of registers

  • 11 bit accumulator
  • 10 bit output accumulator
  • 10 bit output register
  • 23 bit oscillator divided into low and high 11 bit parts plus top bit
  • two flag bits (predicates)

The oscillator is used to calculate the phase of the waveforms, keep track of time in the demo, index the notes for the music and to know which frame to display.

Calculating voice phases from the shared oscillator

There are no registers to keep track of the phases of different synth voices. Instead, for each sample of a voice that needs to be computed, the first 30 cycles are used to compute phase = (freq * osc) >> n to produce an 11 bit phase in the accumulator. The bits above 11 are truncateed, since the waveform repeats after one phase. freq varies between 256 and 511 to choose a note, while n selects the octave.

The product phase = (freq * osc) >> n is calculated using shifts and adds (at most one of each per cycle), discarding low order bits when they are not needed anymore, and high order bits that will not be needed. To illustrate the method, say that we want to calculate bits 10:3 of the product of an 8 bit and an 11 bit number. The calculation can be visualized as follows:

             ********
            ********
           ********
          ********
         ?*******|
        ??****** |
       ???*****  |
      ????****   |
     ?????***    |
    ??????**     |
 + ???????*      |
---------------------
= ????????********???

We have 11 product terms to add up, each with 8 bits.

  • We proceed from the smallest term, adding up terms.
  • In the first phase, the bottom bit in the current sum is not needed in the final output, so it can be dropped since no later term will change it (they are all shifted further to the left).
  • In the second phase, we are out of bottom bits to ignore, and we can instead start to ignore top bits in the terms, since they are above the range of bits needed in the result.
  • By changing the number of steps in the first phase, we can change the shift amount n.

This way, we can use the same number of bits to store each intermediate result as is needed to store the final result. The implementation proceeds by shifting the intermediate result right by one for each step, switching to rotate right when coming to the second phase (to preserve the bits that are rotated out). When all relevant terms have been added, the result will have been rotated back to the correct position.

Evaluating waveforms using a single accumulator as intermediate storage

The synth ALU has only a single intermediate register to work with, the accumulator (to save area). To evaluate a piecewise linear function (which the melodic/harmonic waveforms are made of), it first evaluates one or several conditions on the current accumulator value to know which piece of the piecewise linear function that it should evaluate, storing the results in the predicates. Then, it can use the predicate values to choose how to transform the accumulator.

Melody/harmony voices

There are two waveforms used for the melody/harmony voices: saw like and pulse like. An ideal sawtooth wave includes a sudden jump every period, and an ideal pulse wave contains two. To simulate a gradually closing lowpass filter, these jumps have been changed to ramps. The slope of the ramps is gradually decreased as a note ages.

The pulse like waveform is also uses pulse width modulation by a triangle wave, which is added to the intermediate phase after it itself has been made into a triangle wave as a step in the waveform computation.

Bass drum

The bass drum approximates a clamped triangle wave with exponentially decreasing frequency. This was a bit challenging to implement, since there is no register to store the bass drum's phase between samples, instead it has to be recalculated at each sample from the linearly increasing oscillator.

The bass drum uses a variation on the multiplication algorithm, takeing the lower bits of the oscillator and calculating an approximate square. Let x be the relevant oscillator bits in fixed point. As x goes from 0 to one, the function

y = (2-x)^2 mod 1

wraps around 3 times, with the slope at the end being half of the slope at the beginning. Several such quadratic sections are shifted into decreasing octaves to give an approximation of an exponentially decaying frequency. The square approximation is calculated using a variation of the multiplication algorithm described above. It uses only 8 slopes per octave, which seems to be barely enough to give the impression of a continuously descending pitch, but allows the algorithm to use the top 11 bits of the oscillator as one of its inputs.

The bass drum phase is used to evaluate a triangle wave, which is clamped to gradually reduce its volume.

Hihat

The hihat is created by noise clamped to a decreasing amplitude. This kind of noise is traditionally created with a Linear Feedback Shift Register (LFSR), but that would have required space for registers to hold the LFSR state. Instead, a new noise value is calculated for each sample based on the oscillator, using the algorithm

acc = osc_low
for i=0:3
	acc = bitshuffle(acc, pattern) + osc_high
	acc = acc + (acc >> 1)

The pattern used for shuffling is fixed, all it needs is an 11-bit wide multiplexer. After four iterations, the result sounds like noise.

Prenoise pedal tone

The prenoise waveform used as a pedal tone is computed using a simplification of the noise algorithm above, with only one iteration:

acc = <selected bits from osc>
acc = bitshuffle(acc, pattern)
acc = acc + rotate_right(acc, 1)  # could use acc *= 3 instead

The permutation used in the bitshuffle step is the same as in the noise case above, and has been chosen for the sonic results it produces in the prenoise case. The result is a waveform with a power of 2 period that changes timbre in a rhythmic manner.

Visualization voice

The visualization voice can evaluate the waveform from any of the other voices, using the current scanline's y position instead of the oscillator, to keep the waveform steady from frame to frame. Two waveforms can be evaluated per scan line, one to be shown on the left side of the screen and one on the right side. The synth is synchronized with the display output so that a new visualization waveform sample is computed in the middle of each scan line and one in hblank. There are 3 registers to store the evaluated waveforms, to keep track of two waveforms and have access to the value from the previous scanline when a waveform is displayed.

Sequencer

The notes to play are taken from logic that represents a note ROM, and it has quite high latency. Out of the 64 cycles used to compute each voice sample, the first cycle is used to wait for the output from the note ROM to stabilize, and the synthesizer doesn't do anything with the note data until the second cycle. This is accomplished with a multicycle timing constraint. (The multicycle constraint turned out not to be needed for the IHP version, and was removed.)

The note ROM contains data for 4 channels. For each channel and time position pos, it outputs an enable flag, a note value (note and octave), and an age value t0. The actual age is computed as t = t0 + pos (with wraparound). This allows t0 to be piecewise constant in the note ROM. The age t is filled out with low order bits from the oscillator, and used to modulate the waveform and volume of notes as they age. Weaker notes can be achieved by starting them at a higher age.

How to test

Plug in a TinyVGA compatible Pmod on the TT08 demo board's out Pmod. Plug in a Pmod compatible with Mike's audio Pmod on the TT08 demo board's bidir Pmod. Set all inputs to zero to get the default behavior. The demo starts directly after reset.

External hardware

This project needs

IO

#InputOutputBidirectional
0R1
1G1
2B1
3vsync
4R0
5G0
6advance[0]B0
7advance[1]hsyncaudio_out

Chip location

Controller Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux tt_um_chip_rom (Chip ROM) tt_um_factory_test (Tiny Tapeout Factory Test) tt_um_tommythorn_maxbw (Asynchronous Multiplier) tt_um_mattvenn_rgb_mixer (RGB Mixer demo5) tt_um_find_the_damn_issue (Find The Damn Issue) tt_um_brandonramos_VGA_Pong_with_NES_Controllers (VGA Pong with NES Controllers) tt_um_kb2ghz_xalu (4-bit minicomputer ALU) tt_um_a1k0n_demo (Demo by a1k0n) tt_um_zec_square1 ("SQUARE-1": VGA/audio demo) tt_um_jmack2201 (Sprite Bouncer with Looping Background Options) tt_um_ran_DanielZhu (Dice) tt_um_gfg_development_tinymandelbrot (TinyMandelbrot) tt_um_toivoh_demo_tt08 (Sequential Shadows [TT08 demo competition]) tt_um_quarren42_demoscene_top (asic design is my passion) tt_um_crispy_vga (Crispy VGA) tt_um_MichaelBell_canon (TT08 Pachelbel's Canon demo) tt_um_shuangyu_top (Calculator) tt_um_wokwi_407306064811090945 (DDR throughput and flop aperature test) tt_um_favoritohjs_scroller (VGA Scroller) tt_um_tt08_wirecube (Wirecube) tt_um_vga_glyph_mode (Glyph Mode) tt_um_a1k0n_vgadonut (VGA donut) tt_um_roy1707018 (RO) tt_um_sign_addsub (CMOS design of 4-bit Signed Adder Subtractor) tt_um_patater_demokit (Patater Demo Kit Waggling Rainbow on a Chip) tt_um_simon_cipher (simon_cipher) tt_um_thexeno_rgbw_controller (RGBW Color Processor) tt_um_demosiine_sda (DemoSiine) tt_um_bytex64_munch (Munch) tt_um_cfib_demo (cfib Demoscene Entry) tt_um_Richard28277 (4-bit ALU) tt_um_betz_morse_keyer (Morse Code Keyer) tt_um_nvious_graphics (nVious Graphics) tt_um_ezchips_calc (8-Bit Calculator) tt_um_hack_cpu (HACK CPU) tt_um_ring_divider (Divided Ring Oscillator) tt_um_ephrenm_tsal (TSAL_TT) tt_um_kapilan_alarm (Alarm Clock) tt_um_stochastic_addmultiply_CL123abc (Stochastic Multiplier, Adder and Self-Multiplier) tt_um_dlfloatmac (DL float MAC) tt_um_faramire_rotary_ring_wrapper (Rotary Encoder WS2812B Control) tt_um_i2c_peripheral_stevej (i2c peripherals: leading zero count and fnv-1a hash) tt_um_yuri_panchul_schoolriscv_cpu_with_fibonacci_program (schoolRISCV CPU with Fibonacci program) tt_um_yuri_panchul_adder_with_flow_control (Adder with Flow Control) tt_um_brailliance (Brailliance) tt_um_nyan (nyan) tt_um_MichaelBell_mandelbrot (VGA Mandelbrot) tt_um_fountaincoder_top_ad (pulse_add) tt_um_edwintorok (Rounding error) tt_um_mac (MAC) tt_um_dpmu (DPMU) tt_um_JAC_EE_segdecode (7 Segment Decode) tt_um_yuri_panchul_sea_battle_vga_game (Sea Battle) tt_um_benpayne_ps2_decoder (PS2 Decoder) tt_um_meriac_play_tune (Super Mario Tune on A Piezo Speaker) tt_um_comm_ic_bhavuk (Comm_IC) tt_um_daosvik_aesinvsbox (AES Inverse S-box) tt_um_cattuto_sr_latch (TT08 - experiments with latch-based shift registers) tt_um_silice (Warp) tt_um_jayjaywong12 (mulmul) tt_um_emmyxu_obstacle_detection (Obstacle Detection) tt_um_neural_navigators (Neural Net ASIC) tt_um_resfuzzy (resfuzzy) tt_um_cejmu (CEJMU Beers and Adders) tt_um_16_mic_beamformer_arghunter (16 Mic Beamformer) tt_um_pdm_pitch_filter_arghunter (PDM Pitch Filter) tt_um_pdm_correlator_arghunter (PDM Correlator) tt_um_ddc_arghunter (DDC) tt_um_i2s_to_pwm_arghunter (I2S to PWM ) tt_um_supermic_arghunter (Supermic ) tt_um_dmtd_arghunter (DMTD ) tt_um_htfab_bouncy_capsule (Bouncy Capsule) tt_um_samuelm_pwm_generator (PWM generator) tt_um_toivoh_demo_deluxe (Sequential Shadows Deluxe [TT08 demo competition]) tt_um_faramire_stopwatch (Simple Stopwatch) tt_um_johshoff_metaballs (Metaballs) tt_um_top (Flame demo) tt_um_NicklausThompson_SkyKing (SkyKing Demo) tt_um_Electom_cla_4bits (4-bit CLA) tt_um_vga_cbtest (Generate VGA output for Color Blindness Test) tt_um_zoom_zoom (Zoom Zoom) tt_um_dpmunit (DPM_Unit) tt_um_clock_divider_arghunter (Clock Divider ) tt_um_dlmiles_poc_fskmodem_hdlctrx (FSK Modem +HDLC +UART (PoC)) tt_um_emilian_muxpga (TinyFPGA resubmit for TT08) tt_um_pyamnihc_dummy_counter (Dummy Counter) tt_um_whynot (Why not?) tt_um_dlmiles_tt08_poc_uart (UART) tt_um_dendraws_donut (donut) tt_um_tmkong_rgb_mixer (RGB Mixer) tt_um_led_matrix_ayla_lin (32x8 LED Matrix Animation) tt_um_rebeccargb_tt09ball_screensaver (TT09Ball VGA Screensaver) tt_um_rebeccargb_vga_pride (VGA Pride) tt_um_levenshtein (Fuzzy Search Engine) tt_um_rebeccargb_colorbars (Color Bars) tt_um_jamesrosssharp_1bitam (1bit_am_sdr) tt_um_rebeccargb_hardware_utf8 (Hardware UTF Encoder/Decoder) tt_um_rebeccargb_styler (Styler) tt_um_rebeccargb_vga_timing_experiments (VGA Timing Experiments) tt_um_rebeccargb_universal_decoder (Universal Binary to Segment Decoder) tt_um_rebeccargb_intercal_alu (INTERCAL ALU) tt_um_toivoh_pio_ram_emu_example (pio-ram-emulator example: Julia fractal) tt_um_tobimckellar_top (Simple PWM Module) tt_um_JesusMinguillon_freqSweep (freqSweep) tt_um_led_cipher (LED Bitserial Cipher) tt_um_my_elevator (Elevator Design) tt_um_wokwi_413387065339458561 (APA102 to WS2812 Translator) tt_um_wokwi_413386991502909441 (SPI Logic Analyzer with Charlieplexed Display) tt_um_alf19185_ALU (4 bit ALU ) tt_um_rtfb_collatz (Collatz conjecture brute-forcer) tt_um_senolgulgonul (Senol Gulgonul tt09) tt_um_Esteban_Oman_Mendoza_maze_2024_top (Space Detective Maze Explorer) tt_um_sebastienparadis_hamming_top (Hamming Code (7,4)) tt_um_prefix8 (tiny-tapeout-8bit-GPTPrefixCircuit) tt_um_lif_tk (LIF on a Ring Topology) tt_um_asheldon44_dsm_decimation_filter (Delta-Sigma ADC Decimation Filter) tt_um_juarez_jimenez (an lfsr with synaptic neurons (excitatory or inhibitatory)) tt_um_lif_clarencechan28 (Perceptron) tt_um_uart_mvm (Matmul System) tt_um_algofoogle_tt09_ring_osc (Verilog ring oscillator) tt_um_pid_controller (PID Controller) tt_um_frequency_counter (Frequency Counter SSD1306 OLED) tt_um_delta_liafn (Delta RNN and Leaky Integrate-and-Fire Nueron Circuit) tt_um_devinatkin_basys3_uart (Basys 3 Over UART Link) tt_um_pwm_top (Generador PWM multiproposito con frecuencia y ciclo de trabajo modulable) tt_um_lfsr_stevej (Linear Feedback Shift Register) tt_um_jamesrosssharp_tiny1bitam (Tiny 1-bit AM Radio) tt_um_instrumented_ring_oscillator (instrumented_ring_oscillator) tt_um_lif1 (STDP Circuit) tt_um_alif (3 Neuron ALIF) tt_um_tiny_ternary_tapeout (T3 (Tiny Ternary Tapeout)) tt_um_snn_with_delays_paolaunisa (ChatGPT-generated Spiking Neural Network with Delays) tt_um_arandomdev_fir_engine_top (FIREngine) tt_um_carryskip_adder8 (8-bit carry-skip) tt_um_riscv_mini (RISC-V Mini) tt_um_CLA8 (8-bit Carry Look-Ahead Adder) tt_um_hybrid_adder (Hybrid_Adder_8bit) tt_um_uart_mvm_sys (Matmul System) tt_um_MichaelBell_hd_8b10b (8b10b decoder and multiplier) tt_um_program_counter_top_level (Test Design 1) tt_um_murmann_group (Decimation Filter for Incremental and Regular Delta-Sigma Modulators) tt_um_adder_accumulator_sathworld (adder-accumulator) tt_um_control_block (ECE 298A 8-Bit CPU Control Block) tt_um_LFSR_Encrypt (LFSR Encrypter) tt_um_cdc_test (SkyKing Demo) tt_um_two_lif_stdp (Two LIF Neurons with STDP Learning) tt_um_underserved (ITS-RISCV) tt_um_znah_vga_ca (znah_vga_ca) tt_um_mikegoelzer_7segmentbyte (7-Segment Byte Display) tt_um_idann (Forward Pass Network for Simple ANN) tt_um_carryskip_adder9 (carry skip adder) tt_um_mroblesh (Frequency Encoder and Decoder) tt_um_wokwi_411379488132926465 (Semana UCU Verilog) tt_um_rejunity_atari2600 (Atari 2600) tt_um_rejunity_z80 (Zilog Z80) tt_um_couchand_cora16 (CORA-16) tt_um_kashmaster_carryskip (8-bit-CARRY_SKIP) tt_um_tiny_ternary_tapeout_csa (T3 (Tiny Ternary Tapeout) CSA ) tt_um_array_secD7 (Tiny Tapeout Group 7 Lab D) tt_um_chip4lyfe (Leaky Integrate Fire Neuron) tt_um_ronikant_jeremykam_tinyregisters (Tiny Registers) tt_um_VanceWiberg_top (Team 17's 8 bit DAC) tt_um_claudiotalarico_counter (4-bit up/down binary counter) tt_um_gmejiamtz (Configurable Logic Block) tt_um_I2C (I2C and SPI) tt_um_perceptron_mtchun (Perceptron Neuron) tt_um_histogramming (Histogramming) tt_um_gfcwfzkm_scope_bfh_mht1_3 (Basic Oszilloscope and Signal Generator) tt_um_MichaelBell_rle_vga (RLE Video Player) tt_um_ece298a_8_bit_cpu_top (8-Bit CPU) tt_um_Coline3003_top (15 channels emission counter) tt_um_dlmiles_dffram32x8_2r1w (Tiny RAM DFF 2r1w) tt_um_urish_sic1 (SIC-1 8-bit SUBLEQ Single Instruction Computer) tt_um_Coline3003_spect_top (Spectrogram extractor, 2 channels) tt_um_CarrySelect8bit (carry_select) tt_um_koggestone_adder8 (test_friday2) tt_um_Rapoport (Perceptron) tt_um_cellular_alchemist (Hopfield Network with Izhikevich-type RS and FS Neurons) tt_um_tinysynth (Tinysynth) tt_um_wokwi_414120248222232577 (A Tale of Two NCOs) tt_um_a1k0n_nyancat (VGA Nyan Cat) tt_um_tommythorn_workshop (Workshop demo) tt_um_lrc_stevej (LRC - Longitudinal Redundancy Check generator) tt_um_shifter (Shifter) tt_um_schoeberl_test (tinydsp-lol) tt_um_anislam (Leaky integrate and fire spiking neural network) tt_um_systolicLif (Basic model for Systollic array implementation of LIF) tt_um_algofoogle_tt09_ring_osc2 (Verilog ring oscillator V2) tt_um_dff_mem (dff_mem) tt_um_nomuwill (16 Bit Izhikevich Neuron) tt_um_digital_clock_example (7-Segment Digital Desk Clock) tt_um_udxs (Basic Perceptron + ReLU) tt_um_matrix_mult (Basic Matrix-Vector Multiplication) tt_um_db_MAC (8 bit MAC Unit) tt_um_anas_7193 (Programmable PWM Generator) tt_um_flyingfish800 (Verilog test project) tt_um_project_tt09 (Basic LIF Neuron) tt_um_lifn (Integrate-and-Fire Neuron Circuit) tt_um_rejunity_e2m0_x_i8_matmul (E2M0 x INT8 Systolic Array) tt_um_michaelmcculloch_alu (Michaels Tiny Tapeout ALU) tt_um_dog_BILBO (8-bit CBILBO) tt_um_stochastic_integrator_tt9_CL123abc (Stochastic Integrator) tt_um_samkho_two_channel_square_wave_generator (TwoChannelSquareWaveGenerator) tt_um_urish_giant_ringosc (Giant Ring Oscillator (3853 inverters)) tt_um_htfab_caterpillar (Simon's Caterpillar) tt_um_purdue_socet_uart (SoCET UART with FIFO buffers) tt_um_rejunity_sn76489 (Classic 8-bit era Programmable Sound Generator SN76489) tt_um_rejunity_ay8913 (Classic 8-bit era Programmable Sound Generator AY-3-8913) tt_um_tommythorn_cgates (Cgates) tt_um_09eksdee (eksdee) tt_um_rejunity_decoder (ternary, E1M0, E2M0 decoders) tt_um_kailinsley (Dynamic Threshold Leaky Integrate-and-Fire) tt_um_rejunity_vga_test01 (VGA Drop (audio/visual demo)) tt_um_wallento_4bit_toycpu (4-Bit Toy CPU) tt_um_warp (Warp) tt_um_algofoogle_tt09_ring_osc3 (Verilog ring oscillator V3) tt_um_kev_ma_matmult222 (2-bit 2x2 Matrix Multiplier) tt_um_rejunity_vga_logo (VGA Tiny Logo (1 tile)) tt_um_liaf (A simple leaky integrate and fire neuron) tt_um_lif_network_MR (Leaky Neuron Network) tt_um_lsnn_hschweig (Neuromorphic Hardware for SNN LSTM) tt_um_Nishanth_RISCV (RISCV Processor Design) tt_um_KoushikCSN_RISCV (RISCV Processor Design) tt_um_ccu_goatgate (tiny cipher 4 bit key) tt_um_lif_ZB (Tutorial: Simple LIF Neuron) tt_um_z2a_rgb_mixer (RGB Mixer demo) tt_um_vga_clock (VGA clock) tt_um_synth_simple_mm (synth_simple) tt_um_gus16 (GUS16 CPU) tt_um_rejunity_ternary_dot (Ternary 128-element Dot Product) tt_um_virantha_enigma (Enigma - 52-bit Key Length) tt_um_atomNPU (AtomNPU) tt_um_alphaonesoc (AlphaOneSoC) tt_um_gxrii_spi_sevenseg (SPI 7-segment display) tt_um_urish_simon (Simon Says memory game) tt_um_branch_pred (TinyTapeout Minimal Branch Predictor) tt_um_xor_encryption (Xor-Logic) tt_um_MAC_Accelerator_OnSachinSharma (MAC Operation) tt_um_moody_mimosa (Moody-mimosa) tt_um_wrapper (6Digit7SegClock) tt_um_MichaelBell_tinyQV (TinyQV Risc-V SoC) tt_um_devmonk_ay8913 (Classic 8-bit era Programmable Sound Generator AY-3-8913) tt_um_toivoh_demo_tt10 (Orion Iron Ion [TT08 demo competition]) tt_um_2048_vga_game (2048 sliding tile puzzle game (VGA)) tt_um_gamepad_pmod_demo (Gamepad Pmod Demo) tt_um_tinytapeout_logo_screensaver (VGA Screensaver with Tiny Tapeout Logo) tt_um_mattvenn_spi_test (SPI test) tt_um_huffman_coder (Huffmann_Coder) tt_um_multiplier_tt10 (Vedic multiplier) tt_um_schoeberl_wildcat (Wildcat RISC-V) tt_um_kentrane_tinyspectrum (Tiny piano) tt_um_i2c_regf (Asynchronous I2C Registerfile Interface) tt_um_tappu_tobias1012 (Tappu) tt_um_mp_lif_schor (mp_LIF_neuron) tt_um_asgerwenneb (Custom SRAM) tt_um_Strider93 (digital LIF Neuron) tt_um_wokwi_422960078645704705 (Hero on Tape) tt_um_keszocze_ssmcl (SSMCl) tt_um_luke_clock (TT10_Luke_Clock) tt_um_enjens (Verilog based clock to 7-segment counter) tt_um_UartMain (XOR Cipher) tt_um_torurstrom_async_lock (Asynchronous Locking Unit) tt_um_larva (LaRVa CPU) tt_um_zhouzhouthezhou_adder (tt10_zhouzhouthezhou_adder) tt_um_jp_cd101_saw (KCH CD101 Saw Synth) tt_um_hpdl1414_uart_atudoroi (TT10 HPDL 1414 Uart) tt_um_jun1okamura_test0 (7-segment with LFSR) tt_um_strau0106_simple_viii (simple-viii) tt_um_obriensp_jtag (JTAG TAP) tt_um_10_vga_crossyroad (Crossyroad) tt_um_bilal_trng (TRNG) tt_um_space_invaders_game (Space Invaders ASIC) tt_um_sushi_demo (zc-sushi-demo) tt_um_kch_cd101 (kch cd101) tt_um_uart_bgdtanasa (ttUART) tt_um_zedulo_spitest1 (SimpleSPIdev) tt_um_daobaanh_rng (RNG_test) tt_um_gcd_stephan (15bit GCD) tt_um_spacewar (XY Spacewar) tt_um_gregac_tiny_nn (Tiny Neural Network Accelerator) tt_um_log_afpm (16-bit Logarithmic Approximate Floating Point Multiplier) tt_um_rkarl_Spiral (TT_spiralPattern) tt_um_led_jellyant (ledtest) tt_um_project_tt10 (Simple shift Reg) tt_um_DaDDS (DaDDS) tt_um_nithishreddykvs (Pulse Width Modulation) tt_um_monishvr_fifo (Synchronous FIFO) tt_um_reemashivva_fifo (Asynchronous FIFO) tt_um_save_buffer_hash_table (Tiny Hash Table) tt_um_drum_goekce (DRUM) tt_um_rte_sine_synth (Sine Synth) tt_um_tiny_shader_mole99 (Tiny Shader) tt_um_flummer_ltc (Linear Timecode (LTC) generator) tt_um_bitty (Bitty) tt_um_ole_moller_priority_encoder_to_7_segment_decoder (Priority-encoder) tt_um_algofoogle_vga (IHP VGA demo) tt_um_ultra_tiny_cpu (UltraTiny-CPU) tt_um_uwasic_dinogame (UW ASIC - Optimized Dino) tt_um_Qwendu_spi_fpu (SPI FPU) tt_um_aditya_patra (Priority-Encoded Arbiter) tt_um_4_bit_ALU (ALU) tt_um_htfab_checkers (Overengineered Checkers) tt_um_brukstus_tdc_with_spi (TDC with SPI) tt_um_toniklippeo (toni_clk_gen) tt_um_spi_pwm_djuara (spi_pwm) tt_um_iitbbs (CYCLIPSONIC) tt_um_wokwi_411783629732984833 (BINCounterAndGates) tt_um_wokwi_412635532198550529 (tt09-pettit-wokproc-trainer) tt_um_wokwi_413385294512575489 (Duffy) tt_um_wokwi_413387014781302785 (L display) tt_um_wokwi_413387093939376129 (sphereinabox hello) tt_um_wokwi_413387190167208961 (Will It NAND?) tt_um_wokwi_group_1 tt_um_wokwi_group_2 tt_um_wokwi_group_3 tt_um_wokwi_group_4 tt_um_wokwi_group_5 tt_um_wokwi_group_6 tt_um_wokwi_group_7 tt_um_wokwi_group_8 tt_um_wokwi_group_9 tt_um_wokwi_group_10 tt_um_wokwi_group_11 tt_um_wokwi_group_12 tt_um_tetrap_triggerer (triggerer) tt_um_wokwi_group_13 tt_um_multiplier_group_1 tt_um_multiplier_group_2 tt_um_multiplier_group_3