├── correlator ├── .gitignore ├── config.vlt ├── x.dat ├── Makefile ├── correlator.v ├── test.gtkw ├── correlator.gtkw ├── mac.v └── correlator_tb.v ├── orangecrab ├── .gitignore ├── source.sh ├── config.vlt ├── reset_crab.sh ├── firmware.h ├── ram.v ├── cpu_sections.lds ├── orangecrab_r02.lpf ├── make.py ├── orangecrab.v ├── Makefile └── firmware.c ├── wavegen ├── .gitignore ├── config.vlt ├── Makefile ├── wavegen_tb.v ├── wave.py ├── uart.v ├── wavegen.gtkw └── wavegen.v ├── serv ├── .gitignore └── README.md ├── dsp ├── .gitignore ├── images │ └── scr_202007181421.png ├── multiplier.v ├── dma.h ├── addr_adder.v ├── config.vlt ├── twos_complement.v ├── firmware.h ├── dpram.v ├── pipe.v ├── shifter.v ├── pipe_tb.gtkw ├── accumulator.v ├── test.gtkw ├── iomem.v ├── gpio.v ├── shifter_tb.v ├── agc_tb.gtkw ├── dma.c ├── i2s_clock_tb.gtkw ├── i2s_tx.v ├── dsp_tb.gtkw ├── i2s_clock.v ├── icebreaker_sections.lds ├── spl_tb.gtkw ├── shifter_tb.gtkw ├── i2s_rx.v ├── i2s_rx_tb.gtkw ├── audio_gen.py ├── spl.v ├── sk9822_tb.v ├── icebreaker.v ├── dma_tb.gtkw ├── i2s_clock_tb.v ├── sk9822_tb.gtkw ├── dsp.gtkw ├── README.md ├── pipe_tb.v ├── Makefile ├── firmware.c ├── sk9822.v ├── dsp_tb.v ├── i2s_secondary.v ├── spl_tb.v ├── dma.v ├── agc.v ├── sequencer.v ├── dma_tb.v ├── agc_tb.v ├── i2s_rx_tb.v ├── dsp.v └── audio_engine.v ├── README.md ├── .gitignore ├── icebreaker.pcf ├── main.mk └── alhambra-ii.pcf /correlator/.gitignore: -------------------------------------------------------------------------------- 1 | *_tb 2 | -------------------------------------------------------------------------------- /orangecrab/.gitignore: -------------------------------------------------------------------------------- 1 | pll.v 2 | build 3 | -------------------------------------------------------------------------------- /wavegen/.gitignore: -------------------------------------------------------------------------------- 1 | wave.v 2 | pll.v 3 | wavegen_tb 4 | -------------------------------------------------------------------------------- /serv/.gitignore: -------------------------------------------------------------------------------- 1 | pll.v 2 | *.hex 3 | *.elf 4 | *_tb 5 | tags 6 | -------------------------------------------------------------------------------- /dsp/.gitignore: -------------------------------------------------------------------------------- 1 | *_tb 2 | firmware.elf 3 | pll.v 4 | tags 5 | source.sh 6 | tick.wav 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Archive for FPGA Verilog code 3 | ============================= 4 | 5 | 6 | -------------------------------------------------------------------------------- /dsp/images/scr_202007181421.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaveBerkeley/fpga/HEAD/dsp/images/scr_202007181421.png -------------------------------------------------------------------------------- /correlator/config.vlt: -------------------------------------------------------------------------------- 1 | `verilator_config 2 | lint_off -file "/usr/share/yosys/ice40/cells_sim.v" 3 | lint_off -rule DECLFILENAME 4 | -------------------------------------------------------------------------------- /correlator/x.dat: -------------------------------------------------------------------------------- 1 | 1234 2 | 2345 3 | 8080 4 | 2222 5 | 3333 6 | 4444 7 | 0000 8 | ffff 9 | 1111 10 | 2222 11 | 4444 12 | 8888 13 | -------------------------------------------------------------------------------- /serv/README.md: -------------------------------------------------------------------------------- 1 | 2 | SERV based SoC code moved to a new repository. 3 | 4 | See [github](https://github.com/DaveBerkeley/serv_soc) 5 | -------------------------------------------------------------------------------- /orangecrab/source.sh: -------------------------------------------------------------------------------- 1 | export SOC=/home/dave/Desktop/git/serv_soc/src 2 | export SERV=~/Desktop/serv 3 | export PATH=/opt/riscv32i/bin:$HOME/yosys:$PATH 4 | -------------------------------------------------------------------------------- /wavegen/config.vlt: -------------------------------------------------------------------------------- 1 | `verilator_config 2 | lint_off -file "/usr/share/yosys/ice40/cells_sim.v" 3 | lint_off -file "pll.v" 4 | lint_off -rule DECLFILENAME 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | *.swp 3 | *~ 4 | # build products 5 | *.asc 6 | *.bin 7 | *.json 8 | *.log 9 | *.rpt 10 | # test products 11 | *.vcd 12 | *.vvp 13 | -------------------------------------------------------------------------------- /dsp/multiplier.v: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | */ 5 | 6 | module multiplier( 7 | input wire ck, 8 | input wire [15:0] a, 9 | input wire [15:0] b, 10 | output reg [31:0] out 11 | ); 12 | 13 | always @(posedge ck) begin 14 | out <= a * b; 15 | end 16 | 17 | endmodule 18 | 19 | 20 | -------------------------------------------------------------------------------- /orangecrab/config.vlt: -------------------------------------------------------------------------------- 1 | `verilator_config 2 | lint_off -file "pll.v" 3 | lint_off -rule DECLFILENAME 4 | lint_off -file "${SERV}/rtl/serv_top.v" 5 | lint_off -file "${SERV}/rtl/serv_mem_if.v" 6 | lint_off -file "${SERV}/rtl/serv_ctrl.v" 7 | lint_off -file "${SERV}/rtl/serv_alu.v" 8 | lint_off -file "${SERV}/rtl/serv_immdec.v" 9 | lint_off -file "${SERV}/rtl/serv_decode.v" 10 | -------------------------------------------------------------------------------- /orangecrab/reset_crab.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CRAB_POWER="home/usb/1/0" 4 | CRAB_RESET="home/usb/1/1" 5 | 6 | HOST="mosquitto" 7 | 8 | OFF="R" 9 | ON="S" 10 | 11 | mosquitto_pub -h $HOST -t $CRAB_POWER -m $OFF 12 | 13 | #sleep 1 14 | #mosquitto_pub -h $HOST -t $CRAB_RESET -m $ON 15 | 16 | sleep 1 17 | mosquitto_pub -h $HOST -t $CRAB_POWER -m $ON 18 | 19 | #sleep 1 20 | #mosquitto_pub -h $HOST -t $CRAB_RESET -m $OFF 21 | 22 | # FIN 23 | -------------------------------------------------------------------------------- /dsp/dma.h: -------------------------------------------------------------------------------- 1 | 2 | #if defined(USE_DMA) 3 | 4 | #define DMA_STATUS_XFER_DONE (1 << 0) 5 | #define DMA_STATUS_BLOCK_DONE (1 << 1) 6 | 7 | uint32_t dma_get_status(); 8 | 9 | void dma_set_addr(void *addr); 10 | void dma_set_match(void *addr); 11 | void dma_set_step(uint32_t v); 12 | void dma_set_cycles(uint32_t v); 13 | void dma_set_blocks(uint32_t v); 14 | 15 | void dma_start(bool repeat); 16 | void dma_stop(); 17 | 18 | #endif 19 | 20 | // FIN 21 | -------------------------------------------------------------------------------- /dsp/addr_adder.v: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | */ 5 | 6 | module addr_adder 7 | #(parameter FRAME_W = 6, parameter CHAN_W = 3) 8 | ( input wire ck, 9 | input wire [FRAME_W-1:0] frame, 10 | input wire [FRAME_W-1:0] offset, 11 | input wire [CHAN_W-1:0] chan, 12 | output reg [(FRAME_W+CHAN_W)-1:0] addr 13 | ); 14 | 15 | always @(posedge ck) begin 16 | addr <= { chan, frame + offset }; 17 | end 18 | 19 | endmodule 20 | 21 | -------------------------------------------------------------------------------- /dsp/config.vlt: -------------------------------------------------------------------------------- 1 | `verilator_config 2 | lint_off -file "pll.v" 3 | lint_off -file "${SOC}/ice40up5k_spram.v" 4 | lint_off -file "/usr/share/yosys/ice40/cells_sim.v" 5 | lint_off -file "${SERV}/rtl/serv_top.v" 6 | lint_off -file "${SERV}/rtl/serv_mem_if.v" 7 | lint_off -file "${SERV}/rtl/serv_ctrl.v" 8 | lint_off -file "${SERV}/rtl/serv_alu.v" 9 | lint_off -file "${SERV}/rtl/serv_decode.v" 10 | lint_off -file "${SERV}/rtl/serv_immdec.v" 11 | lint_off -rule DECLFILENAME 12 | -------------------------------------------------------------------------------- /dsp/twos_complement.v: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | */ 5 | 6 | module twos_complement 7 | #(parameter WIDTH=16) 8 | (input wire ck, 9 | input wire inv, 10 | input wire [(WIDTH-1):0] in, 11 | output reg [(WIDTH-1):0] out 12 | ); 13 | 14 | initial out = 0; 15 | 16 | always @(posedge ck) begin 17 | if (inv) 18 | out <= 1'b1 + ~in; 19 | else 20 | out <= in; 21 | end 22 | 23 | endmodule 24 | 25 | -------------------------------------------------------------------------------- /wavegen/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = wavegen 2 | ADD_SRC = ../dsp/i2s_clock.v ../dsp/i2s_tx.v ../dsp/i2s_secondary.v 3 | ADD_CLEAN = wave.v wavegen_tb 4 | ADD_DEPS = wave.v 5 | ADD_YOSYS = 6 | ADD_VERILATOR = config.vlt 7 | ADD_IVERILOG = $(PROJ).v 8 | 9 | TB_SRC = ../dsp/i2s_clock.v ../dsp/i2s_tx.v ../dsp/i2s_secondary.v 10 | 11 | PACKAGE = tq144:4k 12 | DEVICE = hx8k 13 | 14 | PIN_DEF = ../alhambra-ii.pcf 15 | 16 | include ../main.mk 17 | 18 | wave.v : wave.py 19 | ./wave.py > wave.v 20 | 21 | -------------------------------------------------------------------------------- /correlator/Makefile: -------------------------------------------------------------------------------- 1 | PROJ = correlator 2 | ADD_SRC = ../dsp/dpram.v ../dsp/iomem.v ../dsp/multiplier.v ../dsp/accumulator.v ../dsp/shifter.v ../dsp/gpio.v ../dsp/twos_complement.v ../dsp/pipe.v mac.v 3 | ADD_CLEAN = correlator_tb correlator_syntb correlator_syn.v *_tb *.vcd 4 | ADD_YOSYS = -dsp 5 | ADD_VERILATOR = config.vlt 6 | ADD_IVERILOG = correlator.v 7 | 8 | PACKAGE = sg48 9 | DEVICE = up5k 10 | 11 | PIN_DEF = ../icebreaker.pcf 12 | 13 | #TB_SRC = $(filter-out pll.v, $(ADD_SRC)) 14 | TB_SRC = $(ADD_SRC) 15 | 16 | include ../main.mk 17 | 18 | 19 | -------------------------------------------------------------------------------- /wavegen/wavegen_tb.v: -------------------------------------------------------------------------------- 1 | 2 | `default_nettype none 3 | `timescale 1ns / 100ps 4 | 5 | /* 6 | * 7 | */ 8 | 9 | module tb(); 10 | 11 | initial begin 12 | $dumpfile("wavegen.vcd"); 13 | $dumpvars(0, tb); 14 | #500000 $finish; 15 | end 16 | 17 | reg ck = 0; 18 | 19 | always #42 ck <= !ck; 20 | 21 | wire d0, d1, d2, d3; 22 | 23 | top top(.CLK(ck), .D0(d0), .D1(d1), .D2(d2), .D3(d3)); 24 | 25 | // feeed the generated signal back 26 | assign d0 = d1; 27 | assign d2 = d3; 28 | 29 | endmodule 30 | 31 | -------------------------------------------------------------------------------- /dsp/firmware.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | */ 5 | 6 | #if !defined(__FIRMWARE_H__) 7 | #define __FIRMWARE_H__ 8 | 9 | #define LEDS ((uint32_t volatile*) 0x40000000) 10 | #define flash ((uint32_t volatile*) 0x70000000) 11 | 12 | #if defined(USE_SK9822) 13 | #define LED_IO ((uint32_t volatile*) 0x90000000) 14 | #endif 15 | 16 | /* 17 | * 18 | */ 19 | 20 | #define TRACE() { print(__FILE__); print(" "); print_dec(__LINE__); print("\r\n"); } 21 | 22 | 23 | uint32_t colour(uint8_t bright, uint8_t r, uint8_t g, uint8_t b); 24 | 25 | #endif // __FIRMWARE_H__ 26 | 27 | // FIN 28 | -------------------------------------------------------------------------------- /orangecrab/firmware.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | */ 5 | 6 | #if !defined(__FIRMWARE_H__) 7 | #define __FIRMWARE_H__ 8 | 9 | #define LEDS ((uint32_t volatile*) 0x40000000) 10 | #define flash ((uint32_t volatile*) 0x70000000) 11 | 12 | #if defined(USE_SK9822) 13 | #define LED_IO ((uint32_t volatile*) 0x90000000) 14 | #endif 15 | 16 | /* 17 | * 18 | */ 19 | 20 | #define TRACE() { print(__FILE__); print(" "); print_dec(__LINE__); print("\r\n"); } 21 | 22 | 23 | uint32_t colour(uint8_t bright, uint8_t r, uint8_t g, uint8_t b); 24 | 25 | #endif // __FIRMWARE_H__ 26 | 27 | // FIN 28 | -------------------------------------------------------------------------------- /dsp/dpram.v: -------------------------------------------------------------------------------- 1 | 2 | 3 | module dpram 4 | # (parameter BITS=16, SIZE=256, AWIDTH=$clog2(SIZE)) 5 | ( 6 | input wire ck, 7 | input wire we, 8 | input wire [AWIDTH-1:0] waddr, 9 | input wire [BITS-1:0] wdata, 10 | 11 | input wire re, 12 | input wire [AWIDTH-1:0] raddr, 13 | output reg [BITS-1:0] rdata 14 | ); 15 | 16 | reg [BITS-1:0] ram [0:SIZE-1]; 17 | 18 | always @(posedge ck) begin 19 | 20 | if (we) begin 21 | ram[waddr] <= wdata; 22 | end 23 | 24 | if (re) begin 25 | rdata <= ram[raddr]; 26 | end 27 | 28 | end 29 | 30 | endmodule 31 | 32 | // FIN 33 | -------------------------------------------------------------------------------- /dsp/pipe.v: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | */ 5 | 6 | module pipe 7 | #(parameter LENGTH=1, parameter INIT=0) 8 | (input wire ck, 9 | input wire in, 10 | output wire out 11 | ); 12 | 13 | reg [(LENGTH-1):0] delay = INIT; 14 | 15 | generate 16 | 17 | if (LENGTH == 1) begin 18 | 19 | always @(posedge ck) begin 20 | delay <= in; 21 | end 22 | 23 | end else begin 24 | 25 | always @(posedge ck) begin 26 | delay <= { delay[LENGTH-2:0], in }; 27 | end 28 | 29 | end 30 | 31 | endgenerate 32 | 33 | assign out = delay[LENGTH-1]; 34 | 35 | endmodule 36 | 37 | 38 | -------------------------------------------------------------------------------- /correlator/correlator.v: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | */ 5 | 6 | module top ( 7 | input wire CLK 8 | ); 9 | 10 | wire ck; 11 | assign ck = CLK; 12 | 13 | reg clr, acc_en, req; 14 | reg [15:0] x; 15 | reg [15:0] y; 16 | /* verilator lint_off UNUSED */ 17 | wire [39:0] acc_out; 18 | wire acc_done; 19 | /* verilator lint_on UNUSED */ 20 | 21 | initial begin 22 | clr = 0; 23 | acc_en = 0; 24 | req = 0; 25 | x = 16'h1234; 26 | y = 16'h1234; 27 | end 28 | 29 | mac mac(.ck(ck), .en(acc_en), .clr(clr), .req(req), 30 | .x(x), .y(y), .out(acc_out), .done(acc_done)); 31 | 32 | endmodule 33 | 34 | 35 | -------------------------------------------------------------------------------- /wavegen/wave.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import math 4 | 5 | addr_bits = 7 6 | gain_bits = 16 7 | 8 | points = 1 << addr_bits 9 | gain = int(((1 << (gain_bits - 1)) - 1) * 0.7) 10 | dc = 1 << (gain_bits - 1) 11 | 12 | print("// Auto-Generated : do not edit") 13 | print("") 14 | 15 | print("function signed [(%d-1):0] sin(input [(%d-1):0] addr);" % (gain_bits, addr_bits)) 16 | print("begin") 17 | 18 | for i in range(points): 19 | 20 | rad = (i * 2 * math.pi) / points 21 | value = math.sin(rad) * gain 22 | value = int(value) 23 | value &= 0xFFFF 24 | 25 | print(" if (addr == %d) sin = 16'h%04x;" % (i, value)) 26 | 27 | print("end") 28 | print("endfunction") 29 | 30 | # FIN 31 | -------------------------------------------------------------------------------- /dsp/shifter.v: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | */ 5 | 6 | module shifter 7 | #(parameter IN_W=40, OUT_W=16, SHIFT_W=5) 8 | ( 9 | input wire ck, 10 | input wire en, 11 | input wire [SHIFT_W-1:0] shift, 12 | input wire [IN_W-1:0] in, 13 | output reg [OUT_W-1:0] out 14 | ); 15 | 16 | initial out = 0; 17 | 18 | wire [OUT_W-1:0] shifted; 19 | 20 | genvar i; 21 | 22 | generate 23 | 24 | for (i = 0; i < OUT_W; i = i + 1) begin 25 | assign shifted[i] = in[i+shift]; 26 | end 27 | 28 | endgenerate 29 | 30 | always @(posedge ck) begin 31 | if (en) begin 32 | out <= shifted; 33 | end 34 | end 35 | 36 | endmodule 37 | 38 | 39 | -------------------------------------------------------------------------------- /dsp/pipe_tb.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Sat Aug 1 19:48:36 2020 4 | [*] 5 | [dumpfile] "/home/dave/Desktop/git/fpga/dsp/dsp.vcd" 6 | [dumpfile_mtime] "Sat Aug 1 19:22:42 2020" 7 | [dumpfile_size] 145783 8 | [savefile] "/home/dave/Desktop/git/fpga/dsp/pipe_tb.gtkw" 9 | [timestart] 0 10 | [size] 1329 625 11 | [pos] -1 -1 12 | *-19.000000 70000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [sst_width] 196 15 | [signals_width] 118 16 | [sst_expanded] 1 17 | [sst_vpaned_height] 164 18 | @28 19 | tb.ck 20 | tb.rst 21 | tb.pipe_test.in 22 | tb.pipe_test.out 23 | @200 24 | - 25 | @22 26 | tb.p_in[15:0] 27 | tb.p_out[15:0] 28 | @28 29 | tb.pipe1.in 30 | @29 31 | tb.pipe1.out 32 | [pattern_trace] 1 33 | [pattern_trace] 0 34 | -------------------------------------------------------------------------------- /orangecrab/ram.v: -------------------------------------------------------------------------------- 1 | 2 | `default_nettype none 3 | 4 | module sp_ram 5 | ( 6 | input wire ck, 7 | input wire cyc, 8 | input wire we, 9 | input wire [3:0] sel, 10 | /* verilator lint_off UNUSED */ 11 | input wire [31:0] addr, 12 | /* verilator lint_on UNUSED */ 13 | input wire [31:0] wdata, 14 | output wire [31:0] rdata 15 | ); 16 | 17 | parameter WORDS = 8 * 1024; // 32768; 18 | 19 | reg [31:0] mem [0:(WORDS-1)]; 20 | 21 | always @(posedge ck) begin 22 | if (we) begin 23 | if (sel[0]) mem[addr][ 7: 0] <= wdata[ 7: 0]; 24 | if (sel[1]) mem[addr][15: 8] <= wdata[15: 8]; 25 | if (sel[2]) mem[addr][23:16] <= wdata[23:16]; 26 | if (sel[3]) mem[addr][31:24] <= wdata[31:24]; 27 | end 28 | rdata <= mem[addr]; 29 | end 30 | 31 | endmodule 32 | 33 | // FIN 34 | -------------------------------------------------------------------------------- /dsp/accumulator.v: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | */ 5 | 6 | module accumulator( 7 | input wire ck, 8 | input wire en, 9 | input wire rst, 10 | input wire add, 11 | input wire [31:0] in, 12 | output reg signed [(OUT_W-1):0] out 13 | ); 14 | 15 | parameter OUT_W = 40; 16 | 17 | initial out = 0; 18 | 19 | // normalise the input as a 40-bit signed +ve number 20 | wire [(OUT_W-33):0] zeros; 21 | wire signed [(OUT_W-1):0] to_add; 22 | assign zeros = 0; 23 | assign to_add = { zeros, in }; 24 | 25 | wire [(OUT_W-1):0] prev; 26 | 27 | assign prev = rst ? 0 : out; 28 | 29 | always @(posedge ck) begin 30 | if (en) begin 31 | if (add) 32 | out <= prev + to_add; 33 | else 34 | out <= prev - to_add; 35 | end 36 | end 37 | 38 | endmodule 39 | 40 | 41 | -------------------------------------------------------------------------------- /dsp/test.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Sat Jul 18 06:57:25 2020 4 | [*] 5 | [dumpfile] "/home/dave/Desktop/git/fpga/dsp/dsp.vcd" 6 | [dumpfile_mtime] "Sat Jul 18 06:57:05 2020" 7 | [dumpfile_size] 932830 8 | [savefile] "/home/dave/Desktop/git/fpga/dsp/test.gtkw" 9 | [timestart] 59587000 10 | [size] 1899 785 11 | [pos] -1 -1 12 | *-20.007879 63504000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [treeopen] tb.engine. 15 | [sst_width] 196 16 | [signals_width] 174 17 | [sst_expanded] 1 18 | [sst_vpaned_height] 221 19 | @28 20 | tb.engine.rx_0.ck 21 | tb.engine.rx_0.en 22 | @29 23 | tb.engine.rx_0.mid_bit 24 | @22 25 | tb.engine.rx_0.frame_posn[5:0] 26 | tb.engine.rx_0.left[15:0] 27 | tb.engine.rx_0.right[15:0] 28 | @28 29 | tb.engine.rx_0.sd 30 | @22 31 | tb.engine.rx_0.shift[15:0] 32 | [pattern_trace] 1 33 | [pattern_trace] 0 34 | -------------------------------------------------------------------------------- /dsp/iomem.v: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Handle iomem interface 4 | * 5 | * Interface to the Risc-V bus 6 | */ 7 | 8 | module iomem 9 | #(parameter ADDR=16'h0300) 10 | (input wire ck, 11 | input wire valid, 12 | input wire [3:0] wstrb, 13 | /* verilator lint_off UNUSED */ 14 | input wire [31:0] addr, 15 | /* verilator lint_on UNUSED */ 16 | 17 | output reg ready, 18 | output wire we, 19 | output wire re 20 | ); 21 | 22 | initial ready = 0; 23 | 24 | wire enable; 25 | assign enable = valid && !ready && (addr[31:16] == ADDR); 26 | 27 | wire write; 28 | assign write = | wstrb; 29 | assign we = enable && write; 30 | assign re = enable && !write; 31 | 32 | always @(posedge ck) begin 33 | if (ready) 34 | ready <= 0; 35 | if (enable) begin 36 | ready <= 1; 37 | end 38 | end 39 | 40 | endmodule 41 | 42 | // FIN 43 | -------------------------------------------------------------------------------- /correlator/test.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Tue Jul 21 04:35:23 2020 4 | [*] 5 | [dumpfile] "/home/dave/Desktop/git/fpga/correlator/correlator.vcd" 6 | [dumpfile_mtime] "Tue Jul 21 04:34:34 2020" 7 | [dumpfile_size] 510076 8 | [savefile] "/home/dave/Desktop/git/fpga/correlator/test.gtkw" 9 | [timestart] 0 10 | [size] 1851 653 11 | [pos] -1 -1 12 | *-18.000000 140000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [sst_width] 196 15 | [signals_width] 142 16 | [sst_expanded] 1 17 | [sst_vpaned_height] 174 18 | @28 19 | tb.level_test.ck 20 | @22 21 | tb.level_test.in[39:0] 22 | tb.level_test.normal[39:0] 23 | tb.level_test.bit_1[39:0] 24 | tb.level_test.bit_2[39:0] 25 | tb.level_test.bit_4[39:0] 26 | tb.level_test.bit_8[39:0] 27 | tb.level_test.bit_16[39:0] 28 | tb.level_test.bit_32[39:0] 29 | tb.level_test.bit_64[39:0] 30 | tb.level_test.hi_bit[39:0] 31 | tb.level_test.out[5:0] 32 | [pattern_trace] 1 33 | [pattern_trace] 0 34 | -------------------------------------------------------------------------------- /dsp/gpio.v: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | */ 5 | 6 | module gpio( 7 | input wire ck, 8 | input wire rst, 9 | input wire iomem_valid, 10 | output reg iomem_ready, 11 | input wire [3:0] iomem_wstrb, 12 | input wire [31:0] iomem_addr, 13 | input wire [31:0] iomem_wdata, 14 | output reg [31:0] iomem_rdata, 15 | output wire [7:0] leds 16 | ); 17 | 18 | parameter ADDR = 16'h0300; 19 | 20 | reg [31:0] gpio_reg; 21 | assign leds = gpio_reg; 22 | 23 | wire re, we; 24 | 25 | iomem #(.ADDR(ADDR)) io(.ck(ck), 26 | .valid(iomem_valid), .ready(iomem_ready), .wstrb(iomem_wstrb), .addr(iomem_addr), 27 | .we(we), .re(re)); 28 | 29 | always @(posedge ck) begin 30 | if (!rst) begin 31 | gpio_reg <= 0; 32 | end else begin 33 | if (we) 34 | gpio_reg <= iomem_wdata; 35 | if (re) 36 | iomem_rdata <= gpio_reg; 37 | end 38 | end 39 | 40 | endmodule 41 | 42 | 43 | -------------------------------------------------------------------------------- /dsp/shifter_tb.v: -------------------------------------------------------------------------------- 1 | 2 | `default_nettype none 3 | `timescale 1ns / 100ps 4 | 5 | module tb (); 6 | 7 | initial begin 8 | $dumpfile("dsp.vcd"); 9 | $dumpvars(0, tb); 10 | #500000 $finish; 11 | end 12 | 13 | reg ck = 0; 14 | 15 | always #42 ck <= !ck; 16 | 17 | reg en = 0; 18 | reg [4:0] shift = 0; 19 | reg [39:0] in = 0; 20 | wire [15:0] out; 21 | 22 | shifter #(.SHIFT_W(5)) shifter ( 23 | .ck(ck), 24 | .en(en), 25 | .shift(shift), 26 | .in(in), 27 | .out(out) 28 | ); 29 | 30 | integer i; 31 | 32 | initial begin 33 | @(posedge ck); 34 | @(posedge ck); 35 | 36 | in <= 40'h00abcd1234; 37 | en <= 1; 38 | 39 | for (i = 0; i < 24; i = i + 1) begin 40 | 41 | shift <= i; 42 | @(posedge ck); 43 | @(posedge ck); 44 | tb_assert(out == ((in >> shift) & 16'hFFFF)); 45 | 46 | end 47 | 48 | end 49 | 50 | endmodule 51 | 52 | -------------------------------------------------------------------------------- /wavegen/uart.v: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | */ 4 | 5 | module uart( 6 | input wire ck, 7 | input wire [7:0] tx_data, 8 | output wire tx, 9 | output wire ready, 10 | output wire baud 11 | ); 12 | 13 | reg [6:0] baud_counter = 0; 14 | 15 | always @(negedge ck) begin 16 | if (baud_counter < 104) 17 | baud_counter <= baud_counter + 1; 18 | else 19 | baud_counter <= 0; 20 | end 21 | 22 | reg [3:0] count = 0; 23 | reg [9:0] shift; 24 | 25 | always @(negedge ck) begin 26 | if (baud_counter == 0) begin 27 | 28 | if (count == 0) 29 | shift <= { 1'b1, tx_data, 1'b0 }; 30 | else 31 | shift <= { 1'b1, shift[9:1] }; 32 | 33 | if (count == 10) 34 | count <= 0; 35 | else 36 | count <= count + 1; 37 | end 38 | end 39 | 40 | assign tx = shift[0]; 41 | assign ready = count == 0; 42 | assign baud = baud_counter >= 50; 43 | 44 | endmodule 45 | 46 | 47 | -------------------------------------------------------------------------------- /dsp/agc_tb.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Mon Aug 24 17:36:00 2020 4 | [*] 5 | [dumpfile] "/home/dave/Desktop/git/fpga/dsp/dsp.vcd" 6 | [dumpfile_mtime] "Mon Aug 24 13:15:03 2020" 7 | [dumpfile_size] 93291 8 | [savefile] "/home/dave/Desktop/git/fpga/dsp/agc_tb.gtkw" 9 | [timestart] 0 10 | [size] 1712 598 11 | [pos] -1 -1 12 | *-17.802307 969000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [treeopen] tb.agc.gain_mod. 15 | [treeopen] tb.gain. 16 | [sst_width] 196 17 | [signals_width] 182 18 | [sst_expanded] 1 19 | [sst_vpaned_height] 155 20 | @28 21 | tb.ck 22 | tb.gain_en 23 | @29 24 | tb.gain_done 25 | @28 26 | tb.gain_addr[1:0] 27 | @22 28 | tb.gain_gain[15:0] 29 | tb.gain_in_data[23:0] 30 | tb.gain.mul_a[15:0] 31 | tb.gain.mul_b[15:0] 32 | tb.gain.mul_out[31:0] 33 | @28 34 | tb.gain_out_addr[1:0] 35 | @22 36 | tb.gain_out_data[15:0] 37 | @28 38 | tb.gain_out_we 39 | @22 40 | tb.out_0[15:0] 41 | tb.out_1[15:0] 42 | tb.out_2[15:0] 43 | tb.out_3[15:0] 44 | [pattern_trace] 1 45 | [pattern_trace] 0 46 | -------------------------------------------------------------------------------- /dsp/dma.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "dma.h" 5 | 6 | #define ADDR_DMA ((uint32_t volatile*) 0x65000000) 7 | 8 | #define DMA_ADDR 0 9 | #define DMA_STEP 1 10 | #define DMA_CYCLES 2 11 | #define DMA_BLOCKS 3 12 | #define DMA_START 4 13 | #define DMA_STOP 5 14 | #define DMA_STATUS 6 15 | #define DMA_MATCH 7 16 | 17 | uint32_t dma_get_status() 18 | { 19 | return ADDR_DMA[DMA_STATUS]; 20 | } 21 | 22 | void dma_set_addr(void *addr) 23 | { 24 | ADDR_DMA[DMA_ADDR] = (uint32_t) addr; 25 | } 26 | 27 | void dma_set_match(void *addr) 28 | { 29 | ADDR_DMA[DMA_MATCH] = (uint32_t) addr; 30 | } 31 | 32 | void dma_set_step(uint32_t v) 33 | { 34 | ADDR_DMA[DMA_STEP] = v; 35 | } 36 | 37 | void dma_set_cycles(uint32_t v) 38 | { 39 | ADDR_DMA[DMA_CYCLES] = v; 40 | } 41 | 42 | void dma_set_blocks(uint32_t v) 43 | { 44 | ADDR_DMA[DMA_BLOCKS] = v; 45 | } 46 | 47 | /* 48 | * 49 | */ 50 | 51 | void dma_start(bool repeat) 52 | { 53 | ADDR_DMA[DMA_START] = repeat; 54 | } 55 | 56 | void dma_stop() 57 | { 58 | ADDR_DMA[DMA_STOP] = 1; 59 | } 60 | 61 | // FIN 62 | -------------------------------------------------------------------------------- /dsp/i2s_clock_tb.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Mon Aug 17 10:35:46 2020 4 | [*] 5 | [dumpfile] "/home/dave/Desktop/git/fpga/dsp/dsp.vcd" 6 | [dumpfile_mtime] "Mon Aug 17 10:35:38 2020" 7 | [dumpfile_size] 590861 8 | [savefile] "/home/dave/Desktop/git/fpga/dsp/i2s_clock_tb.gtkw" 9 | [timestart] 376340000 10 | [size] 1617 696 11 | [pos] -1 -1 12 | *-21.647114 357000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [treeopen] tb.i2s_dual. 15 | [sst_width] 196 16 | [signals_width] 198 17 | [sst_expanded] 1 18 | [sst_vpaned_height] 187 19 | @28 20 | tb.i2s_dual.ck 21 | tb.ext_rst 22 | tb.i2s_dual.rst 23 | tb.i2s_dual.ext_sck 24 | tb.i2s_dual.ext_ws 25 | tb.i2s_dual.i2s_detect.ws_0 26 | @22 27 | tb.i2s_dual.i2s_detect.ext_frame_posn[5:0] 28 | @28 29 | tb.i2s_dual.i2s_detect.has_64_bits 30 | @29 31 | tb.i2s_dual.i2s_detect.had_64_bits 32 | @28 33 | tb.i2s_dual.i2s_detect.sof 34 | tb.i2s_dual.i2s_detect.ext_okay 35 | tb.i2s_dual.i2s_detect.local_sof 36 | tb.i2s_dual.i2s_detect.frames[1:0] 37 | tb.i2s_dual.local_sck 38 | tb.external 39 | tb.i2s_dual.sck 40 | tb.i2s_dual.ws 41 | [pattern_trace] 1 42 | [pattern_trace] 0 43 | -------------------------------------------------------------------------------- /dsp/i2s_tx.v: -------------------------------------------------------------------------------- 1 | 2 | module i2s_tx 3 | #(parameter CLOCKS=64) 4 | (input wire ck, 5 | input wire en, 6 | input wire [5:0] frame_posn, 7 | input wire [15:0] left, 8 | input wire [15:0] right, 9 | output reg sd // data out 10 | ); 11 | 12 | reg [15:0] shift = 0; 13 | wire [5:0] MASK; 14 | wire [5:0] midpoint; 15 | wire [5:0] frame; 16 | 17 | generate 18 | if (CLOCKS==64) begin 19 | assign MASK = 6'b111111; 20 | assign midpoint = 32; 21 | end 22 | if (CLOCKS==32) begin 23 | assign MASK = 6'b011111; 24 | assign midpoint = 16; 25 | end 26 | endgenerate 27 | 28 | //assign MASK = 6'b011111; // 6'((1 << $clog2(CLOCKS)) - 1); 29 | assign frame = frame_posn & MASK; 30 | 31 | always @(posedge ck) begin 32 | 33 | if (en) begin 34 | sd <= shift[15]; 35 | 36 | if (frame == 0) begin 37 | shift <= left; 38 | end else if (frame == midpoint) begin 39 | shift <= right; 40 | end else begin 41 | shift <= shift << 1; 42 | end 43 | 44 | end 45 | 46 | end 47 | 48 | endmodule 49 | 50 | -------------------------------------------------------------------------------- /dsp/dsp_tb.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Thu Jul 30 15:31:07 2020 4 | [*] 5 | [dumpfile] "(null)" 6 | [savefile] "/home/dave/Desktop/git/fpga/dsp/dsp_tb.gtkw" 7 | [timestart] 2817000 8 | [size] 1835 711 9 | [pos] -1 -1 10 | *-19.000000 4830000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 11 | [treeopen] tb. 12 | [treeopen] tb.engine. 13 | [treeopen] tb.engine.seq. 14 | [sst_width] 196 15 | [signals_width] 174 16 | [sst_expanded] 1 17 | [sst_vpaned_height] 194 18 | @28 19 | tb.engine.ck 20 | tb.engine.wb_rst 21 | tb.engine.ack 22 | tb.engine.wb_dbus_cyc 23 | @22 24 | tb.engine.wb_dbus_adr[31:0] 25 | tb.engine.wb_dbus_dat[31:0] 26 | tb.engine.wb_dbus_sel[3:0] 27 | @28 28 | tb.engine.wb_dbus_we 29 | @22 30 | tb.rd_data[31:0] 31 | @28 32 | tb.engine.status_ack 33 | @23 34 | tb.engine.control_reg[8:0] 35 | @28 36 | tb.engine.seq.done 37 | tb.engine.error 38 | @22 39 | tb.engine.rdt[31:0] 40 | tb.engine.seq.coef_addr[7:0] 41 | tb.engine.seq.coef_data[31:0] 42 | tb.engine.seq.op_code[4:0] 43 | tb.engine.seq.offset[7:0] 44 | @28 45 | tb.engine.seq.chan[2:0] 46 | @22 47 | tb.engine.seq.gain[15:0] 48 | tb.engine.seq.audio_raddr[10:0] 49 | tb.engine.seq.capture_out[31:0] 50 | tb.engine.audio_in.waddr[10:0] 51 | @28 52 | tb.engine.allow_audio_writes 53 | [pattern_trace] 1 54 | [pattern_trace] 0 55 | -------------------------------------------------------------------------------- /dsp/i2s_clock.v: -------------------------------------------------------------------------------- 1 | 2 | module i2s_clock 3 | # (parameter DIVIDER=12, BITS=$clog2(DIVIDER)) 4 | ( 5 | input wire ck, // system clock 6 | input wire rst, // system reset 7 | output reg en, // I2S enable 8 | output reg sck, // I2S clock 9 | output reg ws, // I2S WS 10 | output reg [5:0] frame_posn // 64 clock counter for complete L/R frame 11 | ); 12 | 13 | // Divide the system clock down 14 | reg [BITS:0] prescale = 0; 15 | 16 | // 64 clock counter for complete L/R frame 17 | initial begin 18 | frame_posn = 0; 19 | en = 0; 20 | ws = 0; 21 | sck = 0; 22 | end 23 | 24 | always @(posedge ck) begin 25 | 26 | if (rst) begin 27 | 28 | prescale <= 0; 29 | frame_posn <= 0; 30 | en <= 0; 31 | ws <= 0; 32 | sck <= 0; 33 | 34 | end else begin 35 | 36 | if (prescale == (DIVIDER-1)) begin 37 | prescale <= 0; 38 | frame_posn <= frame_posn + 1; 39 | en <= 1; 40 | end else begin 41 | prescale <= prescale + 1; 42 | en <= 0; 43 | end 44 | 45 | end 46 | 47 | sck <= (prescale >= (DIVIDER/2)) ? 1 : 0; 48 | ws <= (frame_posn >= 32) ? 1 : 0; 49 | 50 | end 51 | 52 | endmodule 53 | 54 | -------------------------------------------------------------------------------- /correlator/correlator.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Mon Jul 20 06:43:55 2020 4 | [*] 5 | [dumpfile] "/home/dave/Desktop/git/fpga/correlator/correlator.vcd" 6 | [dumpfile_mtime] "Mon Jul 20 06:43:40 2020" 7 | [dumpfile_size] 148120 8 | [savefile] "/home/dave/Desktop/git/fpga/correlator/correlator.gtkw" 9 | [timestart] 336000 10 | [size] 1908 649 11 | [pos] -1 -1 12 | *-18.000000 1470000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [treeopen] tb.mac. 15 | [sst_width] 196 16 | [signals_width] 134 17 | [sst_expanded] 1 18 | [sst_vpaned_height] 173 19 | @28 20 | tb.ck 21 | tb.rst 22 | tb.clr 23 | tb.start 24 | tb.fetch_done 25 | tb.fetching 26 | @22 27 | tb.raddr_x[7:0] 28 | @28 29 | tb.req 30 | tb.acc_en 31 | @22 32 | tb.data_x[15:0] 33 | tb.data_y[15:0] 34 | tb.mac.ux[15:0] 35 | tb.mac.uy[15:0] 36 | tb.mac.mul_xy[31:0] 37 | @28 38 | tb.mac.acc_add 39 | tb.mac.acc_en 40 | tb.mac.clr 41 | tb.mac.acc_rst 42 | @22 43 | tb.acc_out[39:0] 44 | @28 45 | tb.mac.en 46 | tb.mac.req 47 | @29 48 | tb.acc_done 49 | @22 50 | tb.audio[15:0] 51 | @c00022 52 | tb.shifter.shift[4:0] 53 | @28 54 | (0)tb.shifter.shift[4:0] 55 | (1)tb.shifter.shift[4:0] 56 | (2)tb.shifter.shift[4:0] 57 | (3)tb.shifter.shift[4:0] 58 | (4)tb.shifter.shift[4:0] 59 | @1401200 60 | -group_end 61 | [pattern_trace] 1 62 | [pattern_trace] 0 63 | -------------------------------------------------------------------------------- /dsp/icebreaker_sections.lds: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | ROM (xr) : ORIGIN = 0x00100000, LENGTH = 0x20000 4 | RAM (rw) : ORIGIN = 0x00000000, LENGTH = 0x20000 5 | } 6 | SECTIONS { 7 | .text : 8 | { 9 | . = ALIGN(4); 10 | _stext = .; 11 | *(.text) 12 | *(.text*) 13 | *(.eh_frame) 14 | . = ALIGN(4); 15 | _etext = .; 16 | _sidata = _etext; 17 | } >ROM 18 | .data : AT ( _sidata ) 19 | { 20 | . = ALIGN(4); 21 | _sdata = .; 22 | _ram_start = .; 23 | . = ALIGN(4); 24 | *(.data) 25 | *(.data*) 26 | *(.sdata) 27 | *(.sdata*) 28 | *(.rodata) 29 | *(.rodata*) 30 | *(.srodata) 31 | *(.srodata*) 32 | . = ALIGN(4); 33 | _edata = .; 34 | } >RAM 35 | .bss : 36 | { 37 | . = ALIGN(4); 38 | _sbss = .; 39 | *(.bss) 40 | *(.bss*) 41 | *(.sbss) 42 | *(.sbss*) 43 | *(COMMON) 44 | . = ALIGN(4); 45 | _ebss = .; 46 | } >RAM 47 | 48 | /* Specify the stack size */ 49 | _stack_size = 0x1000; 50 | _estack = ORIGIN(RAM) + LENGTH(RAM); 51 | _sstack = _estack - _stack_size; 52 | 53 | /* The heap is everything else */ 54 | .heap : 55 | { 56 | . = ALIGN(4); 57 | _sheap = .; 58 | _eheap = _sstack; 59 | } >RAM 60 | 61 | } 62 | -------------------------------------------------------------------------------- /orangecrab/cpu_sections.lds: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | ROM (xr) : ORIGIN = 0x00100000, LENGTH = 0x20000 4 | RAM (rw) : ORIGIN = 0x00000000, LENGTH = 0x20000 5 | } 6 | SECTIONS { 7 | .text : 8 | { 9 | . = ALIGN(4); 10 | _stext = .; 11 | *(.text) 12 | *(.text*) 13 | *(.eh_frame) 14 | . = ALIGN(4); 15 | _etext = .; 16 | _sidata = _etext; 17 | } >ROM 18 | .data : AT ( _sidata ) 19 | { 20 | . = ALIGN(4); 21 | _sdata = .; 22 | _ram_start = .; 23 | . = ALIGN(4); 24 | *(.data) 25 | *(.data*) 26 | *(.sdata) 27 | *(.sdata*) 28 | *(.rodata) 29 | *(.rodata*) 30 | *(.srodata) 31 | *(.srodata*) 32 | . = ALIGN(4); 33 | _edata = .; 34 | } >RAM 35 | .bss : 36 | { 37 | . = ALIGN(4); 38 | _sbss = .; 39 | *(.bss) 40 | *(.bss*) 41 | *(.sbss) 42 | *(.sbss*) 43 | *(COMMON) 44 | . = ALIGN(4); 45 | _ebss = .; 46 | } >RAM 47 | 48 | /* Specify the stack size */ 49 | _stack_size = 0x1000; 50 | _estack = ORIGIN(RAM) + LENGTH(RAM); 51 | _sstack = _estack - _stack_size; 52 | 53 | /* The heap is everything else */ 54 | .heap : 55 | { 56 | . = ALIGN(4); 57 | _sheap = .; 58 | _eheap = _sstack; 59 | } >RAM 60 | 61 | } 62 | -------------------------------------------------------------------------------- /orangecrab/orangecrab_r02.lpf: -------------------------------------------------------------------------------- 1 | 2 | LOCATE COMP "clk" SITE "A9"; 3 | IOBUF PORT "clk" PULLMODE=NONE IO_TYPE=LVCMOS33; 4 | FREQUENCY PORT "clk" 48 MHZ; 5 | 6 | # 3-colour LED 7 | LOCATE COMP "r" SITE "K4"; 8 | LOCATE COMP "g" SITE "M3"; 9 | LOCATE COMP "b" SITE "J3"; 10 | 11 | LOCATE COMP "p0" SITE "N17"; 12 | LOCATE COMP "p1" SITE "M18"; 13 | LOCATE COMP "p5" SITE "B10"; 14 | LOCATE COMP "p6" SITE "B9"; 15 | LOCATE COMP "p9" SITE "C8"; 16 | LOCATE COMP "p10" SITE "B8"; 17 | LOCATE COMP "p11" SITE "A8"; 18 | LOCATE COMP "p12" SITE "H2"; 19 | LOCATE COMP "p13" SITE "J2"; 20 | 21 | LOCATE COMP "a0" SITE "L4"; 22 | LOCATE COMP "a1" SITE "N3"; 23 | LOCATE COMP "a2" SITE "N4"; 24 | LOCATE COMP "a3" SITE "H4"; 25 | LOCATE COMP "a4" SITE "G4"; 26 | LOCATE COMP "a5" SITE "T17"; 27 | 28 | LOCATE COMP "reset" SITE "T15"; 29 | 30 | IOBUF PORT "r" IO_TYPE=LVCMOS33; 31 | IOBUF PORT "g" IO_TYPE=LVCMOS33; 32 | IOBUF PORT "b" IO_TYPE=LVCMOS33; 33 | 34 | IOBUF PORT "p0" IO_TYPE=LVCMOS33; 35 | IOBUF PORT "p1" IO_TYPE=LVCMOS33; 36 | IOBUF PORT "p5" IO_TYPE=LVCMOS33; 37 | IOBUF PORT "p6" IO_TYPE=LVCMOS33; 38 | IOBUF PORT "p9" IO_TYPE=LVCMOS33; 39 | IOBUF PORT "p10" IO_TYPE=LVCMOS33; 40 | IOBUF PORT "p11" IO_TYPE=LVCMOS33; 41 | IOBUF PORT "p12" IO_TYPE=LVCMOS33; 42 | IOBUF PORT "p13" IO_TYPE=LVCMOS33; 43 | 44 | IOBUF PORT "reset" IO_TYPE=LVCMOS33; 45 | 46 | LOCATE COMP "btn" SITE "J17"; # BTN_PWRn (inverted logic) 47 | IOBUF PORT "btn" IO_TYPE=SSTL135_I; 48 | 49 | -------------------------------------------------------------------------------- /dsp/spl_tb.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Wed Aug 5 07:53:11 2020 4 | [*] 5 | [dumpfile] "/home/dave/Desktop/git/fpga/dsp/dsp.vcd" 6 | [dumpfile_mtime] "Wed Aug 5 07:50:44 2020" 7 | [dumpfile_size] 3282682 8 | [savefile] "/home/dave/Desktop/git/fpga/dsp/spl_tb.gtkw" 9 | [timestart] 0 10 | [size] 1641 656 11 | [pos] -1 -1 12 | *-18.000000 317000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [sst_width] 196 15 | [signals_width] 142 16 | [sst_expanded] 1 17 | [sst_vpaned_height] 172 18 | @28 19 | tb.ck 20 | @22 21 | tb.spl.in[15:0] 22 | @c00022 23 | tb.spl.uint[15:0] 24 | @28 25 | (0)tb.spl.uint[15:0] 26 | (1)tb.spl.uint[15:0] 27 | (2)tb.spl.uint[15:0] 28 | (3)tb.spl.uint[15:0] 29 | (4)tb.spl.uint[15:0] 30 | (5)tb.spl.uint[15:0] 31 | (6)tb.spl.uint[15:0] 32 | (7)tb.spl.uint[15:0] 33 | (8)tb.spl.uint[15:0] 34 | (9)tb.spl.uint[15:0] 35 | (10)tb.spl.uint[15:0] 36 | (11)tb.spl.uint[15:0] 37 | (12)tb.spl.uint[15:0] 38 | (13)tb.spl.uint[15:0] 39 | (14)tb.spl.uint[15:0] 40 | (15)tb.spl.uint[15:0] 41 | @1401200 42 | -group_end 43 | @22 44 | tb.spl.out[15:0] 45 | @28 46 | tb.spl.decay_en 47 | tb.spl.peak_en 48 | @200 49 | - 50 | @28 51 | tb.spl_xfer.ck 52 | tb.spl_xfer.rst 53 | tb.spl_xfer.run 54 | tb.spl_xfer.addr[2:0] 55 | @22 56 | tb.spl_xfer.data_in[15:0] 57 | tb.spl_xfer.data_out[15:0] 58 | @29 59 | tb.spl_xfer.busy 60 | @28 61 | tb.spl_xfer.done 62 | tb.spl_xfer.we 63 | [pattern_trace] 1 64 | [pattern_trace] 0 65 | -------------------------------------------------------------------------------- /dsp/shifter_tb.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Wed Aug 19 14:26:16 2020 4 | [*] 5 | [dumpfile] "/home/dave/Desktop/git/fpga/dsp/dsp.vcd" 6 | [dumpfile_mtime] "Wed Aug 19 14:20:36 2020" 7 | [dumpfile_size] 3294247 8 | [savefile] "/home/dave/Desktop/git/fpga/dsp/shifter_tb.gtkw" 9 | [timestart] 17200000 10 | [size] 1680 610 11 | [pos] -1 -1 12 | *-21.000000 126000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [treeopen] tb.spl. 15 | [sst_width] 196 16 | [signals_width] 126 17 | [sst_expanded] 1 18 | [sst_vpaned_height] 157 19 | @28 20 | tb.ck 21 | @22 22 | tb.spl.in[15:0] 23 | @28 24 | tb.spl.peak_en 25 | tb.spl.decay_en 26 | @22 27 | tb.out[15:0] 28 | @28 29 | tb.level.ck 30 | @22 31 | tb.level.in[15:0] 32 | @28 33 | tb.level.ck 34 | tb.level.en 35 | @22 36 | tb.level.in[15:0] 37 | @c00022 38 | tb.level.shift[15:0] 39 | @28 40 | (0)tb.level.shift[15:0] 41 | (1)tb.level.shift[15:0] 42 | (2)tb.level.shift[15:0] 43 | (3)tb.level.shift[15:0] 44 | (4)tb.level.shift[15:0] 45 | (5)tb.level.shift[15:0] 46 | (6)tb.level.shift[15:0] 47 | (7)tb.level.shift[15:0] 48 | (8)tb.level.shift[15:0] 49 | (9)tb.level.shift[15:0] 50 | (10)tb.level.shift[15:0] 51 | (11)tb.level.shift[15:0] 52 | (12)tb.level.shift[15:0] 53 | (13)tb.level.shift[15:0] 54 | (14)tb.level.shift[15:0] 55 | (15)tb.level.shift[15:0] 56 | @1401200 57 | -group_end 58 | @28 59 | tb.level.ready 60 | @23 61 | tb.level.level[3:0] 62 | [pattern_trace] 1 63 | [pattern_trace] 0 64 | -------------------------------------------------------------------------------- /wavegen/wavegen.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Fri Jul 17 14:37:27 2020 4 | [*] 5 | [dumpfile] "/home/dave/Desktop/git/fpga/wavegen/wavegen.vcd" 6 | [dumpfile_mtime] "Fri Jul 17 14:37:14 2020" 7 | [dumpfile_size] 465890 8 | [savefile] "/home/dave/Desktop/git/fpga/wavegen/wavegen.gtkw" 9 | [timestart] 191619000 10 | [size] 1856 635 11 | [pos] -1 -1 12 | *-19.026495 193578000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [treeopen] tb.top. 15 | [sst_width] 196 16 | [signals_width] 150 17 | [sst_expanded] 1 18 | [sst_vpaned_height] 168 19 | @28 20 | tb.top.CLK 21 | tb.top.D0 22 | tb.top.D1 23 | tb.top.D2 24 | tb.top.D3 25 | tb.top.D4 26 | tb.top.D5 27 | tb.top.D6 28 | @200 29 | - 30 | @28 31 | tb.top.i2sck.ck 32 | tb.top.i2sck.en 33 | @22 34 | tb.top.i2sck.frame_posn[5:0] 35 | @28 36 | tb.top.i2sck.sck 37 | tb.top.i2sck.ws 38 | @200 39 | - 40 | @28 41 | tb.top.sec.ck 42 | tb.top.sec.en 43 | @22 44 | tb.top.sec.frame_posn[5:0] 45 | tb.top.sec.match[4:0] 46 | @c00022 47 | tb.top.sec.prescale[4:0] 48 | @28 49 | (0)tb.top.sec.prescale[4:0] 50 | (1)tb.top.sec.prescale[4:0] 51 | (2)tb.top.sec.prescale[4:0] 52 | (3)tb.top.sec.prescale[4:0] 53 | (4)tb.top.sec.prescale[4:0] 54 | @1401200 55 | -group_end 56 | @28 57 | tb.top.sec.sck 58 | tb.top.sec.sck0 59 | tb.top.sec.prev_sck 60 | @29 61 | tb.top.sec.ws 62 | @28 63 | tb.top.sec.ws0 64 | tb.top.sec.prev_ws 65 | tb.top.sec.start_frame 66 | tb.top.sec.start_sck 67 | [pattern_trace] 1 68 | [pattern_trace] 0 69 | -------------------------------------------------------------------------------- /dsp/i2s_rx.v: -------------------------------------------------------------------------------- 1 | 2 | module i2s_rx 3 | #(parameter BITS=16, CLOCKS=64) 4 | (input wire ck, 5 | input wire sample, // sample the data in here 6 | input wire [5:0] frame_posn, 7 | input wire sd, // I2S data in 8 | output reg [BITS-1:0] left, 9 | output reg [BITS-1:0] right 10 | ); 11 | 12 | // The 24-bit data from the mic, starts at t=2 (I2S spec) 13 | 14 | initial left = 0; 15 | initial right = 0; 16 | 17 | // shift the microphone data into N-bit shift register. 18 | reg [BITS-1:0] shift = 0; 19 | 20 | wire [5:0] EOW_LEFT; 21 | wire [5:0] EOW_RIGHT; 22 | wire [5:0] MASK; 23 | wire [5:0] frame; 24 | wire [5:0] midpoint; 25 | 26 | generate 27 | if (CLOCKS==64) begin 28 | assign MASK = 6'b111111; 29 | assign midpoint = 32; 30 | end 31 | if (CLOCKS==32) begin 32 | assign MASK = 6'b011111; 33 | assign midpoint = 16; 34 | end 35 | endgenerate 36 | 37 | assign EOW_LEFT = MASK & (1 + BITS); 38 | assign EOW_RIGHT = MASK & (1 + BITS + midpoint); 39 | assign frame = frame_posn & MASK; 40 | 41 | always @(posedge ck) begin 42 | 43 | if (sample) begin 44 | 45 | shift <= { shift[BITS-2:0], sd }; 46 | 47 | if (frame == EOW_LEFT) begin 48 | left <= shift; 49 | end 50 | 51 | if (frame == EOW_RIGHT) begin 52 | right <= shift; 53 | end 54 | 55 | end 56 | 57 | end 58 | 59 | endmodule 60 | 61 | -------------------------------------------------------------------------------- /dsp/i2s_rx_tb.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Mon Nov 2 16:50:32 2020 4 | [*] 5 | [dumpfile] "/home/dave/Desktop/git/fpga/dsp/dsp.vcd" 6 | [dumpfile_mtime] "Mon Nov 2 16:49:40 2020" 7 | [dumpfile_size] 367714 8 | [savefile] "/home/dave/Desktop/git/fpga/dsp/i2s_rx_tb.gtkw" 9 | [timestart] 0 10 | [size] 1725 605 11 | [pos] -106 231 12 | *-26.198023 24240000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [sst_width] 196 15 | [signals_width] 166 16 | [sst_expanded] 1 17 | [sst_vpaned_height] 157 18 | @28 19 | tb.ck 20 | tb.rst 21 | @22 22 | tb.i2s_rx.frame_posn[5:0] 23 | @28 24 | tb.i2s_rx.sd 25 | tb.i2s_rx.sample 26 | @c00022 27 | tb.i2s_rx.shift[23:0] 28 | @28 29 | (0)tb.i2s_rx.shift[23:0] 30 | (1)tb.i2s_rx.shift[23:0] 31 | (2)tb.i2s_rx.shift[23:0] 32 | (3)tb.i2s_rx.shift[23:0] 33 | (4)tb.i2s_rx.shift[23:0] 34 | (5)tb.i2s_rx.shift[23:0] 35 | (6)tb.i2s_rx.shift[23:0] 36 | (7)tb.i2s_rx.shift[23:0] 37 | (8)tb.i2s_rx.shift[23:0] 38 | (9)tb.i2s_rx.shift[23:0] 39 | (10)tb.i2s_rx.shift[23:0] 40 | (11)tb.i2s_rx.shift[23:0] 41 | (12)tb.i2s_rx.shift[23:0] 42 | (13)tb.i2s_rx.shift[23:0] 43 | (14)tb.i2s_rx.shift[23:0] 44 | (15)tb.i2s_rx.shift[23:0] 45 | (16)tb.i2s_rx.shift[23:0] 46 | (17)tb.i2s_rx.shift[23:0] 47 | (18)tb.i2s_rx.shift[23:0] 48 | (19)tb.i2s_rx.shift[23:0] 49 | (20)tb.i2s_rx.shift[23:0] 50 | (21)tb.i2s_rx.shift[23:0] 51 | (22)tb.i2s_rx.shift[23:0] 52 | (23)tb.i2s_rx.shift[23:0] 53 | @1401200 54 | -group_end 55 | @22 56 | tb.i2s_rx.left[23:0] 57 | tb.i2s_rx.right[23:0] 58 | @200 59 | - 60 | @22 61 | tb.left_32[15:0] 62 | tb.right_32[15:0] 63 | tb.tx_shift_32[31:0] 64 | @28 65 | tb.sd_32 66 | tb.tx_hw.sd 67 | @29 68 | tb.tx_hw_32.sd 69 | [pattern_trace] 1 70 | [pattern_trace] 0 71 | -------------------------------------------------------------------------------- /icebreaker.pcf: -------------------------------------------------------------------------------- 1 | # 12 MHz clock 2 | set_io -nowarn CLK 35 3 | 4 | # RS232 5 | set_io -nowarn RX 6 6 | set_io -nowarn TX 9 7 | 8 | # LEDs and Button 9 | set_io -nowarn BTN_N 10 10 | set_io -nowarn LEDR_N 11 11 | set_io -nowarn LEDG_N 37 12 | 13 | # RGB LED Driver 14 | set_io -nowarn LED_RED_N 39 15 | set_io -nowarn LED_GRN_N 40 16 | set_io -nowarn LED_BLU_N 41 17 | 18 | # SPI Flash 19 | set_io -nowarn FLASH_SCK 15 20 | set_io -nowarn FLASH_SSB 16 21 | set_io -nowarn FLASH_IO0 14 22 | set_io -nowarn FLASH_IO1 17 23 | set_io -nowarn FLASH_IO2 12 24 | set_io -nowarn FLASH_IO3 13 25 | 26 | # PMOD 1A 27 | set_io -nowarn P1A1 4 28 | set_io -nowarn P1A2 2 29 | set_io -nowarn P1A3 47 30 | set_io -nowarn P1A4 45 31 | set_io -nowarn P1A7 3 32 | set_io -nowarn P1A8 48 33 | set_io -nowarn P1A9 46 34 | set_io -nowarn P1A10 44 35 | 36 | # PMOD 1B 37 | set_io -nowarn P1B1 43 38 | set_io -nowarn P1B2 38 39 | set_io -nowarn P1B3 34 40 | set_io -nowarn P1B4 31 41 | set_io -nowarn P1B7 42 42 | set_io -nowarn P1B8 36 43 | set_io -nowarn P1B9 32 44 | set_io -nowarn P1B10 28 45 | 46 | # PMOD 2 47 | set_io -nowarn P2_1 27 48 | set_io -nowarn P2_2 25 49 | set_io -nowarn P2_3 21 50 | set_io -nowarn P2_4 19 51 | set_io -nowarn P2_7 26 52 | set_io -nowarn P2_8 23 53 | set_io -nowarn P2_9 20 54 | set_io -nowarn P2_10 18 55 | 56 | # LEDs and Buttons (PMOD 2) 57 | set_io -nowarn LED1 26 58 | set_io -nowarn LED2 27 59 | set_io -nowarn LED3 25 60 | set_io -nowarn LED4 23 61 | set_io -nowarn LED5 21 62 | set_io -nowarn BTN1 20 63 | set_io -nowarn BTN2 19 64 | set_io -nowarn BTN3 18 65 | -------------------------------------------------------------------------------- /correlator/mac.v: -------------------------------------------------------------------------------- 1 | 2 | module mac ( 3 | input wire ck, 4 | input wire en, 5 | input wire clr, 6 | input wire req, 7 | input wire [15:0] x, 8 | input wire [15:0] y, 9 | output wire [39:0] out, 10 | output reg done 11 | ); 12 | 13 | wire neg_x; 14 | assign neg_x = x[15]; 15 | wire neg_y; 16 | assign neg_y = y[15]; 17 | 18 | wire [15:0] ux; 19 | wire [15:0] uy; 20 | 21 | // pipeline t=1 : conditionally invert / latch the input data 22 | 23 | twos_complement #(.WIDTH(16)) x2c(.ck(ck), .inv(neg_x), .in(x), .out(ux)); 24 | twos_complement #(.WIDTH(16)) y2c(.ck(ck), .inv(neg_y), .in(y), .out(uy)); 25 | 26 | // pipeline t=2 : multiply the unsigned x & y values 27 | 28 | wire [31:0] mul_xy; 29 | multiplier mul(.ck(ck), .a(ux), .b(uy), .out(mul_xy)); 30 | 31 | // pipeline t=3 : accumulate the data 32 | 33 | wire acc_en, acc_rst; 34 | 35 | pipe #(.LENGTH(2)) p_en (.ck(ck), .rst(1'b1), .in(en), .out(acc_en)); 36 | pipe #(.LENGTH(2)) p_clr(.ck(ck), .rst(1'b1), .in(clr), .out(acc_rst)); 37 | 38 | reg acc_add; 39 | 40 | // add / sub depending on the signs of the x/y inputs 41 | reg add_0 = 0; 42 | always @(posedge ck) begin 43 | add_0 <= !(neg_x ^ neg_y); 44 | acc_add <= add_0; 45 | end 46 | 47 | accumulator #(.OUT_W(40)) 48 | acc(.ck(ck), .en(acc_en), .rst(acc_rst), .add(acc_add), .in(mul_xy), .out(out)); 49 | 50 | // pipeline t=4 : data ready 51 | 52 | wire req_t1; 53 | pipe #(.LENGTH(1)) p_req(.ck(ck), .rst(1'b1), .in(req), .out(req_t1)); 54 | 55 | initial done = 0; 56 | 57 | always @(posedge ck) begin 58 | if (clr || req || req_t1) 59 | done <= 0; 60 | else 61 | done <= 1; 62 | end 63 | 64 | endmodule 65 | 66 | 67 | -------------------------------------------------------------------------------- /dsp/audio_gen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # https://old.reddit.com/r/Python/comments/6g9ccc/it_is_ridiculously_easy_to_generate_any_audio/ 4 | 5 | import argparse 6 | import sys 7 | import struct 8 | import wave 9 | 10 | SFREQ = 31250 11 | SAMPLE_LEN = SFREQ * 30 # 30 seconds of audio 12 | 13 | ofile = wave.open('tick.wav', 'w') 14 | 15 | ofile.setparams((2, 2, SFREQ, 0, 'NONE', 'not compressed')) 16 | 17 | parser = argparse.ArgumentParser(description='create wav file from input') 18 | parser.add_argument("--tick", action="store_true", help="generate tick file") 19 | parser.add_argument("--binary", action="store_true", help="read binary file") 20 | parser.add_argument("--text", action="store_true", help="read text file") 21 | parser.add_argument("filename", nargs='?', help="read text file") 22 | 23 | args = parser.parse_args() 24 | 25 | values = [] 26 | 27 | if args.text: 28 | 29 | with open(args.filename, 'r') as f: 30 | 31 | for line in f: 32 | value = int(line, 16) 33 | packed_value = struct.pack('H', value) 34 | values.append(packed_value) 35 | 36 | if args.binary: 37 | 38 | with open(args.filename, 'rb') as f: 39 | 40 | while True: 41 | # add to left and right 42 | value = f.read(2) 43 | if not value: 44 | break 45 | values.append(value) 46 | 47 | if args.tick: 48 | 49 | for i in range(0, SAMPLE_LEN): 50 | if (i % (2 * 1024)): 51 | value = 32000 # periodic impulse 52 | else: 53 | value = 0 54 | packed_value = struct.pack('h', value) 55 | # add to left and right 56 | values.append(packed_value) 57 | values.append(packed_value) 58 | 59 | value_str = b''.join(values) 60 | ofile.writeframes(value_str) 61 | 62 | ofile.close() 63 | 64 | # FIN 65 | -------------------------------------------------------------------------------- /dsp/spl.v: -------------------------------------------------------------------------------- 1 | 2 | module spl 3 | #(parameter WIDTH=16) 4 | ( 5 | input wire ck, 6 | input wire rst, 7 | input wire peak_en, 8 | input wire decay_en, 9 | input wire [(WIDTH-1):0] in, 10 | output wire [(WIDTH-1):0] out 11 | ); 12 | 13 | wire [(WIDTH-1):0] uint; 14 | 15 | twos_complement #(.WIDTH(WIDTH)) 16 | twos_complement ( 17 | .ck(ck), 18 | .inv(in[WIDTH-1]), 19 | .in(in), 20 | .out(uint) 21 | ); 22 | 23 | reg [(WIDTH-1):0] max = 0; 24 | 25 | always @(posedge ck) begin 26 | 27 | if (rst) begin 28 | max <= 0; 29 | end 30 | 31 | if (peak_en & (uint >= max)) begin 32 | max <= uint; 33 | end 34 | 35 | if (decay_en & (max > 0)) begin 36 | max <= max - 1; 37 | end 38 | 39 | end 40 | 41 | assign out = max; 42 | 43 | endmodule 44 | 45 | /* 46 | * 47 | */ 48 | 49 | module level 50 | #(parameter IN_W=24, BITS = $clog2(IN_W)) 51 | ( 52 | input wire ck, 53 | input wire en, 54 | input wire [IN_W-1:0] in, 55 | output wire [BITS-1:0] level, 56 | output wire ready 57 | ); 58 | 59 | reg [IN_W-1:0] shift = 0; 60 | 61 | reg [BITS-1:0] bits = 0; 62 | reg busy = 0; 63 | 64 | always @(posedge ck) begin 65 | if (en) begin 66 | shift <= in; 67 | bits <= 0; 68 | busy <= 1; 69 | end 70 | 71 | if (busy && !en) begin 72 | if (shift[IN_W-1] != shift[IN_W-2]) begin 73 | // top bits differ, done 74 | busy <= 0; 75 | end else begin 76 | bits <= bits + 1; 77 | shift <= { shift[IN_W-1], shift[IN_W-2:0], !shift[IN_W-1] }; 78 | end 79 | end 80 | end 81 | 82 | assign level = bits; 83 | assign ready = !busy; 84 | 85 | endmodule 86 | 87 | // FIN 88 | -------------------------------------------------------------------------------- /main.mk: -------------------------------------------------------------------------------- 1 | 2 | all: $(PROJ).rpt $(PROJ).bin 3 | 4 | %.blif: %.v $(ADD_SRC) $(ADD_DEPS) 5 | yosys -ql $*.log $(if $(USE_ARACHNEPNR),-DUSE_ARACHNEPNR) -p 'synth_ice40 -top top -blif $@' $< $(ADD_SRC) 6 | 7 | VERILATOR_SRC?=$(ADD_SRC) 8 | 9 | %.json: %.v $(ADD_SRC) $(ADD_DEPS) 10 | verilator --top-module top $(ADD_VERILATOR) $< $(VERILATOR_SRC) /usr/share/yosys/ice40/cells_sim.v --lint-only -Wall 11 | yosys -ql $*.log $(MORE_YOSYS) $(if $(USE_ARACHNEPNR),-DUSE_ARACHNEPNR) -p 'synth_ice40 $(ADD_YOSYS) -top top -json $@' $< $(ADD_SRC) 12 | 13 | ifeq ($(USE_ARACHNEPNR),) 14 | %.asc: $(PIN_DEF) %.json 15 | nextpnr-ice40 --$(DEVICE) $(if $(PACKAGE),--package $(PACKAGE)) $(if $(FREQ),--freq $(FREQ)) --json $(filter-out $<,$^) --pcf $< --asc $@ 16 | else 17 | %.asc: $(PIN_DEF) %.blif 18 | arachne-pnr -d $(subst up,,$(subst hx,,$(subst lp,,$(DEVICE)))) $(if $(PACKAGE),-P $(PACKAGE)) -o $@ -p $^ 19 | endif 20 | 21 | 22 | %.bin: %.asc 23 | icepack $< $@ 24 | 25 | %.rpt: %.asc 26 | icetime $(if $(FREQ),-c $(FREQ)) -d $(DEVICE) -mtr $@ $< 27 | 28 | %_tb: %_tb.v %.v $(TB_DEPS) 29 | verilator --top-module $(PROJ) $(ADD_VERILATOR) $(TB_VERILATOR) $(TB_SRC) $(PROJ).v --lint-only -Wall 30 | iverilog -DSIMULATION $(MORE_YOSYS) -g2012 $(ADD_IVERILOG) -o $@ $(TB_SRC) $@.v $(ADD_TB_IVERILOG) 31 | ./$@ 32 | #gtkwave $(PROJ).vcd $@.gtkw & 33 | 34 | %_tb.vcd: %_tb 35 | vvp -N $< +vcd=$@ 36 | 37 | %_syn.v: %.blif 38 | yosys -p 'read_blif -wideports $^; write_verilog $@' 39 | 40 | %_syntb: %_tb.v %_syn.v 41 | verilator --top-module top $< $(ADD_SRC) --lint-only -Wall -Wno-DECLFILENAME 42 | iverilog -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v` 43 | 44 | %_syntb.vcd: %_syntb 45 | vvp -N $< +vcd=$@ 46 | 47 | prog: $(PROJ).bin 48 | iceprog $< 49 | 50 | clean: 51 | rm -f $(PROJ).blif $(PROJ).asc $(PROJ).rpt $(PROJ).bin $(PROJ).json $(PROJ).log *.vvp *.vcd $(ADD_CLEAN) *~ 52 | 53 | .SECONDARY: 54 | .PHONY: all prog clean 55 | -------------------------------------------------------------------------------- /orangecrab/make.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import argparse 5 | 6 | from edalize import * 7 | 8 | if __name__ == '__main__': 9 | 10 | parser = argparse.ArgumentParser(description='run edalize') 11 | parser.add_argument('--lpf', dest='lpf') 12 | parser.add_argument('--tool', dest='tool') 13 | parser.add_argument('--project', dest='project') 14 | parser.add_argument('--top', dest='top', default='top') 15 | parser.add_argument('files', nargs='+') 16 | 17 | args = parser.parse_args() 18 | 19 | work_root = 'build' 20 | if not os.path.exists(work_root): 21 | os.makedirs(work_root) 22 | 23 | files = [] 24 | 25 | for fname in args.files: 26 | d = { 'name' : os.path.relpath(fname, work_root), 'file_type' : 'verilogSource' } 27 | files.append(d) 28 | 29 | if args.lpf: 30 | d = { 'name' : os.path.relpath(args.lpf, work_root), 'file_type' : 'LPF'} 31 | files.append(d) 32 | 33 | parameters = { 34 | #'clk_freq_hz' : {'datatype' : 'int', 'default' : 1000, 'paramtype' : 'vlogparam'}, 35 | #'vcd' : {'datatype' : 'bool', 'paramtype' : 'plusarg'} 36 | } 37 | 38 | tool = args.tool 39 | 40 | if not tool: 41 | raise Exception('no --tool specified (eg. icarus, yosys, trellis)') 42 | if not args.project: 43 | raise Exception('no --project name specified') 44 | 45 | edam = { 46 | 'files' : files, 47 | 'name' : args.project, 48 | 'parameters' : parameters, 49 | 'toplevel' : args.top, 50 | 'tool_options' : { 51 | 'yosys' : { 52 | 'arch' : 'ecp5', 53 | }, 54 | 'trellis' : { 55 | # For Orange Crab 56 | 'nextpnr_options' : [ '--25k', '--package', 'CSFBGA285' ], 57 | }, 58 | }, 59 | } 60 | 61 | backend = get_edatool(tool)(edam=edam, work_root=work_root) 62 | 63 | backend.configure() 64 | backend.build() 65 | 66 | args = { 67 | # TODO dunno 68 | #'vcd' : True, 69 | } 70 | 71 | backend.run(args) 72 | 73 | # FIN 74 | -------------------------------------------------------------------------------- /dsp/sk9822_tb.v: -------------------------------------------------------------------------------- 1 | 2 | 3 | `default_nettype none 4 | `timescale 1ns / 100ps 5 | 6 | module tb (); 7 | 8 | initial begin 9 | $dumpfile("dsp.vcd"); 10 | $dumpvars(0, tb); 11 | #500000 $finish; 12 | end 13 | 14 | reg ck = 0; 15 | 16 | always #42 ck <= !ck; 17 | 18 | wire rst; 19 | 20 | reset #(.LENGTH(4)) reset (.ck(ck), .rst_req(1'b0), .rst(rst)); 21 | 22 | wire wb_clk; 23 | assign wb_clk = ck; 24 | wire wb_rst; 25 | assign wb_rst = rst; 26 | 27 | reg wb_dbus_cyc = 0; 28 | reg wb_dbus_we = 0; 29 | reg [31:0] wb_dbus_adr = 32'hZ; 30 | reg [31:0] wb_dbus_dat = 32'hZ; 31 | 32 | wire ack; 33 | wire led_ck; 34 | wire led_data; 35 | 36 | sk9822_peripheral 37 | #(.ADDR(8'hab)) 38 | sk9822_peripheral( 39 | .wb_clk(wb_clk), 40 | .wb_rst(wb_rst), 41 | .wb_dbus_cyc(wb_dbus_cyc), 42 | .wb_dbus_we(wb_dbus_we), 43 | .wb_dbus_adr(wb_dbus_adr), 44 | .wb_dbus_dat(wb_dbus_dat), 45 | .ack(ack), 46 | .led_ck(led_ck), 47 | .led_data(led_data) 48 | ); 49 | 50 | task write(input [31:0] addr, input [31:0] data); 51 | 52 | begin 53 | wb_dbus_cyc <= 1; 54 | wb_dbus_adr <= addr; 55 | wb_dbus_dat <= data; 56 | wb_dbus_we <= 1; 57 | end 58 | 59 | endtask 60 | 61 | localparam ADDR = 32'hab00_0000; 62 | 63 | // respond to ACK 64 | always @(posedge wb_clk) begin 65 | if (ack) begin 66 | wb_dbus_cyc <= 0; 67 | wb_dbus_adr <= 32'hZ; 68 | wb_dbus_dat <= 32'hZ; 69 | wb_dbus_we <= 0; 70 | end 71 | end 72 | 73 | integer i; 74 | 75 | initial begin 76 | $display("start"); 77 | 78 | wait(!wb_rst); 79 | @(posedge wb_clk); 80 | @(posedge wb_clk); 81 | @(posedge wb_clk); 82 | @(posedge wb_clk); 83 | @(posedge wb_clk); 84 | 85 | for (i = 0; i < 16; i = i + 1) begin 86 | write(ADDR+(i*4), i + (i << 8) + (i << 16)); 87 | wait(ack); 88 | wait(!ack); 89 | @(posedge wb_clk); 90 | end 91 | 92 | $display("done"); 93 | //$finish; 94 | end 95 | 96 | endmodule 97 | 98 | 99 | -------------------------------------------------------------------------------- /dsp/icebreaker.v: -------------------------------------------------------------------------------- 1 | 2 | 3 | `default_nettype none 4 | 5 | /* 6 | * 7 | */ 8 | 9 | module top ( 10 | input wire CLK, 11 | output wire TX, 12 | 13 | // XIP Flash 14 | output wire FLASH_SCK, 15 | output wire FLASH_SSB, 16 | output wire FLASH_IO0, 17 | input wire FLASH_IO1, 18 | output wire FLASH_IO2, 19 | output wire FLASH_IO3, 20 | 21 | output wire P2_1, 22 | output wire P2_2, 23 | output wire P2_3, 24 | output wire P2_4, 25 | output wire P2_7, 26 | output wire P2_8, 27 | output wire P2_9, 28 | 29 | // Test pins 30 | input wire P1A1, 31 | input wire P1A2, 32 | output wire P1A3, 33 | output wire P1A4, 34 | 35 | // I2S Input 36 | output wire P1A7, 37 | output wire P1A8, 38 | input wire P1A9, 39 | input wire P1A10, 40 | 41 | // I2S Output 42 | output wire P1B1, 43 | output wire P1B2, 44 | output wire P1B3, 45 | output wire P1B4, 46 | 47 | input wire P1B7, 48 | input wire P1B8, 49 | output wire P1B9, 50 | output wire P1B10 51 | ); 52 | 53 | /* verilator lint_off UNUSED */ 54 | wire [7:0] test_out; 55 | /* verilator lint_on UNUSED */ 56 | 57 | assign P2_1 = test_out[0]; 58 | assign P2_2 = test_out[1]; 59 | assign P2_3 = test_out[2]; 60 | assign P2_4 = test_out[3]; 61 | assign P2_7 = test_out[4]; 62 | assign P2_8 = test_out[5]; 63 | assign P2_9 = test_out[6]; 64 | 65 | assign FLASH_IO2 = 1; 66 | assign FLASH_IO3 = 1; 67 | 68 | assign P1B4 = 0; 69 | 70 | dsp dsp( 71 | .ext_ck(CLK), 72 | 73 | .tx(TX), 74 | 75 | .spi_sck(FLASH_SCK), 76 | .spi_cs(FLASH_SSB), 77 | .spi_mosi(FLASH_IO0), 78 | .spi_miso(FLASH_IO1), 79 | 80 | // sk9822 LED drive 81 | .led_ck(P1A3), 82 | .led_data(P1A4), 83 | 84 | .sck(P1A7), 85 | .ws(P1A8), 86 | // Microphone inputs 87 | .sd_in0(P1A9), 88 | .sd_in1(P1A10), 89 | .sd_in2(P1A1), 90 | .sd_in3(P1A2), 91 | 92 | // Ext sync input 93 | .ext_sck(P1B7), 94 | .ext_ws(P1B8), 95 | .ext_sd(P1B3), 96 | 97 | // I2S output 98 | .o_sck(P1B1), 99 | .o_ws(P1B2), 100 | .o_sd0(P1B9), 101 | .o_sd1(P1B10), 102 | 103 | // Test pins 104 | .test(test_out) 105 | ); 106 | 107 | endmodule 108 | 109 | -------------------------------------------------------------------------------- /dsp/dma_tb.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Sat Aug 8 15:28:19 2020 4 | [*] 5 | [dumpfile] "(null)" 6 | [savefile] "/home/dave/Desktop/git/fpga/dsp/dma_tb.gtkw" 7 | [timestart] 111670000 8 | [size] 1697 832 9 | [pos] -1 -1 10 | *-21.213655 118180000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 11 | [treeopen] tb. 12 | [treeopen] tb.dma. 13 | [sst_width] 196 14 | [signals_width] 169 15 | [sst_expanded] 1 16 | [sst_vpaned_height] 233 17 | @28 18 | tb.wb_clk 19 | tb.wb_rst 20 | tb.dma.wb_dbus_we 21 | tb.dma.wb_dbus_cyc 22 | @22 23 | tb.dma.wb_dbus_adr[31:0] 24 | tb.dma.wb_dbus_dat[31:0] 25 | @28 26 | tb.dma.dbus_ack 27 | tb.dma.xfer_block 28 | @22 29 | tb.dma.dbus_rdt[31:0] 30 | @28 31 | tb.dma.dma_cyc 32 | @22 33 | tb.rd_data[31:0] 34 | @28 35 | tb.dma.dma_ack 36 | @c00022 37 | tb.dma.dma_adr[31:0] 38 | @28 39 | (0)tb.dma.dma_adr[31:0] 40 | (1)tb.dma.dma_adr[31:0] 41 | (2)tb.dma.dma_adr[31:0] 42 | (3)tb.dma.dma_adr[31:0] 43 | (4)tb.dma.dma_adr[31:0] 44 | (5)tb.dma.dma_adr[31:0] 45 | (6)tb.dma.dma_adr[31:0] 46 | (7)tb.dma.dma_adr[31:0] 47 | (8)tb.dma.dma_adr[31:0] 48 | (9)tb.dma.dma_adr[31:0] 49 | (10)tb.dma.dma_adr[31:0] 50 | (11)tb.dma.dma_adr[31:0] 51 | (12)tb.dma.dma_adr[31:0] 52 | (13)tb.dma.dma_adr[31:0] 53 | (14)tb.dma.dma_adr[31:0] 54 | (15)tb.dma.dma_adr[31:0] 55 | (16)tb.dma.dma_adr[31:0] 56 | (17)tb.dma.dma_adr[31:0] 57 | (18)tb.dma.dma_adr[31:0] 58 | (19)tb.dma.dma_adr[31:0] 59 | (20)tb.dma.dma_adr[31:0] 60 | (21)tb.dma.dma_adr[31:0] 61 | (22)tb.dma.dma_adr[31:0] 62 | (23)tb.dma.dma_adr[31:0] 63 | (24)tb.dma.dma_adr[31:0] 64 | (25)tb.dma.dma_adr[31:0] 65 | (26)tb.dma.dma_adr[31:0] 66 | (27)tb.dma.dma_adr[31:0] 67 | (28)tb.dma.dma_adr[31:0] 68 | (29)tb.dma.dma_adr[31:0] 69 | (30)tb.dma.dma_adr[31:0] 70 | (31)tb.dma.dma_adr[31:0] 71 | @1401200 72 | -group_end 73 | @22 74 | tb.dma.dma_dat[31:0] 75 | tb.dma.dma_rdt[31:0] 76 | tb.dma.dma_sel[3:0] 77 | @28 78 | tb.dma.dma_we 79 | tb.dma.reg_start_req 80 | @29 81 | tb.dma.reg_repeat 82 | @22 83 | tb.dma.reg_addr[23:0] 84 | tb.dma.reg_match[23:0] 85 | tb.dma.reg_step[15:0] 86 | tb.dma.reg_cycles[15:0] 87 | tb.dma.reg_blocks[15:0] 88 | tb.dma.addr[23:0] 89 | tb.dma.block[15:0] 90 | tb.dma.xfer_adr[15:0] 91 | tb.dma.xfer_dat[15:0] 92 | @28 93 | tb.dma.xfer_re 94 | tb.dma.block_en 95 | tb.dma.block_done 96 | tb.dma.running 97 | tb.dma.xfer_done 98 | @22 99 | tb.dma.run_addr[23:0] 100 | tb.dma.run_cycles[15:0] 101 | [pattern_trace] 1 102 | [pattern_trace] 0 103 | -------------------------------------------------------------------------------- /dsp/i2s_clock_tb.v: -------------------------------------------------------------------------------- 1 | 2 | 3 | `default_nettype none 4 | `timescale 1ns / 100ps 5 | 6 | module tb (); 7 | 8 | initial begin 9 | $dumpfile("dsp.vcd"); 10 | $dumpvars(0, tb); 11 | end 12 | 13 | reg ck = 0; 14 | 15 | always #42 ck <= !ck; 16 | 17 | wire rst; 18 | 19 | reset #(.LENGTH(4)) reset (.ck(ck), .rst_req(1'b0), .rst(rst)); 20 | 21 | // Simulate External Clock Gen 22 | 23 | reg ext_rst = 1; 24 | wire ext_en; 25 | wire ext_sck; 26 | wire ext_ws; 27 | wire [5:0] ext_frame_posn; 28 | 29 | localparam DIVIDER = 16; 30 | 31 | i2s_clock #(.DIVIDER(DIVIDER)) 32 | i2s_clock_ext ( 33 | .ck(ck), 34 | .rst(ext_rst), 35 | .en(ext_en), 36 | .sck(ext_sck), 37 | .ws(ext_ws), 38 | .frame_posn(ext_frame_posn) 39 | ); 40 | 41 | wire sck; 42 | wire ws; 43 | wire en; 44 | wire [5:0] frame_posn; 45 | wire external; 46 | 47 | i2s_dual #(.DIVIDER(DIVIDER)) 48 | i2s_dual( 49 | .ck(ck), 50 | .rst(rst), 51 | .ext_sck(ext_sck), 52 | .ext_ws(ext_ws), 53 | .sck(sck), 54 | .ws(ws), 55 | .en(en), 56 | .frame_posn(frame_posn), 57 | .external(external) 58 | ); 59 | 60 | integer i; 61 | 62 | initial begin 63 | 64 | $display("start i2s tests"); 65 | 66 | wait(!rst); 67 | 68 | // Wait for a few frames 69 | wait(ws); 70 | wait(!ws); 71 | wait(ws); 72 | wait(!ws); 73 | 74 | // turn off EXT 75 | ext_rst <= 1; 76 | for (i = 0; i < 30; i = i + 1) begin 77 | @(posedge sck); 78 | end 79 | 80 | // turn on EXT 81 | ext_rst <= 0; 82 | tb_assert(!external); 83 | 84 | // Wait for a few frames 85 | for (i = 0; i < 6; i = i + 1) begin 86 | wait(ws); 87 | wait(!ws); 88 | end 89 | 90 | tb_assert(external); 91 | 92 | // Wait for a few frames 93 | for (i = 0; i < 6; i = i + 1) begin 94 | wait(ws); 95 | wait(!ws); 96 | end 97 | 98 | // turn off EXT 99 | ext_rst <= 1; 100 | 101 | // Wait for a few frames 102 | wait(ws); 103 | wait(!ws); 104 | wait(ws); 105 | wait(!ws); 106 | 107 | tb_assert(!external); 108 | 109 | $display("done"); 110 | $finish; 111 | end 112 | 113 | endmodule 114 | 115 | -------------------------------------------------------------------------------- /dsp/sk9822_tb.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Fri Aug 14 17:30:23 2020 4 | [*] 5 | [dumpfile] "/home/dave/Desktop/git/fpga/dsp/dsp.vcd" 6 | [dumpfile_mtime] "Fri Aug 14 14:41:35 2020" 7 | [dumpfile_size] 247693 8 | [savefile] "/home/dave/Desktop/git/fpga/dsp/sk9822_tb.gtkw" 9 | [timestart] 0 10 | [size] 1730 629 11 | [pos] -1 -1 12 | *-26.173794 37716000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [treeopen] tb.sk9822_peripheral. 15 | [sst_width] 196 16 | [signals_width] 166 17 | [sst_expanded] 1 18 | [sst_vpaned_height] 166 19 | @28 20 | tb.wb_clk 21 | tb.wb_rst 22 | tb.wb_dbus_cyc 23 | @22 24 | tb.wb_dbus_adr[31:0] 25 | @28 26 | tb.wb_dbus_we 27 | @22 28 | tb.wb_dbus_dat[31:0] 29 | @28 30 | tb.sk9822_peripheral.chip_select.ack 31 | tb.sk9822_peripheral.chip_select.cyc 32 | tb.sk9822_peripheral.dpram.re 33 | tb.sk9822_peripheral.led_ck 34 | tb.sk9822_peripheral.led_data 35 | tb.sk9822_peripheral.dpram.we 36 | @22 37 | tb.sk9822_peripheral.dpram.waddr[3:0] 38 | tb.sk9822_peripheral.dpram.wdata[31:0] 39 | tb.sk9822_peripheral.bit_count[4:0] 40 | @c00023 41 | tb.sk9822_peripheral.shift[31:0] 42 | @29 43 | (0)tb.sk9822_peripheral.shift[31:0] 44 | (1)tb.sk9822_peripheral.shift[31:0] 45 | (2)tb.sk9822_peripheral.shift[31:0] 46 | (3)tb.sk9822_peripheral.shift[31:0] 47 | (4)tb.sk9822_peripheral.shift[31:0] 48 | (5)tb.sk9822_peripheral.shift[31:0] 49 | (6)tb.sk9822_peripheral.shift[31:0] 50 | (7)tb.sk9822_peripheral.shift[31:0] 51 | (8)tb.sk9822_peripheral.shift[31:0] 52 | (9)tb.sk9822_peripheral.shift[31:0] 53 | (10)tb.sk9822_peripheral.shift[31:0] 54 | (11)tb.sk9822_peripheral.shift[31:0] 55 | (12)tb.sk9822_peripheral.shift[31:0] 56 | (13)tb.sk9822_peripheral.shift[31:0] 57 | (14)tb.sk9822_peripheral.shift[31:0] 58 | (15)tb.sk9822_peripheral.shift[31:0] 59 | (16)tb.sk9822_peripheral.shift[31:0] 60 | (17)tb.sk9822_peripheral.shift[31:0] 61 | (18)tb.sk9822_peripheral.shift[31:0] 62 | (19)tb.sk9822_peripheral.shift[31:0] 63 | (20)tb.sk9822_peripheral.shift[31:0] 64 | (21)tb.sk9822_peripheral.shift[31:0] 65 | (22)tb.sk9822_peripheral.shift[31:0] 66 | (23)tb.sk9822_peripheral.shift[31:0] 67 | (24)tb.sk9822_peripheral.shift[31:0] 68 | (25)tb.sk9822_peripheral.shift[31:0] 69 | (26)tb.sk9822_peripheral.shift[31:0] 70 | (27)tb.sk9822_peripheral.shift[31:0] 71 | (28)tb.sk9822_peripheral.shift[31:0] 72 | (29)tb.sk9822_peripheral.shift[31:0] 73 | (30)tb.sk9822_peripheral.shift[31:0] 74 | (31)tb.sk9822_peripheral.shift[31:0] 75 | @1401201 76 | -group_end 77 | @22 78 | tb.sk9822_peripheral.ram_addr[3:0] 79 | tb.sk9822_peripheral.ram_data[31:0] 80 | [pattern_trace] 1 81 | [pattern_trace] 0 82 | -------------------------------------------------------------------------------- /dsp/dsp.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI 3 | [*] Tue Jul 14 06:50:06 2020 4 | [*] 5 | [dumpfile] "/home/dave/Desktop/git/fpga/dsp/dsp.vcd" 6 | [dumpfile_mtime] "Tue Jul 14 06:48:07 2020" 7 | [dumpfile_size] 846329 8 | [savefile] "/home/dave/Desktop/git/fpga/dsp/dsp.gtkw" 9 | [timestart] 4996000 10 | [size] 1918 791 11 | [pos] -1 -1 12 | *-18.683033 4998000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb. 14 | [treeopen] tb.engine. 15 | [treeopen] tb.engine.seq. 16 | [sst_width] 196 17 | [signals_width] 190 18 | [sst_expanded] 1 19 | [sst_vpaned_height] 217 20 | @28 21 | tb.engine.coef.ck 22 | tb.engine.seq.rst 23 | tb.engine.iomem_valid 24 | @22 25 | tb.engine.iomem_wstrb[3:0] 26 | @28 27 | tb.engine.iomem_ready 28 | @22 29 | tb.engine.coef.waddr[7:0] 30 | tb.engine.coef.wdata[31:0] 31 | @28 32 | tb.engine.seq.reset 33 | tb.engine.coef.ck 34 | @c00022 35 | tb.engine.seq.coef_addr[7:0] 36 | @28 37 | (0)tb.engine.seq.coef_addr[7:0] 38 | (1)tb.engine.seq.coef_addr[7:0] 39 | (2)tb.engine.seq.coef_addr[7:0] 40 | (3)tb.engine.seq.coef_addr[7:0] 41 | (4)tb.engine.seq.coef_addr[7:0] 42 | (5)tb.engine.seq.coef_addr[7:0] 43 | (6)tb.engine.seq.coef_addr[7:0] 44 | (7)tb.engine.seq.coef_addr[7:0] 45 | @1401200 46 | -group_end 47 | @22 48 | tb.engine.seq.coef_data[31:0] 49 | @28 50 | tb.engine.seq.done_req 51 | @22 52 | tb.engine.seq.op_code[4:0] 53 | tb.engine.seq.gain[15:0] 54 | @28 55 | tb.engine.seq.chan[2:0] 56 | @22 57 | tb.engine.audio_wdata[15:0] 58 | @23 59 | tb.engine.seq.audio_in[15:0] 60 | @22 61 | tb.engine.seq.audio_raddr[10:0] 62 | @28 63 | tb.engine.audio_we 64 | tb.engine.seq.negative 65 | @22 66 | tb.engine.seq.audio[15:0] 67 | tb.engine.seq.mul.a[15:0] 68 | tb.engine.seq.mul.b[15:0] 69 | tb.engine.seq.mul_out[31:0] 70 | @28 71 | tb.engine.seq.ck 72 | tb.engine.seq.reset 73 | tb.engine.seq.acc_en 74 | tb.engine.seq.negative 75 | tb.engine.seq.acc_add 76 | tb.engine.seq.acc_reset 77 | @22 78 | tb.engine.seq.acc_out[39:0] 79 | tb.engine.seq.capture_out[31:0] 80 | @28 81 | tb.engine.seq.out_en_req 82 | tb.engine.seq.shift_en 83 | @22 84 | tb.engine.seq.shift_out[15:0] 85 | tb.engine.seq.out_addr[3:0] 86 | @28 87 | tb.engine.seq.out_we 88 | @22 89 | tb.engine.out_audio[15:0] 90 | @28 91 | tb.engine.allow_audio_writes 92 | @22 93 | tb.engine.left[15:0] 94 | tb.engine.right[15:0] 95 | @28 96 | tb.engine.seq.done 97 | tb.engine.seq.error 98 | tb.engine.tx.ck 99 | tb.engine.tx.en 100 | tb.i2sx.sck 101 | tb.engine.i2s_out.ws 102 | @22 103 | tb.engine.tx.frame_posn[5:0] 104 | tb.engine.tx.left[15:0] 105 | tb.engine.tx.right[15:0] 106 | @28 107 | tb.engine.tx.sd 108 | @200 109 | - 110 | @22 111 | tb.i2sx.prescale[4:0] 112 | tb.i2sx.match[4:0] 113 | @28 114 | tb.txx.en 115 | @22 116 | tb.i2sx.frame_posn[5:0] 117 | tb.txx.left[15:0] 118 | tb.txx.right[15:0] 119 | @28 120 | tb.txx.sd 121 | @22 122 | tb.txx.shift[15:0] 123 | @200 124 | - 125 | @22 126 | tb.engine.tx.shift[15:0] 127 | [pattern_trace] 1 128 | [pattern_trace] 0 129 | -------------------------------------------------------------------------------- /orangecrab/orangecrab.v: -------------------------------------------------------------------------------- 1 | 2 | `default_nettype none 3 | 4 | module top ( 5 | input wire clk, 6 | /* verilator lint_off UNUSED */ 7 | input wire btn, 8 | /* verilator lint_on UNUSED */ 9 | //output wire reset, 10 | output wire r, 11 | output wire g, 12 | output wire b, 13 | output wire p0, 14 | output wire p1, 15 | output wire p5, 16 | output wire p6, 17 | output wire p9, 18 | output wire p10, 19 | output wire p11, 20 | output wire p12, 21 | output wire p13 22 | ); 23 | 24 | reg [28:0] divider = 0; 25 | 26 | always @(posedge clk) begin 27 | divider <= divider + 1; 28 | end 29 | 30 | /* 31 | * 32 | */ 33 | 34 | // DSP interface 35 | /* verilator lint_off UNUSED */ 36 | wire ext_ck; 37 | 38 | assign ext_ck = clk; 39 | 40 | wire tx; 41 | 42 | // XIP Flash 43 | wire spi_sck; 44 | wire spi_cs; 45 | wire spi_mosi; 46 | wire spi_miso; 47 | 48 | wire [7:0] test; 49 | 50 | // sk9822 drive 51 | wire led_ck; 52 | wire led_data; 53 | 54 | // I2S 55 | wire sck; 56 | wire ws; 57 | // Mic in 58 | reg sd_in0 = 0; 59 | reg sd_in1 = 0; 60 | reg sd_in2 = 0; 61 | reg sd_in3 = 0; 62 | 63 | // I2S Output 64 | wire o_sck; 65 | wire o_ws; 66 | wire o_sd; 67 | 68 | // External I2S sync input, SD output 69 | reg ext_sck = 0; 70 | reg ext_ws = 0; 71 | wire ext_sd; 72 | /* verilator lint_on UNUSED */ 73 | 74 | dsp #(.PLL_HZ(24000000)) dsp ( 75 | .ext_ck(ext_ck), 76 | .tx(tx), 77 | .spi_sck(spi_sck), 78 | .spi_cs(spi_cs), 79 | .spi_mosi(spi_mosi), 80 | .spi_miso(spi_miso), 81 | .test(test), 82 | .led_ck(led_ck), 83 | .led_data(led_data), 84 | .sck(sck), 85 | .ws(ws), 86 | .sd_in0(sd_in0), 87 | .sd_in1(sd_in1), 88 | .sd_in2(sd_in2), 89 | .sd_in3(sd_in3), 90 | .o_sck(o_sck), 91 | .o_ws(o_ws), 92 | .o_sd(o_sd), 93 | .ext_sck(ext_sck), 94 | .ext_ws(ext_ws), 95 | .ext_sd(ext_sd) 96 | ); 97 | 98 | assign r = divider[24]; 99 | assign g = divider[25]; 100 | assign b = divider[26]; 101 | //assign r = reset; 102 | //assign g = reset; 103 | //assign b = reset; 104 | 105 | assign p0 = 0; 106 | assign p1 = 0; 107 | 108 | assign p5 = spi_sck; 109 | assign p6 = spi_cs; 110 | assign p9 = spi_mosi; 111 | 112 | assign p10 = divider[7]; 113 | assign p11 = o_ws; 114 | assign p12 = 0; 115 | assign p13 = 0; 116 | 117 | assign spi_miso = btn; 118 | 119 | endmodule 120 | 121 | /* 122 | * Dummy modules 123 | */ 124 | 125 | module pll( 126 | input wire clock_in, 127 | output wire clock_out, 128 | output wire locked 129 | ); 130 | 131 | // divide down the 48Mhz 132 | 133 | reg divide = 0; 134 | 135 | always @(posedge clock_in) begin 136 | divide <= !divide; 137 | end 138 | 139 | assign clock_out = divide; 140 | assign locked = 1; 141 | 142 | endmodule 143 | 144 | // FIN 145 | -------------------------------------------------------------------------------- /dsp/README.md: -------------------------------------------------------------------------------- 1 | Digital Audio Processor 2 | ======================= 3 | 4 | [github](https://github.com/DaveBerkeley/fpga/tree/master/dsp) 5 | 6 | Experimental audio processor. 7 | It is intended as a run-time engine to control beam forming 8 | for a microphone phased array. 9 | 10 | It has 8 channels of 16-bit audio input, over [I2S](https://en.wikipedia.org/wiki/I%C2%B2S). 11 | Each channel is saved into a circular buffer, currently 256 words long. 12 | 13 | There is a simple engine which executes a series of commands stored in DPRAM. 14 | These commands are loaded by the host processor. 15 | The commands take an offset, a channel and a gain and apply the audio data to a MAC. 16 | The MAC uses the 16x16 multiply DSP on the FPGA, giving a 32-bit result, 17 | followed by a 40-bit accumulator. 18 | 19 | The output of the 40-bit accumulator is shifted by n bits, 20 | to reduce the output width to 16-bits, 21 | and the output written to DPRAM and/or to the output I2S devices. 22 | This is done by the **SAVE** instruction, which works on the last accumulator output. 23 | 24 | A typical sequence might be to sum the weighted gains of several channels, 25 | with different time delays, and output them to the left / right output channels. 26 | 27 | A simple example program might be : 28 | 29 | code : 48010400 MACZ offset=00 chan=1 gain=0400 30 | code : 40000200 MAC offset=02 chan=0 gain=0200 31 | code : 40030100 MAC offset=05 chan=3 gain=0100 32 | code : 10480001 SAVE shift=09 addr=01 33 | ... 34 | code : 48020400 MACZ offset=00 chan=2 gain=0400 35 | code : 40030200 MAC offset=02 chan=3 gain=0200 36 | code : 40000100 MAC offset=05 chan=0 gain=0100 37 | code : 10480000 SAVE shift=09 addr=00 38 | ... 39 | code : 78000000 HALT 40 | 41 | The program is run from start to finish at the start of every audio frame. 42 | There are no loops, branches. Just a sequence of commands. 43 | 44 | The MACx commands are : **MAC** (add), **MACZ** (reset the accumulator and add), 45 | **MACN** (subtract - used for -ve gains), and **MACNZ** (both). 46 | 47 | The FIR filter allows taps from different audio offsets to be taken. 48 | For example, if you want to interpolate a t-4.5 sample, 49 | you can add t-4 and t-5 and divide by two. 50 | This allows fine control over the audio delay. 51 | 52 | code : 48010400 MAC offset=04 chan=0 gain=0200 53 | code : 40000200 MAC offset=05 chan=0 gain=0200 54 | ... 55 | 56 | Echo cancelation could be acheived by subtracting the signal with a longer time delay : 57 | 58 | code : 48010400 MACN offset=84 chan=0 gain=0200 59 | ... 60 | 61 | Multiple taps can be added, so any FIR filter is possible, up to 256 taps. 62 | 63 | Here is a screenshot of the audio output, the output I2S converted to audio using a PCM5102A DAC. 64 | I used the [FIR design site](http://t-filter.engineerjs.com/) 65 | to generate the coefficients for a band-pass filter centred on around 2kHz. 66 | I use an impulse generated by a second FPGA and view the output. 67 | 68 | ![screenshot](https://github.com/DaveBerkeley/fpga/blob/master/dsp/images/scr_202007181421.png) 69 | 70 | 71 | The 16x16 multiplier available on the FPGA does not support signed arithmetic, 72 | so any negative audio is inverted before the multiply stage. 73 | The sign is corrected at the accumulator stage, where any -ve gains are also applied. 74 | 75 | The processor uses a multi-stage pipelined architecture. 76 | This gives a throughtput of one MAC per clock cycle, 77 | allowing hundreds of calculations per audio frame. 78 | 79 | The development board I'm using is the [Icebreaker](https://1bitsquared.de/products/icebreaker). 80 | 81 | The host processor is Olof Kindgren's [SERV](https://github.com/olofk/serv). 82 | See my [XiP SoC](https://github.com/DaveBerkeley/serv_soc) based on it. 83 | -------------------------------------------------------------------------------- /orangecrab/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CROSS=riscv32-unknown-elf- 3 | 4 | ifndef SERV 5 | S = https://github.com/olofk/serv 6 | $(error SERV is not set, see $(S)) 7 | endif 8 | 9 | ifndef SOC 10 | S = https://github.com/DaveBerkeley/serv_soc 11 | $(error SOC is not set, see $(S)) 12 | endif 13 | 14 | BUILD = build 15 | PROJ = crab 16 | LPF = orangecrab_r02.lpf 17 | 18 | 19 | # C files 20 | 21 | CFILES = firmware.c 22 | 23 | # Verilog files 24 | 25 | FILES = 26 | FILES += orangecrab.v 27 | 28 | # DSP Files 29 | 30 | DSP=../dsp 31 | 32 | FILES += $(DSP)/dsp.v 33 | #FILES += $(DSP)/audio_engine.v 34 | FILES += $(DSP)/dpram.v 35 | #FILES += $(DSP)/i2s_rx.v 36 | #FILES += $(DSP)/i2s_tx.v 37 | #FILES += $(DSP)/i2s_clock.v 38 | #FILES += $(DSP)/i2s_secondary.v 39 | #FILES += $(DSP)/pipe.v 40 | #FILES += $(DSP)/sequencer.v 41 | #FILES += $(DSP)/multiplier.v 42 | #FILES += $(DSP)/shifter.v 43 | #FILES += $(DSP)/accumulator.v 44 | #FILES += $(DSP)/addr_adder.v 45 | #FILES += $(DSP)/twos_complement.v 46 | 47 | # Serv SoC Files 48 | FILES += $(SOC)/reset.v 49 | FILES += $(SOC)/ibus.v 50 | FILES += $(SOC)/uart.v 51 | FILES += $(SOC)/spi.v 52 | FILES += $(SOC)/gpio.v 53 | FILES += $(SOC)/chip_select.v 54 | FILES += $(SOC)/ram_arb.v 55 | FILES += $(SOC)/bus_arb.v 56 | FILES += $(SOC)/timer.v 57 | FILES += $(SOC)/irq.v 58 | 59 | #HW_FILES += $(SOC)/ram.v 60 | HW_FILES += ram.v 61 | 62 | # Serv CPU internals 63 | CPU_FILES = $(CORE)/serv_rf_top.v 64 | CPU_FILES += $(CORE)/serv_rf_ram_if.v 65 | CPU_FILES += $(CORE)/serv_rf_ram.v 66 | CPU_FILES += $(CORE)/serv_rf_if.v 67 | CPU_FILES += $(CORE)/serv_mem_if.v 68 | CPU_FILES += $(CORE)/serv_top.v 69 | CPU_FILES += $(CORE)/serv_state.v 70 | CPU_FILES += $(CORE)/serv_decode.v 71 | CPU_FILES += $(CORE)/serv_bufreg.v 72 | CPU_FILES += $(CORE)/serv_ctrl.v 73 | CPU_FILES += $(CORE)/serv_alu.v 74 | CPU_FILES += $(CORE)/serv_shift.v 75 | CPU_FILES += $(CORE)/serv_csr.v 76 | CPU_FILES += $(CORE)/serv_immdec.v 77 | 78 | FILES += $(CPU_FILES) 79 | 80 | CORE=$(SERV)/rtl 81 | 82 | VCONFIG = /tmp/$(PROJ)_config.vlt 83 | 84 | SIM_FILES = 85 | SIM_FILES += $(SOC)/sim.v 86 | 87 | ADD_VERILATOR = $(VCONFIG) +incdir+$(CORE) $(SIM_FILES) 88 | 89 | all: dfu prog done 90 | 91 | clean: 92 | rm -rf $(BUILD) $(VCONFIG) 93 | 94 | $(BUILD)/$(PROJ).bit: $(FILES) Makefile $(VCONFIG) $(LPF) 95 | verilator --top-module top $(ADD_VERILATOR) $(FILES) --lint-only -Wall 96 | ./make.py $(FILES) $(HW_FILES) --tool trellis --project $(PROJ) --lpf $(LPF) 97 | 98 | # Orange Crab bootloader 99 | #USB_PID = -v 1209 -p 5af0 100 | # HAD modified bootloader see https://github.com/DaveBerkeley/had2019-playground 101 | USB_PID = -v 1d50 -p 614b 102 | 103 | done: 104 | dfu-util -a 0 -e 105 | 106 | dfu: $(BUILD)/$(PROJ).bit 107 | cp -a $(BUILD)/$(PROJ).bit $(BUILD)/$(PROJ).dfu 108 | dfu-suffix $(USB_PID) -a $(BUILD)/$(PROJ).dfu 109 | dfu-util -a 0 -D $(BUILD)/$(PROJ).dfu 110 | 111 | prog: $(BUILD)/firmware.bin 112 | cp -a $^ $(BUILD)/firmware.dfu 113 | dfu-suffix $(USB_PID) -a $(BUILD)/firmware.dfu 114 | dfu-util -a 1 -D $(BUILD)/firmware.dfu 115 | 116 | $(VCONFIG): config.vlt 117 | envsubst < $^ > $@ 118 | 119 | $(BUILD)/firmware.bin: $(BUILD)/firmware.elf 120 | $(CROSS)objcopy -S -O binary $^ $@ 121 | 122 | CFLAGS = -DICEBREAKER 123 | CFLAGS += -march=rv32i 124 | CFLAGS += -ffreestanding 125 | CFLAGS += -nostartfiles 126 | CFLAGS += -Wall -Werror 127 | CFLAGS += -O1 128 | CFLAGS += -I $(SOC) 129 | CFLAGS += $(SHARED_DEFINES) 130 | LFLAGS = -Wl,-Bstatic,-T,cpu_sections.lds,--strip-debug 131 | 132 | $(BUILD)/firmware.elf: $(CFILES) $(SOC)/start.s $(SOC)/soc.c Makefile cpu_sections.lds 133 | mkdir -p $(BUILD) 134 | $(CROSS)g++ $(CFLAGS) $(LFLAGS) -o $@ $(SOC)/start.s $(SOC)/soc.c $(CFILES) 135 | 136 | # FIN 137 | -------------------------------------------------------------------------------- /alhambra-ii.pcf: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------------------------------------- 2 | #- Alhambra II constraint file (.pcf) 3 | #- By Juan Gonzalez (Obijuan) and Jesus Arroyo Torrens 4 | #- May - 2018 5 | #- GPL license 6 | #- Repo: https://github.com/FPGAwars/Alhambra-II-FPGA 7 | # ----------------------------------------------------------------------------- 8 | 9 | 10 | # ------------ User Leds ------------------------------------------------------ 11 | set_io --nowarn LED0 45 # output 12 | set_io --nowarn LED1 44 # output 13 | set_io --nowarn LED2 43 # output 14 | set_io --nowarn LED3 42 # output 15 | set_io --nowarn LED4 41 # output 16 | set_io --nowarn LED5 39 # output 17 | set_io --nowarn LED6 38 # output 18 | set_io --nowarn LED7 37 # output 19 | 20 | # ------------ User push buttons ---------------------------------------------- 21 | set_io --nowarn SW1 34 # input 22 | set_io --nowarn SW2 33 # input 23 | 24 | # ------------ 5v Digital I/O ------------------------------------------------- 25 | 26 | # --- Top Female header 27 | # --------------------------------------- ------------------------------- 28 | # | SCL SDA AR GND D13 D12 D11 D10 D9 D8 | | D7 D6 D5 D4 D3 D2 D1 D0 | 29 | # --------------------------------------- ------------------------------- 30 | # 31 | # Male, 3 pin connectors 32 | # 33 | # Gnd * * * * * * * * * * * * * * Gnd 34 | # Vcc * * * * * * * * * * * * * * Vcc 35 | # S * * * * * * * * * * * * * * S 36 | # 37 | # 38 | # Male, 3 pin connectors 39 | # * * * * * * 40 | # * * * * * * 41 | # * * * * * * 42 | # --- Bottom female header 43 | # ------------------------------- ------------------------- 44 | # | x 5V R 3v3 5vP GND GND PWR | | DD0 DD1 DD2 DD3 DD4 DD5 | 45 | # ------------------------------- ------------------------- 46 | 47 | # -- In top female header 48 | set_io --nowarn D13 64 49 | set_io --nowarn D12 63 50 | set_io --nowarn D11 21 51 | set_io --nowarn D10 22 52 | set_io --nowarn D9 19 53 | set_io --nowarn D8 20 54 | set_io --nowarn D7 9 55 | set_io --nowarn D6 10 56 | set_io --nowarn D5 7 57 | set_io --nowarn D4 8 58 | set_io --nowarn D3 3 59 | set_io --nowarn D2 4 60 | set_io --nowarn D1 1 61 | set_io --nowarn D0 2 62 | 63 | # -- In Bottom female header 64 | set_io --nowarn DD0 114 65 | set_io --nowarn DD1 115 66 | set_io --nowarn DD2 116 67 | set_io --nowarn DD3 117 68 | set_io --nowarn DD4 118 69 | set_io --nowarn DD5 119 70 | 71 | set_io --nowarn SDA 118 72 | set_io --nowarn SCL 119 73 | 74 | # -------------------------- I2C ADC ------------------------------------------ 75 | set_io --nowarn ADC_SCL 84 # output 76 | set_io --nowarn ADC_SDA 83 77 | set_io --nowarn ADC_INT 90 # input 78 | 79 | # -------------------------- SYSTEM CLOCK ------------------------------------- 80 | set_io --nowarn CLK 49 # input 81 | 82 | # -------------------------- FTDI --------------------------------------------- 83 | # --- FTDI 0: 84 | set_io --nowarn RES 66 # input 85 | set_io --nowarn DONE 65 # output 86 | set_io --nowarn SS 71 # output 87 | set_io --nowarn MISO 68 # input 88 | set_io --nowarn MOSI 67 # output 89 | set_io --nowarn SCK 70 # output 90 | # 91 | # --- FTDI 1: (Serial port) 92 | set_io --nowarn DCD 47 # output 93 | set_io --nowarn DSR 48 # output 94 | set_io --nowarn DTR 52 # input 95 | set_io --nowarn CTS 56 # output 96 | set_io --nowarn RTS 60 # input 97 | set_io --nowarn TX 61 # output 98 | set_io --nowarn RX 62 # input 99 | -------------------------------------------------------------------------------- /dsp/pipe_tb.v: -------------------------------------------------------------------------------- 1 | 2 | `default_nettype none 3 | `timescale 1ns / 100ps 4 | 5 | module tb (); 6 | 7 | initial begin 8 | $dumpfile("dsp.vcd"); 9 | $dumpvars(0, tb); 10 | #500000 $finish; 11 | end 12 | 13 | reg ck = 0; 14 | 15 | always #42 ck <= !ck; 16 | 17 | wire rst; 18 | 19 | reset #(.LENGTH(4)) reset (.ck(ck), .rst_req(1'b0), .rst(rst)); 20 | 21 | // Test pipe() 22 | 23 | reg pt_in = 0; 24 | wire pt_out; 25 | 26 | pipe #(.LENGTH(4)) pipe_test(.ck(ck), .in(pt_in), .out(pt_out)); 27 | 28 | integer pt_i; 29 | 30 | initial begin 31 | $display("test pipe()"); 32 | tb_assert(pt_out == 0); 33 | @(posedge ck); 34 | pt_in <= 1; 35 | tb_assert(pt_out == 0); 36 | 37 | for (pt_i = 0; pt_i < 4; pt_i = pt_i + 1) begin 38 | @(posedge ck); 39 | tb_assert(pt_out == 0); 40 | end 41 | 42 | for (pt_i = 0; pt_i < 4; pt_i = pt_i + 1) begin 43 | @(posedge ck); 44 | tb_assert(pt_out == 1); 45 | end 46 | 47 | pt_in <= 0; 48 | @(posedge ck); 49 | pt_in <= 1; 50 | 51 | @(posedge ck); 52 | tb_assert(pt_out == 1); 53 | @(posedge ck); 54 | tb_assert(pt_out == 1); 55 | @(posedge ck); 56 | tb_assert(pt_out == 1); 57 | @(posedge ck); 58 | tb_assert(pt_out == 0); 59 | @(posedge ck); 60 | tb_assert(pt_out == 1); 61 | @(posedge ck); 62 | tb_assert(pt_out == 1); 63 | @(posedge ck); 64 | tb_assert(pt_out == 1); 65 | 66 | pt_in <= 0; 67 | for (pt_i = 0; pt_i < 4; pt_i = pt_i + 1) begin 68 | @(posedge ck); 69 | tb_assert(pt_out == 1); 70 | end 71 | for (pt_i = 0; pt_i < 4; pt_i = pt_i + 1) begin 72 | @(posedge ck); 73 | tb_assert(pt_out == 0); 74 | end 75 | end 76 | 77 | // Try n-wide pipe 78 | 79 | reg [15:0] p_in = 0; 80 | wire [15:0] p_out; 81 | 82 | pipe #(.LENGTH(3)) pipes [15:0] (.ck(ck), .in(p_in), .out(p_out)); 83 | 84 | initial begin 85 | 86 | @(posedge ck); 87 | wait(!rst); 88 | @(posedge ck); 89 | 90 | p_in <= 16'h1234; 91 | @(posedge ck); 92 | tb_assert(p_out == 16'h0); 93 | 94 | p_in <= 16'haaaa; 95 | @(posedge ck); 96 | tb_assert(p_out == 16'h0); 97 | 98 | p_in <= 16'h5555; 99 | @(posedge ck); 100 | tb_assert(p_out == 16'h0); 101 | 102 | p_in <= 16'h4545; 103 | @(posedge ck); 104 | tb_assert(p_out == 16'h1234); 105 | 106 | p_in <= 16'h4321; 107 | @(posedge ck); 108 | tb_assert(p_out == 16'haaaa); 109 | 110 | @(posedge ck); 111 | tb_assert(p_out == 16'h5555); 112 | 113 | @(posedge ck); 114 | tb_assert(p_out == 16'h4545); 115 | 116 | @(posedge ck); 117 | tb_assert(p_out == 16'h4321); 118 | 119 | @(posedge ck); 120 | tb_assert(p_out == 16'h4321); 121 | 122 | end 123 | 124 | 125 | // Try n-wide pipe 126 | 127 | reg p1_in = 0; 128 | wire p1_out; 129 | 130 | pipe #(.LENGTH(1)) pipe1 (.ck(ck), .in(p1_in), .out(p1_out)); 131 | 132 | initial begin 133 | 134 | @(posedge ck); 135 | wait(!rst); 136 | @(posedge ck); 137 | 138 | p1_in <= 1; 139 | @(posedge ck); 140 | tb_assert(p1_out == 0); 141 | 142 | @(posedge ck); 143 | tb_assert(p1_out == 1); 144 | 145 | @(posedge ck); 146 | tb_assert(p1_out == 1); 147 | 148 | p1_in <= 0; 149 | @(posedge ck); 150 | tb_assert(p1_out == 1); 151 | 152 | @(posedge ck); 153 | tb_assert(p1_out == 0); 154 | 155 | end 156 | 157 | endmodule 158 | 159 | -------------------------------------------------------------------------------- /dsp/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CROSS=riscv32-unknown-elf- 3 | 4 | ifndef SERV 5 | S = https://github.com/olofk/serv 6 | $(error SERV is not set, see $(S)) 7 | endif 8 | 9 | ifndef SOC 10 | S = https://github.com/DaveBerkeley/serv_soc 11 | $(error SOC is not set, see $(S)) 12 | endif 13 | 14 | CORE=$(SERV)/rtl 15 | 16 | PROJ = dsp 17 | ADD_SRC = 18 | ADD_CLEAN = pll.v firmware.elf firmware.bin firmware.hex $(PROJ).bin *_tb $(VCONFIG) 19 | ADD_YOSYS = -dsp 20 | ADD_VERILATOR = $(VCONFIG) +incdir+$(CORE) 21 | ADD_DEPS = pll.v $(VCONFIG) 22 | ADD_IVERILOG = -I $(CORE) 23 | TB_DEPS = pll.v $(VCONFIG) 24 | TB_VERILATOR = /usr/share/yosys/ice40/cells_sim.v $(SOC)/sim.v 25 | ADD_TB_IVERILOG = $(SOC)/sim.v $(SOC)/tb.v 26 | 27 | VCONFIG = /tmp/$(PROJ)_config.vlt 28 | 29 | PACKAGE = sg48 30 | DEVICE = up5k 31 | 32 | DEFINES = 33 | DEFINES += USE_SK9822 34 | #DEFINES += USE_DMA 35 | DEFINES += USE_AUDIO_ENGINE 36 | DEFINES += MAKE_HIFI 37 | #DEFINES += MAKE_DSP 38 | 39 | # -D syntax common to yosys and gcc 40 | SHARED_DEFINES = $(DEFINES:%=-D %) 41 | MORE_YOSYS = $(SHARED_DEFINES) 42 | ADD_VERILATOR += $(DEFINES:%=+define+%) 43 | 44 | PLL_MHZ = 26.304000 45 | #PLL_HZ = 24000000 46 | PLL_HZ = 26304000 # for 41.1KHz 16-bit audio (DIVIDE=10) 47 | 48 | PIN_DEF = ../icebreaker.pcf 49 | 50 | FILES = pll.v 51 | FILES += audio_engine.v 52 | FILES += dpram.v 53 | FILES += i2s_tx.v 54 | FILES += i2s_rx.v 55 | FILES += i2s_clock.v 56 | FILES += i2s_secondary.v 57 | FILES += sequencer.v 58 | FILES += pipe.v 59 | FILES += shifter.v 60 | FILES += accumulator.v 61 | FILES += multiplier.v 62 | FILES += twos_complement.v 63 | FILES += addr_adder.v 64 | FILES += spl.v 65 | FILES += dma.v 66 | FILES += sk9822.v 67 | FILES += agc.v 68 | 69 | # Serv SoC Files 70 | FILES += $(SOC)/reset.v 71 | FILES += $(SOC)/ibus.v 72 | FILES += $(SOC)/uart.v 73 | FILES += $(SOC)/spi.v 74 | FILES += $(SOC)/gpio.v 75 | FILES += $(SOC)/chip_select.v 76 | FILES += $(SOC)/ram_arb.v 77 | FILES += $(SOC)/bus_arb.v 78 | FILES += $(SOC)/timer.v 79 | FILES += $(SOC)/irq.v 80 | 81 | # Files using SB_* modules we don't want in sim 82 | HW_FILES = $(SOC)/ice40up5k_spram.v 83 | HW_FILES += $(SOC)/ram.v 84 | HW_FILES += icebreaker.v 85 | 86 | # Serv CPU internals 87 | CPU_FILES = $(CORE)/serv_rf_top.v 88 | CPU_FILES += $(CORE)/serv_rf_ram_if.v 89 | CPU_FILES += $(CORE)/serv_rf_ram.v 90 | CPU_FILES += $(CORE)/serv_rf_if.v 91 | CPU_FILES += $(CORE)/serv_mem_if.v 92 | CPU_FILES += $(CORE)/serv_top.v 93 | CPU_FILES += $(CORE)/serv_state.v 94 | CPU_FILES += $(CORE)/serv_decode.v 95 | CPU_FILES += $(CORE)/serv_bufreg.v 96 | CPU_FILES += $(CORE)/serv_ctrl.v 97 | CPU_FILES += $(CORE)/serv_alu.v 98 | CPU_FILES += $(CORE)/serv_shift.v 99 | CPU_FILES += $(CORE)/serv_csr.v 100 | CPU_FILES += $(CORE)/serv_immdec.v 101 | 102 | ADD_SRC += $(CPU_FILES) $(FILES) $(HW_FILES) 103 | TB_SRC = $(CPU_FILES) $(FILES) 104 | 105 | 106 | include ../main.mk 107 | 108 | prog_firmware: firmware.bin 109 | iceprog -o 1M $^ 110 | 111 | all: prog_firmware prog 112 | 113 | pll.v : Makefile 114 | icepll -o $(PLL_MHZ) -m -f $@ 115 | # Change *_CORE macro to *_PAD macro 116 | # See SiliconBlue ICE TM Technology Library Version 2.3 117 | sed -i 's/SB_PLL40_CORE/SB_PLL40_PAD/g' $@ 118 | sed -i 's/.REFERENCECLK/.PACKAGEPIN/g' $@ 119 | 120 | firmware.bin: firmware.elf 121 | $(CROSS)objcopy -S -O binary $^ $@ 122 | 123 | CFLAGS = -DICEBREAKER 124 | CFLAGS += -march=rv32i 125 | CFLAGS += -ffreestanding 126 | CFLAGS += -nostartfiles 127 | CFLAGS += -Wall -Werror 128 | CFLAGS += -O1 129 | CFLAGS += -I $(SOC) 130 | CFLAGS += $(SHARED_DEFINES) 131 | LFLAGS = -Wl,-Bstatic,-T,icebreaker_sections.lds,--strip-debug 132 | 133 | CFILES = firmware.c 134 | CFILES += engine.c 135 | CFILES += dma.c 136 | 137 | firmware.elf: $(CFILES) $(SOC)/start.s $(SOC)/soc.c Makefile icebreaker_sections.lds 138 | $(CROSS)g++ $(CFLAGS) $(LFLAGS) -o $@ $(SOC)/start.s $(SOC)/soc.c $(CFILES) 139 | 140 | $(VCONFIG): config.vlt 141 | envsubst < $^ > $@ 142 | 143 | tb: dsp_tb pipe_tb shifter_tb dma_tb i2s_clock_tb sk9822_tb i2s_rx_tb spl_tb agc_tb 144 | 145 | # FIN 146 | -------------------------------------------------------------------------------- /orangecrab/firmware.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "firmware.h" 12 | 13 | /* 14 | * sk9822 data format 15 | */ 16 | 17 | uint32_t colour(uint8_t bright, uint8_t r, uint8_t g, uint8_t b) 18 | { 19 | return (bright << 24) + (b << 16) + (g << 8) + r; 20 | } 21 | 22 | /* 23 | * 24 | */ 25 | 26 | extern "C" void irq_handler(void)__attribute__((interrupt));; 27 | 28 | void irq_handler(void) 29 | { 30 | // check for timer interrupt 31 | // note :- the CPU only knows about the timer irq 32 | // so this will not distinguish other SoC irqs. 33 | uint32_t cause = read_mcause(); 34 | if ((cause & 0xff) != 0x07) 35 | { 36 | TRACE(); 37 | return; 38 | } 39 | 40 | uint32_t irqs = irq_state(); 41 | 42 | // 0x01 is the timer irq 43 | if (irqs != 1) 44 | { 45 | print("\r\n"); 46 | print_num(irqs, 16, 4); 47 | print(" "); 48 | TRACE(); 49 | while (1) ; 50 | } 51 | 52 | if (irqs & 0x01) 53 | { 54 | // timer irq 55 | irq_ack(0x01); 56 | 57 | static uint64_t s = 0x01000000; 58 | 59 | s += 0x00200000; 60 | timer_set(s); 61 | 62 | static int i = 0; 63 | LEDS[0] = i; 64 | i += 1; 65 | 66 | #if defined(USE_SK9822) 67 | const uint8_t bright = 4; 68 | int idx = i % 12; 69 | int r = (i & 0x10) ? 255 : 0; 70 | int g = (i & 0x20) ? 255 : 0; 71 | int b = (i & 0x40) ? 255 : 0; 72 | 73 | for (int j = 0; j < 12; j++) 74 | { 75 | if ((r + g + b) == 0) 76 | { 77 | LED_IO[j] = colour(bright, 32, 32, 32); 78 | continue; 79 | } 80 | 81 | if (j == idx) 82 | LED_IO[j] = colour(bright, r, g, b); 83 | else 84 | LED_IO[j] = colour(0, 0, 0, 0); 85 | } 86 | #endif // USE_SK9822 87 | } 88 | } 89 | 90 | // Memory locations defined in the linker config. 91 | extern "C" uint32_t _stext, _etext, _sdata, _edata, _sheap, _eheap, _sstack, _estack; 92 | 93 | // banner made with : figlet "SERV Risc-V" | sed 's/\\/\\\\/g' 94 | char banner[] = 95 | "\r\n" 96 | " ____ _____ ______ __ ____ _ __ __\r\n" 97 | " / ___|| ____| _ \\ \\ / / | _ \\(_)___ ___ \\ \\ / /\r\n" 98 | " \\___ \\| _| | |_) \\ \\ / / | |_) | / __|/ __|___\\ \\ / / \r\n" 99 | " ___) | |___| _ < \\ V / | _ <| \\__ \\ (_|_____\\ V / \r\n" 100 | " |____/|_____|_| \\_\\ \\_/ |_| \\_\\_|___/\\___| \\_/ \r\n" 101 | "\r\n" 102 | "The World's smallest RISC-V CPU. Bit-serial Architecture.\r\n" 103 | "\r\n" 104 | "https://github.com/olofk/serv\r\n\r\n"; 105 | 106 | /* 107 | * 108 | */ 109 | 110 | void show_section(const char* text, uint32_t *start, uint32_t *end) 111 | { 112 | uint32_t s = (uint32_t) start; 113 | uint32_t e = (uint32_t) end; 114 | 115 | print(text); 116 | print(" addr 0x"); 117 | print_num(s, 16, 6); 118 | print(" size 0x"); 119 | print_num(e - s, 16, 6); 120 | print("\r\n"); 121 | } 122 | 123 | /* 124 | * 125 | */ 126 | 127 | void main() 128 | { 129 | *LEDS = 0; 130 | 131 | #if 1 132 | print(banner); 133 | 134 | print("RAM "); 135 | print_num((uint32_t) &_estack, 10, 6); 136 | print(" bytes\r\n"); 137 | print("\r\n"); 138 | show_section("Program :", & _stext, & _etext); 139 | show_section("Data :", & _sdata, & _edata); 140 | show_section("Heap :", & _sheap, & _eheap); 141 | show_section("Stack :", & _sstack, & _estack); 142 | print("\r\n"); 143 | #endif 144 | 145 | timer_set(0x01000000); 146 | 147 | irq_set_enable(0x01); // timer irq 148 | //irq_set_enable(0x02); // audio_ready irq 149 | 150 | // This write_mie() instruction does not work! 151 | write_mie(0x08); 152 | write_mstatus(0x8); 153 | write_mtvec((uint32_t) irq_handler); 154 | 155 | while (true) ; 156 | } 157 | -------------------------------------------------------------------------------- /dsp/firmware.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "firmware.h" 12 | 13 | /* 14 | * sk9822 data format 15 | */ 16 | 17 | uint32_t colour(uint8_t bright, uint8_t r, uint8_t g, uint8_t b) 18 | { 19 | return (bright << 24) + (b << 16) + (g << 8) + r; 20 | } 21 | 22 | /* 23 | * 24 | */ 25 | 26 | extern "C" void irq_handler(void)__attribute__((interrupt));; 27 | 28 | void irq_handler(void) 29 | { 30 | // check for timer interrupt 31 | // note :- the CPU only knows about the timer irq 32 | // so this will not distinguish other SoC irqs. 33 | uint32_t cause = read_mcause(); 34 | if ((cause & 0xff) != 0x07) 35 | { 36 | TRACE(); 37 | return; 38 | } 39 | 40 | uint32_t irqs = irq_state(); 41 | 42 | // 0x01 is the timer irq 43 | if (irqs != 1) 44 | { 45 | print("\r\n"); 46 | print_num(irqs, 16, 4); 47 | print(" "); 48 | TRACE(); 49 | while (1) ; 50 | } 51 | 52 | if (irqs & 0x01) 53 | { 54 | // timer irq 55 | irq_ack(0x01); 56 | 57 | static uint64_t s = 0x01000000; 58 | 59 | s += 0x00200000; 60 | timer_set(s); 61 | 62 | static int i = 0; 63 | LEDS[0] = i; 64 | i += 1; 65 | 66 | #if defined(USE_SK9822) 67 | const uint8_t bright = 4; 68 | int idx = i % 12; 69 | int r = (i & 0x10) ? 255 : 0; 70 | int g = (i & 0x20) ? 255 : 0; 71 | int b = (i & 0x40) ? 255 : 0; 72 | 73 | for (int j = 0; j < 12; j++) 74 | { 75 | if ((r + g + b) == 0) 76 | { 77 | LED_IO[j] = colour(bright, 32, 32, 32); 78 | continue; 79 | } 80 | 81 | if (j == idx) 82 | LED_IO[j] = colour(bright, r, g, b); 83 | else 84 | LED_IO[j] = colour(0, 0, 0, 0); 85 | } 86 | #endif // USE_SK9822 87 | } 88 | } 89 | 90 | // Memory locations defined in the linker config. 91 | extern "C" uint32_t _stext, _etext, _sdata, _edata, _sheap, _eheap, _sstack, _estack; 92 | 93 | // banner made with : figlet "SERV Risc-V" | sed 's/\\/\\\\/g' 94 | char banner[] = 95 | "\r\n" 96 | " ____ _____ ______ __ ____ _ __ __\r\n" 97 | " / ___|| ____| _ \\ \\ / / | _ \\(_)___ ___ \\ \\ / /\r\n" 98 | " \\___ \\| _| | |_) \\ \\ / / | |_) | / __|/ __|___\\ \\ / / \r\n" 99 | " ___) | |___| _ < \\ V / | _ <| \\__ \\ (_|_____\\ V / \r\n" 100 | " |____/|_____|_| \\_\\ \\_/ |_| \\_\\_|___/\\___| \\_/ \r\n" 101 | "\r\n" 102 | "The World's smallest RISC-V CPU. Bit-serial Architecture.\r\n" 103 | "\r\n" 104 | "https://github.com/olofk/serv\r\n\r\n"; 105 | 106 | /* 107 | * 108 | */ 109 | 110 | void show_section(const char* text, uint32_t *start, uint32_t *end) 111 | { 112 | uint32_t s = (uint32_t) start; 113 | uint32_t e = (uint32_t) end; 114 | 115 | print(text); 116 | print(" addr 0x"); 117 | print_num(s, 16, 6); 118 | print(" size 0x"); 119 | print_num(e - s, 16, 6); 120 | print("\r\n"); 121 | } 122 | 123 | /* 124 | * 125 | */ 126 | 127 | extern void engine(); 128 | 129 | void main() 130 | { 131 | *LEDS = 0; 132 | 133 | #if 1 134 | print(banner); 135 | 136 | print("RAM "); 137 | print_num((uint32_t) &_estack, 10, 6); 138 | print(" bytes\r\n"); 139 | print("\r\n"); 140 | show_section("Program :", & _stext, & _etext); 141 | show_section("Data :", & _sdata, & _edata); 142 | show_section("Heap :", & _sheap, & _eheap); 143 | show_section("Stack :", & _sstack, & _estack); 144 | print("\r\n"); 145 | #endif 146 | 147 | timer_set(0x01000000); 148 | 149 | irq_set_enable(0x01); // timer irq 150 | //irq_set_enable(0x02); // audio_ready irq 151 | 152 | // This write_mie() instruction does not work! 153 | write_mie(0x08); 154 | write_mstatus(0x8); 155 | write_mtvec((uint32_t) irq_handler); 156 | 157 | print("Run audio engine\r\n"); 158 | 159 | engine(); 160 | 161 | print("Engine started ...\r\n"); 162 | 163 | } 164 | -------------------------------------------------------------------------------- /dsp/sk9822.v: -------------------------------------------------------------------------------- 1 | 2 | module sk9822_peripheral 3 | #(parameter ADDR=0) 4 | ( 5 | input wire wb_clk, 6 | input wire wb_rst, 7 | input wire wb_dbus_cyc, 8 | input wire wb_dbus_we, 9 | /* verilator lint_off UNUSED */ 10 | input wire [31:0] wb_dbus_adr, 11 | /* verilator lint_on UNUSED */ 12 | input wire [31:0] wb_dbus_dat, 13 | output wire ack, 14 | output reg led_ck, 15 | output wire led_data 16 | ); 17 | 18 | // For description of protocol see : 19 | // https://cpldcpu.wordpress.com/2016/12/13/sk9822-a-clone-of-the-apa102/ 20 | 21 | reg enabled = 0; 22 | 23 | // Chip Select to enable write access to DP_RAM 24 | 25 | wire cyc; 26 | 27 | chip_select #(.ADDR(ADDR), .WIDTH(8)) 28 | chip_select( 29 | .wb_ck(wb_clk), 30 | .addr(wb_dbus_adr[31:24]), 31 | .wb_cyc(wb_dbus_cyc), 32 | .wb_rst(wb_rst), 33 | .ack(ack), 34 | .cyc(cyc) 35 | ); 36 | 37 | always @(posedge wb_clk) begin 38 | if (cyc) begin 39 | enabled <= wb_dbus_adr[5:2] != 4'hF; 40 | end 41 | end 42 | 43 | // DP_RAM hold the LED values 44 | // 45 | // xxLL BB GG RR (LL = brightness) 46 | 47 | wire ram_re; 48 | reg [3:0] ram_addr = 0; 49 | /* verilator lint_off UNUSED */ 50 | wire [31:0] ram_data; 51 | /* verilator lint_on UNUSED */ 52 | 53 | assign ram_re = 1; 54 | 55 | wire [3:0] write_adr; 56 | assign write_adr = wb_dbus_adr[5:2]; 57 | 58 | wire [15:0] wr_hi_dat; 59 | wire [15:0] wr_lo_dat; 60 | wire [15:0] rd_hi_dat; 61 | wire [15:0] rd_lo_dat; 62 | 63 | assign wr_lo_dat = wb_dbus_dat[15:0]; 64 | assign wr_hi_dat = wb_dbus_dat[31:16]; 65 | assign ram_data[15:0] = rd_lo_dat; 66 | assign ram_data[31:16] = rd_hi_dat; 67 | 68 | dpram #(.BITS(16), .SIZE(16)) 69 | dpram_hi( 70 | .ck(wb_clk), 71 | .we(ack & wb_dbus_we), 72 | .waddr(write_adr), 73 | .wdata(wr_hi_dat), 74 | .re(ram_re), 75 | .raddr(ram_addr), 76 | .rdata(rd_hi_dat) 77 | ); 78 | 79 | dpram #(.BITS(16), .SIZE(16)) 80 | dpram_lo( 81 | .ck(wb_clk), 82 | .we(ack & wb_dbus_we), 83 | .waddr(write_adr), 84 | .wdata(wr_lo_dat), 85 | .re(ram_re), 86 | .raddr(ram_addr), 87 | .rdata(rd_lo_dat) 88 | ); 89 | 90 | // The LED Clock is divided down from sys clock 91 | 92 | localparam PRESCALE = 2; 93 | reg [PRESCALE-1:0] prescale = 0; 94 | 95 | always @(posedge wb_clk) begin 96 | prescale <= prescale + 1; 97 | end 98 | 99 | wire led_en; 100 | assign led_en = prescale == 0; 101 | wire led_half; 102 | assign led_half = prescale == ((1< 1) begin 46 | counter <= counter - 1; 47 | raddr <= raddr + 1; 48 | end else begin 49 | if (ren) 50 | done <= 1; 51 | ren <= 0; 52 | raddr <= 0; 53 | end 54 | end 55 | end 56 | end 57 | 58 | endmodule 59 | 60 | /* 61 | * Returns the index of the highest set bit, 62 | * first normalising -vew numbers 63 | */ 64 | 65 | module highest_bit 66 | #(parameter WIDTH=40, parameter LEVEL_W=$clog2(WIDTH)) 67 | (input wire ck, 68 | input wire signed [(WIDTH-1):0] in, 69 | output reg [(LEVEL_W-1):0] out 70 | ); 71 | 72 | wire [(WIDTH-1):0] normal; 73 | 74 | assign normal = in[WIDTH-1] ? ~in : in; 75 | 76 | wire [(WIDTH-1):0] bit_1; 77 | wire [(WIDTH-1):0] bit_2; 78 | wire [(WIDTH-1):0] bit_4; 79 | wire [(WIDTH-1):0] bit_8; 80 | wire [(WIDTH-1):0] bit_16; 81 | wire [(WIDTH-1):0] bit_32; 82 | wire [(WIDTH-1):0] bit_64; 83 | 84 | assign bit_1 = normal | (normal >> 1); 85 | assign bit_2 = bit_1 | (bit_1 >> 2); 86 | assign bit_4 = bit_2 | (bit_2 >> 4); 87 | assign bit_8 = bit_4 | (bit_4 >> 8); 88 | assign bit_16 = bit_8 | (bit_8 >> 16); 89 | assign bit_32 = bit_16 | (bit_16 >> 32); 90 | assign bit_64 = bit_32 | (bit_32 >> 64); 91 | 92 | wire [(WIDTH-1):0] hi_bit; 93 | 94 | assign hi_bit = bit_64 ^ (bit_64 >> 1); 95 | 96 | integer i; 97 | 98 | always @(posedge ck) begin 99 | out <= 0; 100 | for (i = 0; i < WIDTH; i = i + 1) begin 101 | if (hi_bit[i]) 102 | out <= i; 103 | end 104 | end 105 | 106 | endmodule 107 | 108 | /* 109 | * 110 | */ 111 | 112 | module tb (); 113 | 114 | reg ck = 0; 115 | 116 | always #42 ck <= !ck; 117 | 118 | initial begin 119 | $dumpfile("correlator.vcd"); 120 | $dumpvars(0, tb); 121 | #500000 $finish; 122 | end 123 | 124 | reg [1:0] reset = 0; 125 | 126 | always @(posedge ck) begin 127 | if (reset != 3) 128 | reset <= reset + 1; 129 | end 130 | 131 | wire rst; 132 | assign rst = reset == 3; 133 | 134 | reg we_x = 0; 135 | wire re_x; 136 | reg [7:0] waddr_x = 0; 137 | wire [7:0] raddr_x; 138 | wire [15:0] wdata_x; 139 | wire [15:0] data_x; 140 | 141 | wire fetch_done; 142 | dpram #(.BITS(16), .SIZE(256), .FILE("x.dat")) ram_x(.ck(ck), 143 | .we(we_x), .waddr(waddr_x), .wdata(wdata_x), 144 | .re(re_x), .raddr(raddr_x), .rdata(data_x)); 145 | 146 | localparam ADDR_W = 8; 147 | localparam COUNT_W = 5; 148 | reg start = 0; 149 | reg [(COUNT_W-1):0] count = 12; 150 | wire fetching; 151 | corr_fetch #(.ADDR_W(ADDR_W), .COUNT_W(COUNT_W)) 152 | fetch_x(.ck(ck), .en(1'b1), .start(start), .count(count), 153 | .start_addr(8'h0), .raddr(raddr_x), .ren(fetching), .done(fetch_done)); 154 | 155 | assign re_x = fetching; 156 | 157 | reg clr, acc_en, req = 0; 158 | reg [15:0] data_y; 159 | wire [39:0] acc_out; 160 | wire acc_done; 161 | 162 | mac mac(.ck(ck), .en(acc_en), .clr(clr), .req(req), 163 | .x(data_x), .y(data_y), .out(acc_out), .done(acc_done)); 164 | 165 | wire [5:0] agc; 166 | highest_bit level(.ck(ck), .in(acc_out), .out(agc)); 167 | 168 | wire [4:0] shift; 169 | assign shift = 14; 170 | wire [15:0] audio; 171 | shifter shifter(.ck(ck), .en(1'b1), .shift(shift), .in(acc_out), .out(audio)); 172 | 173 | // highest_bit() test 174 | 175 | wire [5:0] level_out; 176 | reg [39:0] level_in = 0; 177 | highest_bit level_test(.ck(ck), .in(level_in), .out(level_out)); 178 | 179 | task test_level(input [39:0] in, input [5:0] result); 180 | 181 | begin 182 | level_in <= in; 183 | @(posedge ck); 184 | @(posedge ck); 185 | //$display("level_test '%x' '%d', expect '%d'", in, level_out, result); 186 | tb_assert(level_out == result); 187 | end 188 | 189 | endtask 190 | 191 | integer ii; 192 | 193 | initial begin 194 | 195 | $display("test highest_bit()"); 196 | 197 | level_in <= 0; 198 | @(posedge ck); 199 | 200 | test_level(40'h0000000000, 0); 201 | test_level(40'h0000000001, 0); 202 | test_level(40'h0000000003, 1); 203 | test_level(40'h1000000001, 36); 204 | test_level(40'h2002222001, 37); 205 | test_level(40'h7002222001, 38); 206 | test_level(40'h7fffffffff, 38); 207 | 208 | for (ii = 0; ii < 39; ii = ii + 1) begin 209 | test_level(1 << ii, ii); 210 | end 211 | 212 | test_level(40'h8000000000, 38); 213 | test_level(40'hA000000000, 38); 214 | test_level(40'hA123456789, 38); 215 | test_level(40'hffffffffff, 0); 216 | test_level(40'hffffffffef, 4); 217 | test_level(40'hfeffffffef, 32); 218 | 219 | end 220 | 221 | // Test 222 | 223 | always @(posedge ck) begin 224 | acc_en <= fetching; 225 | req <= fetching; 226 | 227 | // set clr for the first cycle of the fetch 228 | if (fetching & !req) 229 | clr <= 1; 230 | if (clr) 231 | clr <= 0; 232 | end 233 | 234 | initial begin 235 | 236 | for (int i = 0; i < 5; i++) begin 237 | @(posedge ck); 238 | end 239 | 240 | data_y <= 16'h7fff; 241 | start <= 1; 242 | 243 | @(posedge ck); 244 | start <= 0; 245 | 246 | // Wait for acc_done ... 247 | 248 | end 249 | 250 | endmodule 251 | 252 | -------------------------------------------------------------------------------- /dsp/spl_tb.v: -------------------------------------------------------------------------------- 1 | 2 | `default_nettype none 3 | `timescale 1ns / 100ps 4 | 5 | /* 6 | * 7 | */ 8 | 9 | module tb (); 10 | 11 | initial begin 12 | $dumpfile("dsp.vcd"); 13 | $dumpvars(0, tb); 14 | #5000000 $finish; 15 | end 16 | 17 | reg ck = 0; 18 | 19 | always #42 ck <= !ck; 20 | 21 | reg rst = 0; 22 | reg peak_en = 0; 23 | reg decay_en = 0; 24 | reg [15:0] in = 0; 25 | wire [15:0] out; 26 | 27 | spl spl (.ck(ck), .rst(rst), .peak_en(peak_en), .decay_en(decay_en), .in(in), .out(out)); 28 | 29 | reg [15:0] level_in = 0; 30 | reg level_en = 0; 31 | wire [3:0] level_code; 32 | wire ready; 33 | 34 | level #(.IN_W(16)) level(.ck(ck), .en(level_en), .in(level_in), .level(level_code), .ready(ready)); 35 | 36 | integer i; 37 | 38 | task set_level(input [15:0] value); 39 | begin 40 | @(posedge ck); 41 | level_en <= 1; 42 | level_in <= value; 43 | @(posedge ck); 44 | level_en <= 0; 45 | level_in <= 16'hZ; 46 | @(posedge ck); 47 | wait(ready); 48 | end 49 | endtask 50 | 51 | // Test level module 52 | initial begin 53 | 54 | set_level(16'b10zz_zzzz_zzzz_zzzz); 55 | tb_assert(level_code == 0); 56 | 57 | set_level(16'b110z_zzzz_zzzz_zzzz); 58 | tb_assert(level_code == 1); 59 | 60 | set_level(16'b1110_zzzz_zzzz_zzzz); 61 | tb_assert(level_code == 2); 62 | 63 | set_level(16'b1111_0zzz_zzzz_zzzz); 64 | tb_assert(level_code == 3); 65 | 66 | set_level(16'b1111_10zz_zzzz_zzzz); 67 | tb_assert(level_code == 4); 68 | 69 | set_level(16'b1111_110z_zzzz_zzzz); 70 | tb_assert(level_code == 5); 71 | 72 | set_level(16'b1111_1110_zzzz_zzzz); 73 | tb_assert(level_code == 6); 74 | 75 | set_level(16'b1111_1111_0zzz_zzzz); 76 | tb_assert(level_code == 7); 77 | 78 | set_level(16'b1111_1111_10zz_zzzz); 79 | tb_assert(level_code == 8); 80 | 81 | set_level(16'b1111_1111_110z_zzzz); 82 | tb_assert(level_code == 9); 83 | 84 | set_level(16'b1111_1111_1110_zzzz); 85 | tb_assert(level_code == 10); 86 | 87 | set_level(16'b1111_1111_1111_0zzz); 88 | tb_assert(level_code == 11); 89 | 90 | set_level(16'b1111_1111_1111_10zz); 91 | tb_assert(level_code == 12); 92 | 93 | set_level(16'b1111_1111_1111_110z); 94 | tb_assert(level_code == 13); 95 | 96 | set_level(16'b1111_1111_1111_1110); 97 | tb_assert(level_code == 14); 98 | 99 | set_level(16'b1111_1111_1111_1111); 100 | tb_assert(level_code == 15); 101 | 102 | set_level(16'b01zz_zzzz_zzzz_zzzz); 103 | tb_assert(level_code == 0); 104 | 105 | set_level(16'b001z_zzzz_zzzz_zzzz); 106 | tb_assert(level_code == 1); 107 | 108 | set_level(16'b0001_0zzz_zzzz_zzzz); 109 | tb_assert(level_code == 2); 110 | 111 | set_level(16'b0000_10zz_zzzz_zzzz); 112 | tb_assert(level_code == 3); 113 | 114 | set_level(16'b0000_01zz_zzzz_zzzz); 115 | tb_assert(level_code == 4); 116 | 117 | set_level(16'b0000_001z_zzzz_zzzz); 118 | tb_assert(level_code == 5); 119 | 120 | set_level(16'b0000_0001_zzzz_zzzz); 121 | tb_assert(level_code == 6); 122 | 123 | set_level(16'b0000_0000_1zzz_zzzz); 124 | tb_assert(level_code == 7); 125 | 126 | set_level(16'b0000_0000_01zz_zzzz); 127 | tb_assert(level_code == 8); 128 | 129 | set_level(16'b0000_0000_001z_zzzz); 130 | tb_assert(level_code == 9); 131 | 132 | set_level(16'b0000_0000_0001_zzzz); 133 | tb_assert(level_code == 10); 134 | 135 | set_level(16'b0000_0000_0000_1zzz); 136 | tb_assert(level_code == 11); 137 | 138 | set_level(16'b0000_0000_0000_01zz); 139 | tb_assert(level_code == 12); 140 | 141 | set_level(16'b0000_0000_0000_001z); 142 | tb_assert(level_code == 13); 143 | 144 | set_level(16'b0000_0000_0000_0001); 145 | tb_assert(level_code == 14); 146 | 147 | set_level(16'b0000_0000_0000_0000); 148 | tb_assert(level_code == 15); 149 | 150 | end 151 | 152 | // Test spl module 153 | 154 | initial begin 155 | $display("test spl()"); 156 | @(posedge ck); 157 | 158 | peak_en = 0; 159 | decay_en = 0; 160 | in <= 16'h4000; 161 | @(posedge ck); 162 | 163 | tb_assert(out == 0); 164 | 165 | peak_en <= 1; 166 | @(posedge ck); 167 | peak_en <= 0; 168 | @(posedge ck); 169 | tb_assert(out == 16'h4000); 170 | 171 | // Check countdown to 0000 172 | decay_en = 1; 173 | @(posedge ck); 174 | @(posedge ck); 175 | tb_assert(out == 16'h3fff); 176 | @(posedge ck); 177 | tb_assert(out == 16'h3ffe); 178 | @(posedge ck); 179 | tb_assert(out == 16'h3ffd); 180 | @(posedge ck); 181 | tb_assert(out == 16'h3ffc); 182 | 183 | wait(out == 16'h0002); 184 | decay_en = 0; 185 | @(posedge ck); 186 | @(posedge ck); 187 | @(posedge ck); 188 | @(posedge ck); 189 | tb_assert(out == 16'h0002); 190 | @(posedge ck); 191 | decay_en = 1; 192 | @(posedge ck); 193 | tb_assert(out == 16'h0001); 194 | @(posedge ck); 195 | tb_assert(out == 16'h0000); 196 | @(posedge ck); 197 | tb_assert(out == 16'h0000); 198 | @(posedge ck); 199 | tb_assert(out == 16'h0000); 200 | 201 | decay_en = 0; 202 | in <= 0; 203 | @(posedge ck); 204 | @(posedge ck); 205 | peak_en <= 1; 206 | 207 | // Check peak hold 208 | for (i = 0; i < 16'h8000; i = i + 10) begin 209 | in <= i; 210 | @(posedge ck); 211 | @(posedge ck); 212 | @(posedge ck); 213 | tb_assert(out == i); 214 | end 215 | 216 | in <= 0; 217 | peak_en <= 0; 218 | 219 | // check the reset 220 | rst <= 1; 221 | @(posedge ck); 222 | @(posedge ck); 223 | tb_assert(out == 0); 224 | rst <= 0; 225 | @(posedge ck); 226 | @(posedge ck); 227 | 228 | // check negative numbers 229 | in <= 0; 230 | @(posedge ck); 231 | @(posedge ck); 232 | peak_en <= 1; 233 | 234 | for (i = 0; i < 16'h8000; i = i + 10) begin 235 | // load 2s complement 236 | in <= 1 + ~i; 237 | @(posedge ck); 238 | @(posedge ck); 239 | @(posedge ck); 240 | tb_assert(out == i); 241 | 242 | in <= i; 243 | @(posedge ck); 244 | @(posedge ck); 245 | @(posedge ck); 246 | tb_assert(out == i); 247 | 248 | end 249 | 250 | @(posedge ck); 251 | @(posedge ck); 252 | @(posedge ck); 253 | $finish; 254 | end 255 | 256 | endmodule 257 | 258 | 259 | -------------------------------------------------------------------------------- /dsp/dma.v: -------------------------------------------------------------------------------- 1 | 2 | module dma 3 | # (parameter ADDR=0, WIDTH=8, XFER_ADDR_W=3) 4 | ( 5 | // CPU bus interface 6 | input wire wb_clk, 7 | input wire wb_rst, 8 | input wire wb_dbus_cyc, 9 | input wire wb_dbus_we, 10 | /* verilator lint_off UNUSED */ 11 | input wire [31:0] wb_dbus_adr, 12 | input wire [31:0] wb_dbus_dat, 13 | /* verilator lint_on UNUSED */ 14 | output wire [31:0] dbus_rdt, 15 | output wire dbus_ack, 16 | 17 | // Xfer 18 | input wire xfer_block, 19 | output reg block_done, 20 | output reg xfer_done, 21 | output reg xfer_match, 22 | 23 | // Src data 24 | output reg [XFER_ADDR_W-1:0] xfer_adr, 25 | output wire xfer_re, 26 | /* verilator lint_off UNUSED */ 27 | input wire [15:0] xfer_dat, 28 | /* verilator lint_on UNUSED */ 29 | 30 | // DMA interface 31 | output reg dma_cyc, 32 | output reg dma_we, 33 | output reg [3:0] dma_sel, 34 | output reg [31:0] dma_adr, 35 | output wire [31:0] dma_dat, 36 | input wire dma_ack, 37 | /* verilator lint_off UNUSED */ 38 | input wire [31:0] dma_rdt 39 | /* verilator lint_on UNUSED */ 40 | ); 41 | 42 | wire cs_ack, cs_cyc; 43 | 44 | wire [7:0] cs_adr = wb_dbus_adr[31:24]; 45 | 46 | chip_select #(.ADDR(ADDR), .WIDTH(WIDTH)) 47 | cs_dma( 48 | .wb_ck(wb_clk), 49 | .addr(cs_adr), 50 | .wb_cyc(wb_dbus_cyc), 51 | .wb_rst(wb_rst), 52 | .ack(cs_ack), 53 | .cyc(cs_cyc) 54 | ); 55 | 56 | reg [23:0] reg_addr = 0; 57 | reg [23:0] reg_match = 0; 58 | reg [15:0] reg_step = 0; 59 | reg [15:0] reg_cycles = 0; 60 | reg [15:0] reg_blocks = 0; 61 | reg reg_start_req = 0; 62 | reg reg_repeat = 0; 63 | 64 | reg [15:0] block = 0; 65 | reg [23:0] addr = 0; 66 | 67 | wire [2:0] io_addr; 68 | assign io_addr = wb_dbus_adr[4:2]; 69 | 70 | // Write to the control registers 71 | 72 | wire writing; 73 | assign writing = cs_cyc & wb_dbus_we; 74 | 75 | always @(posedge wb_clk) begin 76 | 77 | if (writing & !wb_rst) begin 78 | 79 | case (io_addr) 80 | 0 : reg_addr <= wb_dbus_dat[23:0]; 81 | 1 : reg_step <= wb_dbus_dat[15:0]; 82 | 2 : reg_cycles <= wb_dbus_dat[15:0]; 83 | 3 : reg_blocks <= wb_dbus_dat[15:0]; 84 | 4 : begin reg_start_req <= 1; reg_repeat <= wb_dbus_dat[0]; end 85 | 5 : begin reg_start_req <= 0; reg_repeat <= 0; end 86 | 7 : reg_match <= wb_dbus_dat[23:0]; 87 | endcase 88 | 89 | end 90 | 91 | if (xfer_done & reg_repeat & running) begin 92 | if (reg_start_req) begin 93 | reg_start_req <= 0; 94 | end else begin 95 | reg_start_req <= 1; 96 | end 97 | end 98 | 99 | if (wb_rst) begin 100 | 101 | reg_addr <= 0; 102 | reg_match <= 0; 103 | reg_step <= 0; 104 | reg_cycles <= 0; 105 | reg_blocks <= 0; 106 | reg_start_req <= 0; 107 | reg_repeat <= 0; 108 | 109 | end 110 | 111 | end 112 | 113 | // Read the control registers 114 | 115 | wire [31:0] status; 116 | assign status = { 29'h0, xfer_match, block_done, xfer_done }; 117 | 118 | function [31:0] rdt(input [2:0] rd_addr); 119 | 120 | begin 121 | 122 | case (rd_addr) 123 | 0 : rdt = { 8'h0, reg_addr }; 124 | 1 : rdt = { 16'h0, reg_step }; 125 | 2 : rdt = { 16'h0, reg_cycles }; 126 | 3 : rdt = { 16'h0, reg_blocks }; 127 | 6 : rdt = status; 128 | 7 : rdt = { 8'h0, reg_match }; 129 | endcase 130 | 131 | end 132 | 133 | endfunction 134 | 135 | wire reading; 136 | assign reading = cs_ack & !wb_dbus_we; 137 | assign dbus_rdt = reading ? rdt(io_addr) : 0; 138 | 139 | assign dbus_ack = cs_ack; 140 | 141 | // State machine logic 142 | 143 | reg block_en = 0; 144 | 145 | reg running = 0; 146 | reg [23:0] run_addr = 0; 147 | reg [15:0] run_cycles = 0; 148 | 149 | always @(posedge wb_clk) begin 150 | 151 | if (wb_rst) begin 152 | 153 | block <= 0; 154 | addr <= 0; 155 | running <= 0; 156 | run_addr <= 0; 157 | run_cycles <= 0; 158 | 159 | dma_cyc <= 0; 160 | dma_we <= 0; 161 | dma_sel <= 0; 162 | dma_adr <= 0; 163 | 164 | block_done <= 0; 165 | xfer_done <= 0; 166 | xfer_match <= 0; 167 | xfer_adr <= 0; 168 | 169 | end 170 | 171 | if (!reg_start_req) begin 172 | // stop the engine 173 | block_done <= 0; 174 | xfer_done <= 0; 175 | xfer_match <= 0; 176 | running <= 0; 177 | end 178 | 179 | if (reg_start_req & !running) begin 180 | // sequence start 181 | run_addr <= reg_addr; 182 | run_cycles <= reg_cycles; 183 | running <= 1; 184 | block_done <= 0; 185 | block <= reg_blocks; 186 | xfer_done <= 0; 187 | xfer_match <= 0; 188 | running <= 1; 189 | end 190 | 191 | if (reg_start_req & xfer_block & !xfer_done) begin 192 | // block start 193 | block_en <= 1; 194 | addr <= run_addr; 195 | block <= reg_blocks; 196 | block_done <= 0; 197 | xfer_adr <= 0; 198 | end 199 | 200 | if (block_en & !dma_cyc) begin 201 | // start the DMA write request 202 | dma_cyc <= 1; 203 | dma_we <= 1; 204 | case (addr[1]) 205 | 0 : dma_sel <= 4'b0011; 206 | 1 : dma_sel <= 4'b1100; 207 | endcase 208 | dma_adr <= { 8'h0, addr[23:2], 2'b0 }; 209 | 210 | end 211 | 212 | if (dma_ack) begin 213 | // response from DMA, clear cyc etc. 214 | dma_cyc <= 0; 215 | dma_we <= 0; 216 | dma_sel <= 4'b0000; 217 | dma_adr <= 0; 218 | 219 | // increment the pointers for the next xfer 220 | addr <= addr + { 8'h0, reg_step }; 221 | xfer_adr <= xfer_adr + 1; 222 | block <= block - 1; 223 | 224 | end 225 | 226 | if (block_en & (block == 1) & dma_ack) begin 227 | // final xfer of block 228 | block_en <= 0; 229 | run_cycles <= run_cycles - 1; 230 | run_addr <= run_addr + 2; 231 | end 232 | 233 | if ((addr == reg_match) & (reg_match != 0)) begin 234 | xfer_match <= 1; 235 | end 236 | 237 | if (running & (block == 0) & !(block_en | xfer_block)) begin 238 | // end of block 239 | block_done <= 1; 240 | 241 | if (run_cycles == 0) begin 242 | // all blocks completed 243 | xfer_done <= 1; 244 | end 245 | end 246 | 247 | end 248 | 249 | wire [31:0] data_out; 250 | assign data_out = addr[1] ? { xfer_dat, 16'h0 } : { 16'h0, xfer_dat } ; 251 | 252 | assign dma_dat = dma_ack ? data_out : 0; 253 | assign xfer_re = block_en & dma_ack; 254 | 255 | endmodule 256 | -------------------------------------------------------------------------------- /dsp/agc.v: -------------------------------------------------------------------------------- 1 | 2 | `default_nettype none 3 | 4 | module agc 5 | #(parameter IN_W=24, OUT_W=16, CHANS=8, LEVEL_W=$clog2(IN_W), CHAN_W=$clog2(CHANS)) 6 | ( 7 | input wire ck, 8 | input wire en, 9 | output wire [CHAN_W-1:0] src_addr, 10 | input wire signed [IN_W-1:0] in_data, 11 | output wire [LEVEL_W-1:0] level, 12 | output wire signed [OUT_W-1:0] out, 13 | output wire out_we, 14 | output wire done 15 | ); 16 | 17 | wire [IN_W-1:0] normal; 18 | 19 | // Take signed wide input data and convert to absolute value. 20 | twos_complement #(.WIDTH(IN_W)) 21 | twos_complement( 22 | .ck(ck), 23 | .inv(in_data[IN_W-1]), 24 | .in(in_data), 25 | .out(normal) 26 | ); 27 | 28 | // Calculate the index of the MSB. 29 | // This corresponds to the required shift 30 | // needed to convert the eg 24-bit signal into a 16-bit one. 31 | wire level_ready; 32 | reg level_en = 0; 33 | 34 | level #(.IN_W(IN_W)) 35 | level_mod ( 36 | .ck(ck), 37 | .en(level_en), 38 | .in(max_in), 39 | .level(level), 40 | .ready(level_ready) 41 | ); 42 | 43 | wire find_level; 44 | assign find_level = level_en | !level_ready; 45 | 46 | reg find_max = 0; 47 | reg [IN_W-1:0] max_in = 0; 48 | reg find_normal = 0; 49 | reg [1:0] address = 0; 50 | 51 | wire gain_ready; 52 | wire [CHAN_W-1:0] gain_addr; 53 | reg gain_en = 0; 54 | reg gain_wait = 0; 55 | 56 | wire find_gain; 57 | assign find_gain = gain_en | !gain_ready; 58 | 59 | wire busy; 60 | assign busy = find_max | find_normal | find_level | find_gain; 61 | 62 | reg [15:0] gain = 16'b111_11111_1111_1111; 63 | 64 | wire [CHAN_W-1:0] out_addr; 65 | 66 | gain #(.IN_W(IN_W), .OUT_W(OUT_W), .CHANS(CHANS)) 67 | gain_mod ( 68 | .ck(ck), 69 | .en(gain_en), 70 | .gain(gain), 71 | .addr(gain_addr), 72 | .in_data(in_data), 73 | .out_addr(out_addr), 74 | .out_we(out_we), 75 | .out_data(out), 76 | .done(gain_ready) 77 | ); 78 | 79 | always @(posedge ck) begin 80 | 81 | if (en) begin 82 | // Start the sequence 83 | address <= 0; 84 | find_max <= 1; 85 | max_in <= 0; 86 | end 87 | 88 | find_normal <= find_max; 89 | 90 | if (level_en) begin 91 | level_en <= 0; 92 | gain_wait <= 1; 93 | end 94 | 95 | if (gain_wait & level_ready) begin 96 | gain_en <= 1; 97 | gain_wait <= 0; 98 | end 99 | 100 | if (gain_en) begin 101 | gain_en <= 0; 102 | end 103 | 104 | if (gain_ready & gain_wait) begin 105 | gain_wait <= 0; 106 | end 107 | 108 | if (find_normal) begin 109 | // find the largest abs(input) 110 | if (normal > max_in) begin 111 | max_in <= normal; 112 | end 113 | if ((address == CHANS-1) && !find_max) begin 114 | // Finished level acquisition. 115 | // Start to calculate the level 116 | level_en <= 1; 117 | end 118 | end 119 | 120 | // Step through the input channels 121 | // looking for the max value. 122 | if (find_max && !level_en) begin 123 | 124 | if (address != CHANS-1) begin 125 | // request the next input 126 | address <= address + 1; 127 | end else begin 128 | find_max <= 0; 129 | end 130 | 131 | end 132 | end 133 | 134 | assign done = !busy; 135 | assign src_addr = (find_max ? address : 0) | (find_gain ? gain_addr : 0); 136 | 137 | endmodule 138 | 139 | /* 140 | * 141 | */ 142 | 143 | module shift 144 | #(parameter IN_W=24, OUT_W=16, SHIFT=IN_W-OUT_W, SHIFT_W=$clog2(SHIFT)) 145 | ( 146 | input wire ck, 147 | input wire [SHIFT_W-1:0] shift, 148 | input wire [IN_W-1:0] in, 149 | output wire [OUT_W-1:0] out 150 | ); 151 | 152 | wire [OUT_W-1:0] shifted; 153 | 154 | genvar i; 155 | 156 | generate 157 | 158 | for (i = 0; i < OUT_W; i = i + 1) begin 159 | assign shifted[OUT_W-(i+1)] = in[IN_W-(i+shift+1)]; 160 | end 161 | 162 | endgenerate 163 | 164 | assign out = shifted; 165 | 166 | endmodule 167 | 168 | /* 169 | * 170 | */ 171 | 172 | module gain 173 | #(parameter GAIN_W=16, IN_W=24, OUT_W=16, CHANS=8, CHAN_W=$clog2(CHANS)) 174 | ( 175 | input wire ck, 176 | input wire en, 177 | input wire [GAIN_W-1:0] gain, 178 | output reg [CHAN_W-1:0] addr, 179 | input wire signed [IN_W-1:0] in_data, 180 | output wire signed [OUT_W-1:0] out_data, 181 | output wire [CHAN_W-1:0] out_addr, 182 | output wire out_we, 183 | output wire done 184 | ); 185 | 186 | initial addr = 0; 187 | 188 | reg busy_start = 0; 189 | 190 | // Top bits of gain give the shift applied 191 | localparam SHIFT = IN_W - OUT_W; 192 | localparam SHIFT_W = $clog2(SHIFT); 193 | 194 | wire [SHIFT_W-1:0] shift_by; 195 | assign shift_by = (SHIFT-1) - gain[GAIN_W-1:GAIN_W-(SHIFT_W+1)]; 196 | 197 | wire [IN_W-1:0] shift_in; 198 | wire [OUT_W-1:0] shift_out; 199 | 200 | assign shift_in = busy_start ? in_data : 0; 201 | 202 | shift #(.IN_W(IN_W), .OUT_W(OUT_W)) 203 | shifter ( 204 | .ck(ck), 205 | .shift(shift_by), 206 | .in(shift_in), 207 | .out(shift_out) 208 | ); 209 | 210 | wire in_neg; 211 | assign in_neg = shift_out[OUT_W-1]; 212 | wire [OUT_W-1:0] mul_abs; 213 | 214 | // Convert to unsigned, as 16x16 mul is unsigned 215 | twos_complement #(.WIDTH(OUT_W)) 216 | inv_in( 217 | .ck(ck), 218 | .inv(in_neg), 219 | .in(shift_out), 220 | .out(mul_abs) 221 | ); 222 | 223 | // need gain range of 0.5 .. 1.0, so top bit always set 224 | wire [15:0] mul_a; 225 | wire [15:0] mul_b; 226 | assign mul_a = { gain[12:0], 3'b0 }; 227 | assign mul_b = mul_abs; 228 | 229 | wire [31:0] mul_out; 230 | 231 | multiplier multipler( 232 | .ck(ck), 233 | .a(mul_a), 234 | .b(mul_b), 235 | .out(mul_out) 236 | ); 237 | 238 | // Now re-apply the sign of the input data 239 | 240 | wire [31:0] mul_signed; 241 | 242 | wire neg_out; 243 | pipe #(.LENGTH(2)) delay(.ck(ck), .in(in_neg), .out(neg_out)); 244 | 245 | // Convert to unsigned, as 16x16 mul is unsigned 246 | twos_complement #(.WIDTH(32)) 247 | inv_out( 248 | .ck(ck), 249 | .inv(neg_out), 250 | .in(mul_out), 251 | .out(mul_signed) 252 | ); 253 | 254 | always @(posedge ck) begin 255 | 256 | if (en) begin 257 | busy_start <= 1; 258 | addr <= 0; 259 | end 260 | 261 | if (busy_start) begin 262 | addr <= addr + 1; 263 | 264 | if (addr == (CHANS-1)) begin 265 | busy_start <= 0; 266 | end 267 | end 268 | 269 | end 270 | 271 | pipe #(.LENGTH(3)) delay_addr [CHAN_W-1:0] (.ck(ck), .in(addr), .out(out_addr)); 272 | 273 | pipe #(.LENGTH(3)) delay_done (.ck(ck), .in(busy_start), .out(out_we)); 274 | 275 | assign out_data = mul_signed[31:16]; 276 | 277 | wire busy; 278 | assign busy = busy_start | out_we; 279 | assign done = !busy; 280 | 281 | endmodule 282 | 283 | -------------------------------------------------------------------------------- /dsp/sequencer.v: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | */ 5 | 6 | module sequencer( 7 | input wire ck, 8 | input wire rst, 9 | input wire [(FRAME_W-1):0] frame, 10 | output reg [(CODE_W-1):0] coef_addr, 11 | input wire [31:0] coef_data, 12 | output wire [(AUDIO_W-1):0] audio_raddr, 13 | input wire [15:0] audio_in, 14 | output reg error, 15 | output wire done, 16 | output wire [(CHAN_W-1):0] out_addr, 17 | output wire [15:0] out_audio, 18 | output reg out_we, 19 | output reg [31:0] capture_out 20 | ); 21 | parameter CHAN_W = 4; 22 | parameter FRAME_W = 4; 23 | parameter CODE_W = 8; 24 | parameter AUDIO_W = 9; 25 | parameter ACC_W = 40; 26 | 27 | // 'reset' is active lo! TODO : Fix This 28 | 29 | wire reset; 30 | assign reset = !rst; 31 | 32 | initial begin 33 | coef_addr = 0; 34 | error = 1; 35 | out_we = 0; 36 | capture_out = 0; 37 | end 38 | 39 | // Pipeline t0 40 | // Program Counter : fetch the opcodes / coefficients 41 | 42 | always @(posedge ck) begin 43 | if (reset && !done_req) 44 | coef_addr <= coef_addr + 1; 45 | else 46 | coef_addr <= 0; 47 | end 48 | 49 | // Pipeline t1 50 | // Latch the op-code, offset, chan and gain 51 | 52 | localparam OP_W = 16 - (CHAN_W + FRAME_W); 53 | 54 | reg [(OP_W-1):0] op_code; 55 | reg [(FRAME_W-1):0] offset; 56 | reg [(CHAN_W-1):0] chan; 57 | reg [15:0] gain; 58 | 59 | always @(posedge ck) begin 60 | if (reset && !done_req && (coef_addr != 0)) begin 61 | gain <= coef_data[15:0]; 62 | chan <= coef_data[16+(CHAN_W-1):16]; 63 | offset <= coef_data[16+(CHAN_W+FRAME_W-1):16+(CHAN_W)]; 64 | op_code <= coef_data[31:16+(CHAN_W+FRAME_W)]; 65 | end else begin 66 | op_code <= 0; 67 | end 68 | end 69 | 70 | // Pipeline t2 71 | 72 | // Instruction Decode 73 | 74 | reg acc_rst_req = 0; // reset the accumulator 75 | reg done_req = 0; // sequence finished 76 | reg acc_en_req = 0; // enable accumulator 77 | reg out_en_req = 0; // enable accumulator 78 | reg acc_add_req = 0; // set if gain is +ve 79 | 80 | task noop; 81 | acc_en_req <= 0; 82 | out_en_req <= 0; 83 | acc_rst_req <= 0; 84 | acc_add_req <= 0; 85 | endtask 86 | 87 | task mac(input zero, input add); 88 | acc_en_req <= 1; 89 | acc_rst_req <= zero; 90 | acc_add_req <= add; 91 | out_en_req <= 0; 92 | endtask 93 | 94 | task halt; 95 | noop(); 96 | done_req <= 1; 97 | endtask 98 | 99 | task save; 100 | acc_en_req <= 0; 101 | acc_rst_req <= 0; 102 | acc_add_req <= 0; 103 | out_en_req <= 1; 104 | endtask 105 | 106 | task err; 107 | error <= 1; 108 | endtask 109 | 110 | // Save the address used to fetch the current audio fetch 111 | reg [(AUDIO_W-1):0] audio_raddr_0; 112 | 113 | always @(posedge ck) begin 114 | audio_raddr_0 <= audio_raddr; 115 | end 116 | 117 | wire [(16-AUDIO_W-1):0] pad; 118 | assign pad = 0; 119 | 120 | task capture(input [3:0] code); 121 | noop(); 122 | case (code) 123 | 0 : capture_out <= coef_data; // the next instructon 124 | 1 : capture_out <= { audio_in, pad, audio_raddr_0 }; 125 | 2 : capture_out <= { gain_2, audio }; // multiplier in 126 | 3 : capture_out <= mul_out; // multiplier out 127 | 128 | 5 : capture_out <= acc_out[31:0]; // accumulator out 129 | 6 : capture_out <= { 13'h0, out_addr, out_audio }; 130 | 7 : capture_out <= { 32'h12345678 }; 131 | endcase 132 | endtask 133 | 134 | localparam OP_NOOP = 5'b00000; 135 | localparam OP_CAPTURE = 5'b00001; 136 | localparam OP_SAVE = 5'b00010; 137 | localparam OP_MAC = 5'b01000; 138 | localparam OP_MACZ = 5'b01001; 139 | localparam OP_MACN = 5'b01010; 140 | localparam OP_MACNZ = 5'b01011; 141 | localparam OP_HALT = 5'b01111; 142 | 143 | // Decode the instructions 144 | always @(posedge ck) begin 145 | if (reset) begin 146 | case (op_code) 147 | OP_NOOP : noop(); 148 | OP_CAPTURE : capture(offset[3:0]); 149 | OP_MAC : mac(0, 1); 150 | OP_MACN : mac(0, 0); 151 | OP_MACZ : mac(1, 1); 152 | OP_MACNZ : mac(1, 0); 153 | OP_SAVE : save(); 154 | OP_HALT : halt(); 155 | default : err(); 156 | endcase 157 | end else begin 158 | noop(); 159 | error <= 0; 160 | done_req <= 0; 161 | end 162 | end 163 | 164 | // Calculate the input audio addr to fetch the next sample from 165 | 166 | addr_adder#(.FRAME_W(FRAME_W), .CHAN_W(CHAN_W)) 167 | adder(.ck(ck), .frame(frame), .offset(offset), .chan(chan), .addr(audio_raddr)); 168 | 169 | // Align the gain to feed the multiplier 170 | 171 | reg [15:0] gain_0; 172 | 173 | always @(posedge ck) begin 174 | gain_0 <= gain; 175 | end 176 | 177 | // Pipeline t3 178 | 179 | // Sign adjust for the multiplier and accumulator stages 180 | // 181 | // If the audio is -ve, make it signed 182 | // But use subtract at the accumulator stage 183 | 184 | reg [15:0] gain_1; 185 | reg [15:0] gain_2; 186 | 187 | always @(posedge ck) begin 188 | gain_1 <= gain_0; 189 | gain_2 <= gain_1; 190 | end 191 | 192 | // test top bit of audio for -ve value 193 | wire neg_audio; 194 | assign neg_audio = audio_in[15]; 195 | 196 | wire [15:0] audio; 197 | 198 | twos_complement #(.WIDTH(16)) neg(.ck(ck), .inv(neg_audio), .in(audio_in), .out(audio)); 199 | 200 | // pipeline the sign change to apply at the accumulator stage 201 | reg negative = 0; 202 | 203 | always @(posedge ck) begin 204 | negative <= neg_audio; 205 | end 206 | 207 | // Pipeline t4 208 | // Multiply normalised audio signal by gain 209 | 210 | wire [31:0] mul_out; 211 | 212 | multiplier mul(.ck(ck), .a(gain_2), .b(audio), .out(mul_out)); 213 | 214 | // Pipeline t5 215 | // Acumulator Stage 216 | 217 | wire signed [(ACC_W-1):0] acc_out; 218 | 219 | wire acc_reset, acc_en; 220 | pipe #(.LENGTH(3)) pipe_acc_reset (.ck(ck), .in(acc_rst_req), .out(acc_reset)); 221 | pipe #(.LENGTH(3)) pipe_acc_en (.ck(ck), .in(acc_en_req), .out(acc_en)); 222 | 223 | reg acc_add_0 = 0; 224 | reg acc_add_1 = 0; 225 | reg acc_add = 0; 226 | always @(posedge ck) begin 227 | acc_add_0 <= acc_add_req; 228 | // subtract if the audio is -ve 229 | acc_add_1 <= acc_add_0; 230 | acc_add <= acc_add_1 ^ negative; 231 | end 232 | 233 | wire [31:0] acc_in; 234 | assign acc_in = mul_out; 235 | 236 | accumulator #(.OUT_W(ACC_W)) acc(.ck(ck), .en(acc_en), .rst(acc_reset), 237 | .add(acc_add), .in(acc_in), .out(acc_out)); 238 | 239 | // Pipeline t6 240 | // Shift the 40-bit accumulator result into 16-bits 241 | 242 | reg [(FRAME_W-1):0] shift_0 = 0; 243 | reg [(FRAME_W-1):0] shift_1 = 0; 244 | reg [(FRAME_W-1):0] shift_2 = 0; 245 | reg [(FRAME_W-1):0] shift_3 = 0; 246 | 247 | always @(posedge ck) begin 248 | shift_0 <= offset; 249 | shift_1 <= shift_0; 250 | shift_2 <= shift_1; 251 | shift_3 <= shift_2; 252 | end 253 | 254 | wire [15:0] shift_out; 255 | 256 | wire shift_en; 257 | pipe #(.LENGTH(3)) pipe_shift_en (.ck(ck), .in(out_en_req), .out(shift_en)); 258 | 259 | shifter #(.SHIFT_W(FRAME_W)) shift_data (.ck(ck), .en(shift_en), .shift(shift_3), .in(acc_out), .out(shift_out)); 260 | 261 | // Pipeline t7 262 | // Write output 263 | // Takes data from the shifter and writes to address derived from 'gain' field 264 | 265 | always @(posedge ck) begin 266 | out_we <= shift_en; 267 | end 268 | 269 | reg [(CHAN_W-1):0] out_addr_0; 270 | reg [(CHAN_W-1):0] out_addr_1; 271 | reg [(CHAN_W-1):0] out_addr_2; 272 | 273 | always @(posedge ck) begin 274 | out_addr_0 <= gain_1[(CHAN_W-1):0]; 275 | out_addr_1 <= out_addr_0; 276 | out_addr_2 <= out_addr_1; 277 | end 278 | 279 | assign out_audio = out_we ? shift_out : 0; 280 | assign out_addr = out_we ? out_addr_2[(CHAN_W-1):0] : 0; 281 | 282 | // Sequence ended. Assert 'done' 283 | 284 | wire done_delay; 285 | 286 | pipe #(.LENGTH(4)) pipe_done (.ck(ck), .in(done_req), .out(done_delay)); 287 | 288 | assign done = done_delay & done_req; 289 | 290 | endmodule 291 | 292 | -------------------------------------------------------------------------------- /dsp/dma_tb.v: -------------------------------------------------------------------------------- 1 | 2 | `default_nettype none 3 | `timescale 1ns / 100ps 4 | 5 | module tb (); 6 | 7 | initial begin 8 | $dumpfile("dsp.vcd"); 9 | $dumpvars(0, tb); 10 | #500000 $finish; 11 | end 12 | 13 | reg wb_clk = 0; 14 | reg wb_rst = 1; 15 | 16 | 17 | always #42 wb_clk <= !wb_clk; 18 | 19 | reg wb_dbus_cyc = 0; 20 | reg wb_dbus_we = 0; 21 | reg [31:0] wb_dbus_adr = 32'hZ; 22 | reg [31:0] wb_dbus_dat = 32'hZ; 23 | wire [31:0] dbus_rdt; 24 | wire dbus_ack; 25 | 26 | wire dma_cyc; 27 | wire dma_we; 28 | wire [3:0] dma_sel; 29 | wire [31:0] dma_adr; 30 | wire [31:0] dma_dat; 31 | reg dma_ack = 0; 32 | wire [31:0] dma_rdt; 33 | 34 | reg xfer_block = 0; 35 | wire block_done; 36 | wire xfer_done; 37 | 38 | wire xfer_re; 39 | wire [15:0] xfer_adr; 40 | wire [15:0] xfer_dat; 41 | 42 | dma #(.ADDR(8'h65), .WIDTH(8), .XFER_ADDR_W(16)) 43 | dma( 44 | .wb_clk(wb_clk), 45 | .wb_rst(wb_rst), 46 | .wb_dbus_cyc(wb_dbus_cyc), 47 | .wb_dbus_we(wb_dbus_we), 48 | .wb_dbus_adr(wb_dbus_adr), 49 | .wb_dbus_dat(wb_dbus_dat), 50 | .dbus_rdt(dbus_rdt), 51 | .dbus_ack(dbus_ack), 52 | .xfer_block(xfer_block), 53 | .xfer_adr(xfer_adr), 54 | .xfer_dat(xfer_dat), 55 | .xfer_re(xfer_re), 56 | .block_done(block_done), 57 | .xfer_done(xfer_done), 58 | .dma_cyc(dma_cyc), 59 | .dma_we(dma_we), 60 | .dma_sel(dma_sel), 61 | .dma_adr(dma_adr), 62 | .dma_dat(dma_dat), 63 | .dma_ack(dma_ack), 64 | .dma_rdt(dma_rdt) 65 | ); 66 | 67 | task read(input [31:0] addr); 68 | 69 | begin 70 | 71 | wb_dbus_cyc <= 1; 72 | wb_dbus_adr <= addr; 73 | 74 | end 75 | 76 | endtask 77 | 78 | task read_wait; 79 | 80 | begin 81 | wait(dbus_ack); 82 | wait(!dbus_ack); 83 | end 84 | 85 | endtask 86 | 87 | task write(input [31:0] addr, input [31:0] data); 88 | 89 | begin 90 | 91 | wb_dbus_cyc <= 1; 92 | wb_dbus_adr <= addr; 93 | wb_dbus_we <= 1; 94 | wb_dbus_dat <= data; 95 | 96 | end 97 | 98 | endtask 99 | 100 | task write_wait; 101 | 102 | begin 103 | wait(dbus_ack); 104 | wait(!dbus_ack); 105 | @(posedge wb_clk); 106 | end 107 | 108 | endtask 109 | 110 | task xfer_pulse; 111 | 112 | begin 113 | 114 | xfer_block <= 1; 115 | @(posedge wb_clk); 116 | xfer_block <= 0; 117 | @(posedge wb_clk); 118 | 119 | end 120 | 121 | endtask 122 | 123 | always @(posedge wb_clk) begin 124 | if (dbus_ack) begin 125 | wb_dbus_cyc <= 0; 126 | wb_dbus_we <= 0; 127 | wb_dbus_adr <= 32'hZ; 128 | wb_dbus_dat <= 32'hZ; 129 | end 130 | end 131 | 132 | // Handle ACK for the target RAM 133 | always @(posedge wb_clk) begin 134 | if (dma_cyc) begin 135 | dma_ack <= 1; 136 | end 137 | if (dma_ack) begin 138 | dma_ack <= 0; 139 | end 140 | end 141 | 142 | reg [31:0] rd_data; 143 | 144 | // Latch any data reads on dbus 145 | always @(posedge wb_clk) begin 146 | if (dbus_ack) begin 147 | rd_data <= dbus_rdt; 148 | end 149 | end 150 | 151 | // Check rdt is never non-zero outside ack 152 | always @(posedge wb_clk) begin 153 | if (!dbus_ack) begin 154 | tb_assert(dbus_rdt == 0); 155 | end 156 | end 157 | 158 | reg auto_poll = 0; 159 | 160 | always @(posedge wb_clk) begin 161 | if (auto_poll) begin 162 | if (block_done) begin 163 | xfer_pulse(); 164 | end 165 | end 166 | end 167 | 168 | assign xfer_dat = xfer_re ? (16'h1111 << xfer_adr) : 0; 169 | 170 | localparam REG_ADDR = 32'h65000000; 171 | localparam REG_STEPS = 32'h65000004; 172 | localparam REG_CYCLES = 32'h65000008; 173 | localparam REG_BLOCKS = 32'h6500000c; 174 | localparam REG_START = 32'h65000010; 175 | localparam REG_STOP = 32'h65000014; 176 | localparam REG_STATUS = 32'h65000018; 177 | localparam REG_MATCH = 32'h6500001c; 178 | 179 | integer i; 180 | 181 | initial begin 182 | 183 | @(posedge wb_clk); 184 | @(posedge wb_clk); 185 | wb_rst <= 0; 186 | @(posedge wb_clk); 187 | @(posedge wb_clk); 188 | 189 | write(REG_ADDR, 32'h00010000); 190 | write_wait(); 191 | 192 | write(REG_MATCH, 32'h00010010); 193 | write_wait(); 194 | 195 | write(REG_STEPS, 32'h00001000); 196 | write_wait(); 197 | 198 | write(REG_CYCLES, 32'h00000010); 199 | write_wait(); 200 | 201 | write(REG_BLOCKS, 32'h8); 202 | write_wait(); 203 | 204 | write(REG_START, 32'h0); 205 | write_wait(); 206 | 207 | @(posedge wb_clk); 208 | 209 | while (!xfer_done) begin 210 | xfer_pulse(); 211 | wait(block_done); 212 | end 213 | 214 | write(REG_STOP, 32'h1); 215 | write_wait(); 216 | 217 | @(posedge wb_clk); 218 | @(posedge wb_clk); 219 | @(posedge wb_clk); 220 | 221 | write(REG_START, 32'h0); 222 | write_wait(); 223 | 224 | while (!xfer_done) begin 225 | xfer_pulse(); 226 | wait(block_done); 227 | end 228 | 229 | // Test reading the control registers 230 | 231 | read(REG_ADDR); 232 | read_wait(); 233 | tb_assert(rd_data == 32'h10000); 234 | @(posedge wb_clk); 235 | 236 | read(REG_STEPS); 237 | read_wait(); 238 | tb_assert(rd_data == 32'h1000); 239 | @(posedge wb_clk); 240 | 241 | read(REG_CYCLES); 242 | read_wait(); 243 | tb_assert(rd_data == 32'h10); 244 | @(posedge wb_clk); 245 | 246 | read(REG_BLOCKS); 247 | read_wait(); 248 | tb_assert(rd_data == 32'h8); 249 | @(posedge wb_clk); 250 | 251 | read(REG_STATUS); 252 | read_wait(); 253 | tb_assert(rd_data == 32'h7); // block/xfer done 254 | @(posedge wb_clk); 255 | 256 | // check that xfer_block is ignored if xfer_done 257 | tb_assert(xfer_done); 258 | tb_assert(block_done); 259 | 260 | xfer_pulse(); 261 | 262 | @(posedge wb_clk); 263 | @(posedge wb_clk); 264 | @(posedge wb_clk); 265 | tb_assert(xfer_done); 266 | tb_assert(block_done); 267 | 268 | // Start another cycle 269 | write(REG_STOP, 32'h1); 270 | write_wait(); 271 | 272 | // Check the status reg 273 | read(REG_STATUS); 274 | read_wait(); 275 | tb_assert(rd_data == 32'h0); 276 | @(posedge wb_clk); 277 | 278 | write(REG_START, 32'h0); 279 | write_wait(); 280 | @(posedge wb_clk); 281 | 282 | while (!xfer_done) begin 283 | xfer_pulse(); 284 | wait(block_done); 285 | end 286 | 287 | // poll for xfer_done 288 | 289 | read(REG_STATUS); 290 | read_wait(); 291 | //tb_assert(rd_data == 32'h3); // block/xfer done 292 | @(posedge wb_clk); 293 | 294 | // Check that reset works 295 | wb_rst <= 1; 296 | @(posedge wb_clk); 297 | @(posedge wb_clk); 298 | wb_rst <= 0; 299 | @(posedge wb_clk); 300 | @(posedge wb_clk); 301 | 302 | read(REG_ADDR); 303 | read_wait(); 304 | tb_assert(rd_data == 32'h0); 305 | @(posedge wb_clk); 306 | 307 | read(REG_STEPS); 308 | read_wait(); 309 | tb_assert(rd_data == 32'h0); 310 | @(posedge wb_clk); 311 | 312 | read(REG_CYCLES); 313 | read_wait(); 314 | tb_assert(rd_data == 32'h0); 315 | @(posedge wb_clk); 316 | 317 | read(REG_BLOCKS); 318 | read_wait(); 319 | tb_assert(rd_data == 32'h0); 320 | @(posedge wb_clk); 321 | 322 | read(REG_STATUS); 323 | read_wait(); 324 | tb_assert(rd_data == 32'h0); 325 | @(posedge wb_clk); 326 | 327 | // Try shorter chan/cycles 328 | 329 | write(REG_ADDR, 32'h00010000); 330 | write_wait(); 331 | 332 | write(REG_MATCH, 32'h00010004); 333 | write_wait(); 334 | 335 | write(REG_STEPS, 32'h00001000); 336 | write_wait(); 337 | 338 | write(REG_CYCLES, 32'h00000004); 339 | write_wait(); 340 | 341 | write(REG_BLOCKS, 32'h4); 342 | write_wait(); 343 | 344 | // Start in repeat mode 345 | write(REG_START, 32'h1); 346 | write_wait(); 347 | 348 | while (!xfer_done) begin 349 | xfer_pulse(); 350 | wait(block_done); 351 | end 352 | 353 | // wait for repeat 354 | wait(!xfer_done); 355 | 356 | // turn repeat off 357 | write(REG_START, 32'h0); 358 | 359 | // Do another block 360 | while (!xfer_done) begin 361 | xfer_pulse(); 362 | wait(block_done); 363 | end 364 | 365 | 366 | //write(REG_STOP, 32'h1); 367 | //write_wait(); 368 | 369 | $display("done"); 370 | 371 | end 372 | 373 | 374 | endmodule 375 | -------------------------------------------------------------------------------- /dsp/agc_tb.v: -------------------------------------------------------------------------------- 1 | 2 | `default_nettype none 3 | `timescale 1ns / 100ps 4 | 5 | /* 6 | * 7 | */ 8 | 9 | module tb (); 10 | 11 | initial begin 12 | $dumpfile("dsp.vcd"); 13 | $dumpvars(0, tb); 14 | #5000000 $finish; 15 | end 16 | 17 | reg ck = 0; 18 | 19 | always #42 ck <= !ck; 20 | 21 | // Test shift 22 | 23 | reg [2:0] shift_by = 0; 24 | reg [23:0] shift_in = 0; 25 | wire [15:0] shift_out; 26 | 27 | shift #(.IN_W(24), .OUT_W(16)) 28 | shift ( 29 | .ck(ck), 30 | .shift(shift_by), 31 | .in(shift_in), 32 | .out(shift_out) 33 | ); 34 | 35 | initial begin 36 | @(posedge ck); 37 | @(posedge ck); 38 | 39 | shift_by <= 3'b000; 40 | shift_in <= 24'h123456; 41 | @(posedge ck); 42 | tb_assert(shift_out == (16'hffff & (shift_in >> 8))); 43 | 44 | shift_by <= 3'b001; 45 | @(posedge ck); 46 | tb_assert(shift_out == (16'hffff & (shift_in >> 7))); 47 | 48 | shift_by <= 3'b010; 49 | @(posedge ck); 50 | tb_assert(shift_out == (16'hffff & (shift_in >> 6))); 51 | 52 | shift_by <= 3'b011; 53 | @(posedge ck); 54 | tb_assert(shift_out == (16'hffff & (shift_in >> 5))); 55 | 56 | shift_by <= 3'b100; 57 | @(posedge ck); 58 | tb_assert(shift_out == (16'hffff & (shift_in >> 4))); 59 | 60 | shift_by <= 3'b101; 61 | @(posedge ck); 62 | tb_assert(shift_out == (16'hffff & (shift_in >> 3))); 63 | 64 | shift_by <= 3'b110; 65 | @(posedge ck); 66 | tb_assert(shift_out == (16'hffff & (shift_in >> 2))); 67 | 68 | shift_by <= 3'b111; 69 | @(posedge ck); 70 | tb_assert(shift_out == (16'hffff & (shift_in >> 1))); 71 | 72 | end 73 | 74 | reg en = 0; 75 | wire [1:0] src_addr; 76 | wire [23:0] in_data; 77 | wire done; 78 | 79 | reg [23:0] mic_0 = 0; 80 | reg [23:0] mic_1 = 0; 81 | reg [23:0] mic_2 = 0; 82 | reg [23:0] mic_3 = 0; 83 | 84 | function [23:0] get_mic(input [1:0] addr); 85 | begin 86 | case (addr) 87 | 0 : get_mic = mic_0; 88 | 1 : get_mic = mic_1; 89 | 2 : get_mic = mic_2; 90 | 3 : get_mic = mic_3; 91 | endcase 92 | end 93 | endfunction 94 | 95 | assign in_data = (src_addr == 0) ? mic_0 : 96 | ((src_addr == 1) ? mic_1 : 97 | ((src_addr == 2) ? mic_2 : 98 | mic_3)); 99 | 100 | wire [4:0] level; 101 | wire [15:0] out; 102 | 103 | agc #(.IN_W(24), .CHANS(4)) 104 | agc ( 105 | .ck(ck), 106 | .en(en), 107 | .src_addr(src_addr), 108 | .in_data(in_data), 109 | .level(level), 110 | .out(out), 111 | .done(done) 112 | ); 113 | 114 | task go; 115 | begin 116 | en <= 1; 117 | @(posedge ck); 118 | en <= 0; 119 | @(posedge ck); 120 | end 121 | endtask 122 | 123 | integer i; 124 | 125 | initial begin 126 | $display("test agc()"); 127 | @(posedge ck); 128 | @(posedge ck); 129 | @(posedge ck); 130 | 131 | // Check it runs through the sequence 132 | mic_0 <= 24'h100000; 133 | mic_1 <= 24'h010000; 134 | mic_2 <= 24'h001000; 135 | mic_3 <= 24'h000100; 136 | go(); 137 | wait(done); 138 | @(posedge ck); 139 | 140 | // Check that all channels are looked at 141 | mic_0 <= 24'h000001; 142 | mic_1 <= 24'h000000; 143 | mic_2 <= 24'h000000; 144 | mic_3 <= 24'h000000; 145 | @(posedge ck); 146 | go(); 147 | wait(done); 148 | tb_assert(level == 22); 149 | 150 | mic_0 <= 24'h000000; 151 | mic_1 <= 24'h000001; 152 | mic_2 <= 24'h000000; 153 | mic_3 <= 24'h000000; 154 | @(posedge ck); 155 | go(); 156 | wait(done); 157 | tb_assert(level == 22); 158 | 159 | mic_0 <= 24'h000000; 160 | mic_1 <= 24'h000000; 161 | mic_2 <= 24'h000001; 162 | mic_3 <= 24'h000000; 163 | @(posedge ck); 164 | go(); 165 | wait(done); 166 | tb_assert(level == 22); 167 | 168 | mic_0 <= 24'h000000; 169 | mic_1 <= 24'h000000; 170 | mic_2 <= 24'h000000; 171 | mic_3 <= 24'h000001; 172 | @(posedge ck); 173 | go(); 174 | wait(done); 175 | tb_assert(level == 22); 176 | 177 | // check each level 178 | mic_0 <= 24'h000000; 179 | mic_1 <= 24'h000000; 180 | mic_2 <= 24'h400000; 181 | mic_3 <= 24'h000000; 182 | for (i = 0; i < 24; i++) begin 183 | @(posedge ck); 184 | go(); 185 | wait(done); 186 | @(posedge ck); 187 | tb_assert(level == i); 188 | mic_2 <= mic_2 >> 1; 189 | end 190 | 191 | // check each level for -ve levels 192 | mic_0 <= 24'h000000; 193 | mic_1 <= 24'h000000; 194 | mic_2 <= 24'hbfffff; 195 | mic_3 <= 24'h000000; 196 | for (i = 0; i < 22; i++) begin 197 | @(posedge ck); 198 | go(); 199 | wait(done); 200 | @(posedge ck); 201 | tb_assert(level == i); 202 | mic_2 <= { 1'b1, mic_2[23:1] }; 203 | end 204 | 205 | // Check mid-word transition, both signs 206 | mic_0 <= 24'h000000; 207 | mic_1 <= 24'hfff000; 208 | mic_2 <= 24'h000000; 209 | mic_3 <= 24'h000000; 210 | @(posedge ck); 211 | go(); 212 | wait(done); 213 | tb_assert(level == 10); 214 | 215 | mic_0 <= 24'h000000; 216 | mic_1 <= 24'h000fff; 217 | mic_2 <= 24'h000000; 218 | mic_3 <= 24'h000000; 219 | @(posedge ck); 220 | go(); 221 | wait(done); 222 | tb_assert(level == 11); 223 | 224 | @(posedge ck); 225 | @(posedge ck); 226 | 227 | $finish; 228 | end 229 | 230 | reg gain_en = 0; 231 | reg [15:0] gain_gain = 0; 232 | wire [1:0] gain_addr; 233 | wire signed [23:0] gain_in_data; 234 | wire signed [15:0] gain_out_data; 235 | wire [1:0] gain_out_addr; 236 | wire gain_out_we; 237 | wire gain_done; 238 | 239 | reg signed [32:0] in_0 = 0; 240 | reg signed [32:0] in_1 = 0; 241 | reg signed [32:0] in_2 = 0; 242 | reg signed [32:0] in_3 = 0; 243 | 244 | assign gain_in_data = (gain_addr == 0) ? in_0 : 245 | ((gain_addr == 1) ? in_1 : 246 | ((gain_addr == 2) ? in_2 : 247 | in_3)); 248 | 249 | gain #(.GAIN_W(16), .IN_W(24), .OUT_W(16), .CHANS(4)) 250 | gain ( 251 | .ck(ck), 252 | .en(gain_en), 253 | .gain(gain_gain), 254 | .addr(gain_addr), 255 | .in_data(gain_in_data), 256 | .out_data(gain_out_data), 257 | .out_addr(gain_out_addr), 258 | .out_we(gain_out_we), 259 | .done(gain_done) 260 | ); 261 | 262 | reg signed [15:0] out_0 = 16'hZ; 263 | reg signed [15:0] out_1 = 16'hZ; 264 | reg signed [15:0] out_2 = 16'hZ; 265 | reg signed [15:0] out_3 = 16'hZ; 266 | 267 | always @(posedge ck) begin 268 | if (gain_out_we) begin 269 | case (gain_out_addr) 270 | 0 : out_0 <= gain_out_data; 271 | 1 : out_1 <= gain_out_data; 272 | 2 : out_2 <= gain_out_data; 273 | 3 : out_3 <= gain_out_data; 274 | endcase 275 | end 276 | end 277 | 278 | task gain_run; 279 | begin 280 | gain_en <= 1; 281 | @(posedge ck); 282 | gain_en <= 0; 283 | @(posedge ck); 284 | wait(gain_done); 285 | @(posedge ck); 286 | end 287 | endtask 288 | 289 | function [15:0] twosc(input signed [15:0] a); 290 | 291 | begin 292 | return a[15] ? (1 + ~a) : a; 293 | end 294 | 295 | endfunction 296 | 297 | function automatic [32:0] mul16(input signed [15:0] a, signed [15:0] b); 298 | 299 | integer sign; 300 | integer twosc; 301 | integer out; 302 | integer m16; 303 | 304 | begin 305 | 306 | $display("a=%x b=%x", a, b); 307 | 308 | sign = a[15]; 309 | twosc = 16'hffff & ((~a) + 1); 310 | 311 | out = b * (sign ? twosc : a); 312 | $display("o=%x", out); 313 | 314 | m16 = sign ? (1 + ~out) : out; 315 | $display("m16=%x", m16); 316 | mul16 = m16; 317 | 318 | end 319 | 320 | endfunction 321 | 322 | function automatic signed [15:0] calc(input [23:0] value, input [15:0] gain); 323 | 324 | integer mantissa; 325 | integer exp; 326 | integer shift; 327 | integer v; 328 | 329 | begin 330 | 331 | $display("v=%x g=%x", value, gain); 332 | 333 | mantissa = { 1'b1, gain[12:0], 2'b1 }; 334 | exp = gain[15:13]; 335 | shift = 7 - exp; 336 | v = 16'hffff & (value >>> shift); 337 | $display("e=%x m=%x", exp, mantissa); 338 | $display("v=%x s=%x", v, shift); 339 | 340 | calc = mul16(v, mantissa); 341 | end 342 | 343 | endfunction 344 | 345 | initial begin 346 | 347 | @(posedge ck); 348 | @(posedge ck); 349 | 350 | gain_gain <= 16'hffff; 351 | 352 | in_0 <= 24'h111111; 353 | in_1 <= 24'h222222; 354 | in_2 <= 24'h444444; 355 | in_3 <= 24'h123456; 356 | gain_run(); 357 | 358 | $display("%x", calc(in_0, gain_gain)); 359 | 360 | //tb_assert(out_0 == 16'h1110); 361 | //tb_assert(out_1 == 16'h2220); 362 | //tb_assert(out_2 == 16'h4441); 363 | //tb_assert(out_3 == 16'h888b); 364 | 365 | gain_gain <= 16'hffff; 366 | 367 | in_0 <= 24'h111111; 368 | in_1 <= 24'h222222; 369 | in_2 <= 24'h444444; 370 | in_3 <= 24'h888888; 371 | gain_run(); 372 | 373 | end 374 | 375 | 376 | endmodule 377 | 378 | 379 | 380 | -------------------------------------------------------------------------------- /dsp/i2s_rx_tb.v: -------------------------------------------------------------------------------- 1 | 2 | 3 | `default_nettype none 4 | `timescale 1ns / 100ps 5 | 6 | module tb (); 7 | 8 | initial begin 9 | $dumpfile("dsp.vcd"); 10 | $dumpvars(0, tb); 11 | end 12 | 13 | reg ck = 0; 14 | 15 | always #42 ck <= !ck; 16 | 17 | wire rst; 18 | 19 | reset #(.LENGTH(20)) reset (.ck(ck), .rst_req(1'b0), .rst(rst)); 20 | 21 | wire sample; 22 | reg [5:0] frame_posn = 0; 23 | wire sd; 24 | wire [23:0] left; 25 | wire [23:0] right; 26 | wire [15:0] left_16; 27 | wire [15:0] right_16; 28 | 29 | i2s_rx #(.BITS(24)) 30 | i2s_rx ( 31 | .ck(ck), 32 | .sample(sample), 33 | .frame_posn(frame_posn), 34 | .sd(sd), 35 | .left(left), 36 | .right(right) 37 | ); 38 | 39 | i2s_rx #(.BITS(16)) 40 | i2s_rx_16 ( 41 | .ck(ck), 42 | .sample(sample), 43 | .frame_posn(frame_posn), 44 | .sd(sd), 45 | .left(left_16), 46 | .right(right_16) 47 | ); 48 | 49 | reg [63:0] tx_shift = 0; 50 | 51 | reg [3:0] prescale = -1; 52 | wire tx_en, frame_en; 53 | 54 | assign frame_en = prescale == 6; 55 | assign tx_en = prescale == 8; 56 | assign sample = prescale == 12; 57 | 58 | always @(posedge ck) begin 59 | 60 | if(rst) begin 61 | prescale <= 0; 62 | tx_shift <= 0; 63 | end else begin 64 | 65 | prescale <= prescale + 1; 66 | if (frame_en) begin 67 | frame_posn <= frame_posn + 1; 68 | end 69 | 70 | if (frame_en) begin 71 | tx_shift <= { tx_shift[62:0], 1'b0 }; 72 | end 73 | 74 | end 75 | 76 | end 77 | 78 | assign sd = tx_shift[63]; 79 | 80 | task send(input [23:0] l, input [23:0] r); 81 | 82 | begin 83 | wait((frame_posn == 1) && tx_en); 84 | tx_shift <= { l, 8'h0, r, 8'h0 }; 85 | wait(frame_posn == 2); 86 | end 87 | 88 | endtask 89 | 90 | initial begin 91 | 92 | $display("start i2s rx tests"); 93 | 94 | wait(!rst); 95 | @(posedge ck); 96 | 97 | // 98 | wait(frame_posn == 5); 99 | send(24'hf0f0f0, 24'hcafedb); 100 | 101 | wait(frame_posn == 0); 102 | tb_assert(left == 24'hf0f0f0); 103 | tb_assert(right == 24'hcafedb); 104 | tb_assert(left_16 == 24'hf0f0); 105 | tb_assert(right_16 == 24'hcafe); 106 | 107 | // 108 | wait(frame_posn == 5); 109 | send(24'h123456, 24'hFFFFFF); 110 | 111 | wait(frame_posn == 0); 112 | tb_assert(left == 24'h123456); 113 | tb_assert(right == 24'hFFFFFF); 114 | tb_assert(left_16 == 24'h1234); 115 | tb_assert(right_16 == 24'hFFFF); 116 | 117 | // 118 | wait(frame_posn == 5); 119 | send(24'h000000, 24'haaaaaa); 120 | 121 | wait(frame_posn == 0); 122 | tb_assert(left == 24'h000000); 123 | tb_assert(right == 24'haaaaaa); 124 | tb_assert(left_16 == 24'h0000); 125 | tb_assert(right_16 == 24'haaaa); 126 | 127 | // 128 | wait(frame_posn == 5); 129 | send(24'h555555, 24'h123456); 130 | 131 | wait(frame_posn == 0); 132 | tb_assert(left == 24'h555555); 133 | tb_assert(right == 24'h123456); 134 | tb_assert(left_16 == 24'h5555); 135 | tb_assert(right_16 == 24'h1234); 136 | 137 | $display("done"); 138 | $finish; 139 | end 140 | 141 | reg [31:0] tx_shift_32 = 0; 142 | wire [15:0] left_32; 143 | wire [15:0] right_32; 144 | wire sd_32; 145 | assign sd_32 = tx_shift_32[31]; 146 | 147 | always @(posedge ck) begin 148 | 149 | if (rst) begin 150 | tx_shift_32 <= 0; 151 | end else begin 152 | if (frame_en) begin 153 | tx_shift_32 <= { tx_shift_32[30:0], 1'b0 }; 154 | end 155 | end 156 | 157 | end 158 | 159 | i2s_rx #(.BITS(16), .CLOCKS(32)) 160 | i2s_rx_32 ( 161 | .ck(ck), 162 | .sample(sample), 163 | .frame_posn(frame_posn), 164 | .sd(sd_32), 165 | .left(left_32), 166 | .right(right_32) 167 | ); 168 | 169 | task send_32(input [15:0] l, input [15:0] r); 170 | 171 | begin 172 | wait((frame_posn == 1) && tx_en); 173 | tx_shift_32 <= { l, r }; 174 | wait(frame_posn == 2); 175 | end 176 | 177 | endtask 178 | 179 | wire [4:0] frame; 180 | assign frame = frame_posn[4:0]; 181 | 182 | initial begin 183 | 184 | $display("start i2s 32-bit rx tests"); 185 | 186 | wait(!rst); 187 | @(posedge ck); 188 | 189 | send_32(16'hface, 16'h1234); 190 | wait(frame == 18); 191 | tb_assert(left_32 == 16'hface); 192 | wait(frame == 2); 193 | tb_assert(right_32 == 16'h1234); 194 | 195 | send_32(16'hffff, 16'h0000); 196 | wait(frame == 18); 197 | tb_assert(left_32 == 16'hffff); 198 | wait(frame == 2); 199 | tb_assert(right_32 == 16'h0000); 200 | 201 | send_32(16'h0000, 16'hffff); 202 | wait(frame == 18); 203 | tb_assert(left_32 == 16'h0000); 204 | wait(frame == 2); 205 | tb_assert(right_32 == 16'hffff); 206 | 207 | send_32(16'haaaa, 16'h5555); 208 | wait(frame == 18); 209 | tb_assert(left_32 == 16'haaaa); 210 | wait(frame == 2); 211 | tb_assert(right_32 == 16'h5555); 212 | end 213 | 214 | reg [15:0] left_tx = 0; 215 | reg [15:0] right_tx = 0; 216 | wire tx; 217 | 218 | i2s_tx #(.CLOCKS(64)) 219 | tx_hw (.ck(ck), 220 | .en(sample), 221 | .frame_posn(frame_posn), 222 | .left(left_tx), 223 | .right(right_tx), 224 | .sd(tx) 225 | ); 226 | 227 | task wait_sample(input signal); 228 | 229 | begin 230 | @(posedge ck); 231 | wait(sample); 232 | @(posedge ck); 233 | wait(!sample); 234 | @(posedge ck); 235 | end 236 | 237 | endtask 238 | 239 | integer i; 240 | 241 | initial begin 242 | 243 | $display("start i2s tx tests"); 244 | 245 | left_tx <= 16'h1234; 246 | right_tx <= 16'habcd; 247 | 248 | wait(!rst); 249 | @(posedge ck); 250 | 251 | // wait for start of next frame 252 | wait(frame_posn == 'h0); 253 | @(posedge ck); 254 | wait(frame_posn == 'h1); 255 | @(posedge ck); 256 | // wait for start of next frame 257 | wait(frame_posn == 'h0); 258 | // first slot is end of prev frame 259 | wait_sample(sample); 260 | 261 | // check the tx bits 262 | // 1 263 | wait_sample(sample); 264 | tb_assert(tx == 1'b0); 265 | wait_sample(sample); 266 | tb_assert(tx == 1'b0); 267 | wait_sample(sample); 268 | tb_assert(tx == 1'b0); 269 | wait_sample(sample); 270 | tb_assert(tx == 1'b1); 271 | // 2 272 | wait_sample(sample); 273 | tb_assert(tx == 1'b0); 274 | wait_sample(sample); 275 | tb_assert(tx == 1'b0); 276 | wait_sample(sample); 277 | tb_assert(tx == 1'b1); 278 | wait_sample(sample); 279 | tb_assert(tx == 1'b0); 280 | // 3 281 | wait_sample(sample); 282 | tb_assert(tx == 1'b0); 283 | wait_sample(sample); 284 | tb_assert(tx == 1'b0); 285 | wait_sample(sample); 286 | tb_assert(tx == 1'b1); 287 | wait_sample(sample); 288 | tb_assert(tx == 1'b1); 289 | // 4 290 | wait_sample(sample); 291 | tb_assert(tx == 1'b0); 292 | wait_sample(sample); 293 | tb_assert(tx == 1'b1); 294 | wait_sample(sample); 295 | tb_assert(tx == 1'b0); 296 | wait_sample(sample); 297 | tb_assert(tx == 1'b0); 298 | 299 | // The 64-version now has 16-bits of zeros 300 | for (i = 0; i < 16; i = i + 1) begin 301 | wait_sample(sample); 302 | tb_assert(tx == 1'b0); 303 | end 304 | 305 | // A 306 | wait_sample(sample); 307 | tb_assert(tx == 1'b1); 308 | wait_sample(sample); 309 | tb_assert(tx == 1'b0); 310 | wait_sample(sample); 311 | tb_assert(tx == 1'b1); 312 | wait_sample(sample); 313 | tb_assert(tx == 1'b0); 314 | // B 315 | wait_sample(sample); 316 | tb_assert(tx == 1'b1); 317 | wait_sample(sample); 318 | tb_assert(tx == 1'b0); 319 | wait_sample(sample); 320 | tb_assert(tx == 1'b1); 321 | wait_sample(sample); 322 | tb_assert(tx == 1'b1); 323 | // C 324 | wait_sample(sample); 325 | tb_assert(tx == 1'b1); 326 | wait_sample(sample); 327 | tb_assert(tx == 1'b1); 328 | wait_sample(sample); 329 | tb_assert(tx == 1'b0); 330 | wait_sample(sample); 331 | tb_assert(tx == 1'b0); 332 | // D 333 | wait_sample(sample); 334 | tb_assert(tx == 1'b1); 335 | wait_sample(sample); 336 | tb_assert(tx == 1'b1); 337 | wait_sample(sample); 338 | tb_assert(tx == 1'b0); 339 | wait_sample(sample); 340 | tb_assert(tx == 1'b1); 341 | 342 | // The 64-version now has 16-bits of zeros 343 | for (i = 0; i < 16; i = i + 1) begin 344 | wait_sample(sample); 345 | tb_assert(tx == 1'b0); 346 | end 347 | 348 | end 349 | 350 | reg [15:0] left_tx_32 = 0; 351 | reg [15:0] right_tx_32 = 0; 352 | wire tx_32; 353 | 354 | i2s_tx #(.CLOCKS(32)) 355 | tx_hw_32 (.ck(ck), 356 | .en(sample), 357 | .frame_posn(frame_posn), 358 | .left(left_tx_32), 359 | .right(right_tx_32), 360 | .sd(tx_32) 361 | ); 362 | 363 | initial begin 364 | 365 | $display("start i2s tx 32 tests"); 366 | 367 | left_tx_32 <= 16'hdead; 368 | right_tx_32 <= 16'hface; 369 | 370 | wait(!rst); 371 | @(posedge ck); 372 | 373 | // wait for start of next frame 374 | wait(frame_posn == 'h0); 375 | @(posedge ck); 376 | wait(frame_posn == 'h1); 377 | @(posedge ck); 378 | // wait for start of next frame 379 | wait(frame_posn == 'h0); 380 | // first slot is end of prev frame 381 | wait_sample(sample); 382 | 383 | // D 384 | wait_sample(sample); 385 | tb_assert(tx_32 == 1'b1); 386 | wait_sample(sample); 387 | tb_assert(tx_32 == 1'b1); 388 | wait_sample(sample); 389 | tb_assert(tx_32 == 1'b0); 390 | wait_sample(sample); 391 | tb_assert(tx_32 == 1'b1); 392 | // E 393 | wait_sample(sample); 394 | tb_assert(tx_32 == 1'b1); 395 | wait_sample(sample); 396 | tb_assert(tx_32 == 1'b1); 397 | wait_sample(sample); 398 | tb_assert(tx_32 == 1'b1); 399 | wait_sample(sample); 400 | tb_assert(tx_32 == 1'b0); 401 | // A 402 | wait_sample(sample); 403 | tb_assert(tx_32 == 1'b1); 404 | wait_sample(sample); 405 | tb_assert(tx_32 == 1'b0); 406 | wait_sample(sample); 407 | tb_assert(tx_32 == 1'b1); 408 | wait_sample(sample); 409 | tb_assert(tx_32 == 1'b0); 410 | // D 411 | wait_sample(sample); 412 | tb_assert(tx_32 == 1'b1); 413 | wait_sample(sample); 414 | tb_assert(tx_32 == 1'b1); 415 | wait_sample(sample); 416 | tb_assert(tx_32 == 1'b0); 417 | wait_sample(sample); 418 | tb_assert(tx_32 == 1'b1); 419 | // F 420 | wait_sample(sample); 421 | tb_assert(tx_32 == 1'b1); 422 | wait_sample(sample); 423 | tb_assert(tx_32 == 1'b1); 424 | wait_sample(sample); 425 | tb_assert(tx_32 == 1'b1); 426 | wait_sample(sample); 427 | tb_assert(tx_32 == 1'b1); 428 | // A 429 | wait_sample(sample); 430 | tb_assert(tx_32 == 1'b1); 431 | wait_sample(sample); 432 | tb_assert(tx_32 == 1'b0); 433 | wait_sample(sample); 434 | tb_assert(tx_32 == 1'b1); 435 | wait_sample(sample); 436 | tb_assert(tx_32 == 1'b0); 437 | // C 438 | wait_sample(sample); 439 | tb_assert(tx_32 == 1'b1); 440 | wait_sample(sample); 441 | tb_assert(tx_32 == 1'b1); 442 | wait_sample(sample); 443 | tb_assert(tx_32 == 1'b0); 444 | wait_sample(sample); 445 | tb_assert(tx_32 == 1'b0); 446 | // E 447 | wait_sample(sample); 448 | tb_assert(tx_32 == 1'b1); 449 | wait_sample(sample); 450 | tb_assert(tx_32 == 1'b1); 451 | wait_sample(sample); 452 | tb_assert(tx_32 == 1'b1); 453 | wait_sample(sample); 454 | tb_assert(tx_32 == 1'b0); 455 | 456 | // start again ... 457 | // D 458 | wait_sample(sample); 459 | tb_assert(tx_32 == 1'b1); 460 | wait_sample(sample); 461 | tb_assert(tx_32 == 1'b1); 462 | wait_sample(sample); 463 | tb_assert(tx_32 == 1'b0); 464 | wait_sample(sample); 465 | tb_assert(tx_32 == 1'b1); 466 | 467 | end 468 | 469 | endmodule 470 | 471 | 472 | -------------------------------------------------------------------------------- /dsp/dsp.v: -------------------------------------------------------------------------------- 1 | 2 | `default_nettype none 3 | 4 | /* 5 | * 6 | */ 7 | 8 | module dsp ( 9 | input wire ext_ck, 10 | output wire tx, 11 | 12 | // XIP Flash 13 | output wire spi_sck, 14 | output wire spi_cs, 15 | output wire spi_mosi, 16 | input wire spi_miso, 17 | 18 | // sk9822 drive 19 | output wire led_ck, 20 | output wire led_data, 21 | 22 | /* verilator lint_off UNUSED */ 23 | output wire [7:0] test, 24 | 25 | // I2S 26 | output wire sck, 27 | output wire ws, 28 | // Mic in 29 | input wire sd_in0, 30 | input wire sd_in1, 31 | input wire sd_in2, 32 | input wire sd_in3, 33 | 34 | // I2S Output 35 | output wire o_sck, 36 | output wire o_ws, 37 | output wire o_sd0, 38 | output wire o_sd1, 39 | 40 | // External I2S sync input, SD output 41 | input wire ext_sck, 42 | input wire ext_ws, 43 | output wire ext_sd 44 | /* verilator lint_on UNUSED */ 45 | 46 | ); 47 | 48 | //parameter PLL_HZ = 30000000; 49 | //parameter PLL_HZ = 24000000; 50 | parameter PLL_HZ = 26250000; 51 | 52 | // Device addresses (addr[31:24]) 53 | localparam GPIO_ADDR = 8'h40; 54 | localparam UART_ADDR = 8'h50; 55 | localparam FLASH_ADDR = 8'h70; 56 | localparam IRQ_ADDR = 8'h80; 57 | localparam LED_ADDR = 8'h90; 58 | localparam TIMER_ADDR = 8'hc0; 59 | // Run code from this location in memory (Flash) 60 | localparam RESET_PC = 32'h0010_0000; 61 | 62 | localparam RUN_SLOW = 0; // Divide the CPU clock down for development 63 | localparam RESET_LOOP = 0; // Repeatedly reset the CPU 64 | localparam TIMER_ENABLED = 1; // Hardware Timer 65 | 66 | localparam CK_HZ = RUN_SLOW ? (PLL_HZ/16) : PLL_HZ; 67 | 68 | // PLL 69 | wire pll_ck; 70 | /* verilator lint_off UNUSED */ 71 | wire locked; 72 | /* verilator lint_on UNUSED */ 73 | pll clock(.clock_in(ext_ck), .clock_out(pll_ck), .locked(locked)); 74 | 75 | // Conditonally slow the cpu clock down for development. 76 | generate 77 | wire ck; 78 | if (RUN_SLOW) begin 79 | reg [3:0] scale = 0; 80 | 81 | always @(posedge pll_ck) begin 82 | scale <= scale + 1; 83 | end 84 | 85 | assign ck = scale[3]; 86 | end else begin 87 | assign ck = pll_ck; 88 | end 89 | endgenerate 90 | 91 | // Reset generator 92 | wire reset_req; 93 | wire rst; 94 | 95 | reset #(.LENGTH(80)) reset_(.ck(ck), .rst_req(reset_req), .rst(rst)); 96 | 97 | // Continually Reset the cpu (for development) 98 | 99 | generate 100 | if (RESET_LOOP) begin 101 | reg [(RUN_SLOW ? 21 : 24):0] reseter = 0; 102 | 103 | always @(posedge ck) begin 104 | reseter <= reseter + 1; 105 | end 106 | 107 | assign reset_req = reseter == 0; 108 | end else begin 109 | assign reset_req = 0; 110 | end 111 | endgenerate 112 | 113 | // CPU dbus 114 | 115 | wire [31:0] wb_dbus_adr; 116 | wire [31:0] wb_dbus_dat; 117 | wire [31:0] wb_dbus_rdt; 118 | wire [3:0] wb_dbus_sel; 119 | wire wb_dbus_we; 120 | wire wb_dbus_cyc; 121 | wire wb_dbus_ack; 122 | 123 | // CPU ibus 124 | 125 | wire wb_clk; 126 | wire wb_rst; 127 | wire [31:0] wb_ibus_adr; 128 | wire [31:0] wb_ibus_rdt; 129 | wire wb_ibus_cyc; 130 | wire wb_ibus_ack; 131 | 132 | assign wb_clk = ck; 133 | assign wb_rst = rst; 134 | 135 | // RAM 136 | 137 | wire ram_ack; 138 | wire [31:0] ram_rdt; 139 | 140 | // DMA from DSP, connected to port B of ram_arb 141 | 142 | /* verilator lint_off UNUSED */ 143 | wire dma_cyc; 144 | wire dma_we; 145 | wire [3:0] dma_sel; 146 | wire [31:0] dma_adr; 147 | wire [31:0] dma_dat; 148 | wire dma_ack; 149 | wire [31:0] dma_rdt; 150 | /* verilator lint_on UNUSED */ 151 | 152 | // Output Port X of ram_arb 153 | wire x_cyc; 154 | wire x_we; 155 | wire [3:0] x_sel; 156 | wire [31:0] x_adr; 157 | wire [31:0] x_dat; 158 | wire [31:0] x_rdt; 159 | wire x_ack; 160 | 161 | `ifdef USE_DMA 162 | 163 | ram_arb # (.WIDTH(32)) 164 | ram_arb 165 | ( 166 | .wb_clk(wb_clk), 167 | .a_cyc(wb_dbus_cyc), 168 | .a_we(wb_dbus_we), 169 | .a_sel(wb_dbus_sel), 170 | .a_adr(wb_dbus_adr), 171 | .a_dat(wb_dbus_dat), 172 | .a_ack(ram_ack), 173 | .a_rdt(ram_rdt), 174 | .b_cyc(dma_cyc), 175 | .b_we(dma_we), 176 | .b_sel(dma_sel), 177 | .b_adr(dma_adr), 178 | .b_dat(dma_dat), 179 | .b_ack(dma_ack), 180 | .b_rdt(dma_rdt), 181 | .x_cyc(x_cyc), 182 | .x_we(x_we), 183 | .x_sel(x_sel), 184 | .x_adr(x_adr), 185 | .x_dat(x_dat), 186 | .x_ack(x_ack), 187 | .x_rdt(x_rdt) 188 | ); 189 | 190 | `else // USE_DMA 191 | 192 | assign ram_ack = x_ack; 193 | assign ram_rdt = x_rdt; 194 | assign dma_ack = 0; 195 | assign dma_rdt = 0; 196 | assign x_cyc = wb_dbus_cyc; 197 | assign x_we = wb_dbus_we; 198 | assign x_sel = wb_dbus_sel; 199 | assign x_adr = wb_dbus_adr; 200 | assign x_dat = wb_dbus_dat; 201 | // ... 202 | 203 | `endif // USE_DMA 204 | 205 | // Dbus RAM 206 | 207 | wire ram_cs; 208 | 209 | chip_select #(.ADDR(0), .WIDTH(8)) 210 | cs_ram ( 211 | .wb_ck(wb_clk), 212 | .addr(x_adr[31:24]), 213 | .wb_cyc(x_cyc), 214 | .wb_rst(wb_rst), 215 | .ack(x_ack), 216 | .cyc(ram_cs) 217 | ); 218 | 219 | sp_ram ram ( 220 | .ck(wb_clk), 221 | .addr(x_adr), 222 | .cyc(ram_cs), 223 | .we(x_we), 224 | .sel(x_sel), 225 | .wdata(x_dat), 226 | .rdata(x_rdt) 227 | ); 228 | 229 | // Risc-V 64-bit Timer 230 | 231 | wire timer_ack; 232 | wire timer_irq; 233 | wire [31:0] timer_rdt; 234 | 235 | generate 236 | 237 | if (TIMER_ENABLED) begin 238 | 239 | wire timer_cyc; 240 | 241 | chip_select #(.ADDR(TIMER_ADDR), .WIDTH(8)) 242 | cs_timer ( 243 | .wb_ck(wb_clk), 244 | .addr(wb_dbus_adr[31:24]), 245 | .wb_cyc(wb_dbus_cyc), 246 | .wb_rst(wb_rst), 247 | .ack(timer_ack), 248 | .cyc(timer_cyc) 249 | ); 250 | 251 | timer timer ( 252 | .wb_clk(wb_clk), 253 | .wb_rst(wb_rst), 254 | .ck_en(1'b1), // no prescale 255 | .wb_dbus_dat(wb_dbus_dat), 256 | .wb_dbus_adr(wb_dbus_adr), 257 | .wb_dbus_we(wb_dbus_we), 258 | .cyc(timer_cyc), 259 | .irq(timer_irq), 260 | .rdt(timer_rdt) 261 | ); 262 | 263 | end else begin 264 | 265 | // No timer hardware 266 | assign timer_ack = 0; 267 | assign timer_irq = 0; 268 | assign timer_rdt = 0; 269 | 270 | end 271 | endgenerate 272 | 273 | // UART 274 | 275 | wire baud_en; 276 | 277 | localparam BAUD = CK_HZ / 115200; 278 | uart_baud #(.DIVIDE(BAUD)) uart_clock (.ck(wb_clk), .baud_ck(baud_en)); 279 | 280 | wire [31:0] uart_rdt; 281 | wire uart_ack; 282 | /* verilator lint_off UNUSED */ 283 | wire tx_busy; 284 | /* verilator lint_on UNUSED */ 285 | 286 | uart #(.ADDR(UART_ADDR), .AWIDTH(8)) 287 | uart_io ( 288 | // cpu bus 289 | .wb_clk(wb_clk), 290 | .wb_rst(wb_rst), 291 | .wb_dbus_adr(wb_dbus_adr), 292 | .wb_dbus_dat(wb_dbus_dat), 293 | .wb_dbus_sel(wb_dbus_sel), 294 | .wb_dbus_we(wb_dbus_we), 295 | .wb_dbus_cyc(wb_dbus_cyc), 296 | .rdt(uart_rdt), 297 | .ack(uart_ack), 298 | // IO 299 | .baud_en(baud_en), 300 | .tx(tx), 301 | .busy(tx_busy) 302 | ); 303 | 304 | // GPIO 305 | 306 | wire [31:0] gpio_rdt; 307 | wire gpio_ack; 308 | 309 | /* verilator lint_off UNUSED */ 310 | wire [7:0] gpio_reg; 311 | /* verilator lint_on UNUSED */ 312 | 313 | gpio #(.ADDR(GPIO_ADDR), .AWIDTH(8)) 314 | gpio_io ( 315 | // cpu bus 316 | .wb_clk(wb_clk), 317 | .wb_rst(wb_rst), 318 | .wb_dbus_adr(wb_dbus_adr), 319 | .wb_dbus_dat(wb_dbus_dat), 320 | .wb_dbus_sel(wb_dbus_sel), 321 | .wb_dbus_we(wb_dbus_we), 322 | .wb_dbus_cyc(wb_dbus_cyc), 323 | .rdt(gpio_rdt), 324 | .ack(gpio_ack), 325 | // IO 326 | .gpio(gpio_reg) 327 | ); 328 | 329 | `ifdef USE_SK9822 330 | 331 | // sk9822 LED driver 332 | 333 | wire led_ack; 334 | 335 | sk9822_peripheral #(.ADDR(LED_ADDR)) 336 | sk9822_peripheral( 337 | .wb_clk(wb_clk), 338 | .wb_rst(wb_rst), 339 | .wb_dbus_cyc(wb_dbus_cyc), 340 | .wb_dbus_we(wb_dbus_we), 341 | .wb_dbus_adr(wb_dbus_adr), 342 | .wb_dbus_dat(wb_dbus_dat), 343 | .ack(led_ack), 344 | .led_ck(led_ck), 345 | .led_data(led_data) 346 | ); 347 | 348 | `else 349 | 350 | wire led_ack; 351 | assign led_ack = 0; 352 | assign led_ck = 0; 353 | assign led_data = 0; 354 | 355 | `endif // USE_SK9822 356 | 357 | // SPI Flash interface 358 | 359 | // flash_read connection to ibus arb 360 | wire [31:0] f_adr; 361 | wire [31:0] f_rdt; 362 | wire f_cyc; 363 | wire f_ack; 364 | // flash_read dbus arb 365 | wire flash_ack; 366 | wire [31:0] flash_rdt; 367 | /* verilator lint_off UNUSED */ 368 | wire flash_busy; 369 | /* verilator lint_on UNUSED */ 370 | 371 | ibus_read #(.ADDR(FLASH_ADDR)) 372 | flash_read ( 373 | .wb_clk(wb_clk), 374 | .wb_rst(wb_rst), 375 | .wb_dbus_cyc(wb_dbus_cyc), 376 | .wb_dbus_we(wb_dbus_we), 377 | .wb_dbus_adr(wb_dbus_adr), 378 | .wb_dbus_dat(wb_dbus_dat), 379 | .wb_dbus_ack(flash_ack), 380 | .wb_dbus_rdt(flash_rdt), 381 | .wb_ibus_cyc(f_cyc), 382 | .wb_ibus_adr(f_adr), 383 | .wb_ibus_ack(f_ack), 384 | .wb_ibus_rdt(f_rdt), 385 | .dev_busy(flash_busy) 386 | ); 387 | 388 | // SPI flash ibus interface 389 | // Run XiP over this 390 | 391 | wire [31:0] s_adr; 392 | wire [31:0] s_rdt; 393 | wire s_cyc; 394 | wire s_ack; 395 | /* verilator lint_off UNUSED */ 396 | wire ibus_ready; 397 | /* verilator lint_on UNUSED */ 398 | 399 | ibus ibus ( 400 | .wb_clk(ck), 401 | .wb_rst(rst), 402 | // iBus interface 403 | .wb_ibus_adr(s_adr), 404 | .wb_ibus_rdt(s_rdt), 405 | .wb_ibus_cyc(s_cyc), 406 | .wb_ibus_ack(s_ack), 407 | // SPI interface 408 | .spi_cs(spi_cs), 409 | .spi_sck(spi_sck), 410 | .spi_miso(spi_miso), 411 | .spi_mosi(spi_mosi), 412 | .ready(ibus_ready) 413 | ); 414 | 415 | // iBus arbitration between CPU and flash_read 416 | 417 | /* verilator lint_off UNUSED */ 418 | wire arb_busy; 419 | /* verilator lint_on UNUSED */ 420 | 421 | bus_arb ibus_arb( 422 | .wb_clk(ck), 423 | // CPU is the priority channel 424 | .a_cyc(wb_ibus_cyc), 425 | .a_adr(wb_ibus_adr), 426 | .a_ack(wb_ibus_ack), 427 | .a_rdt(wb_ibus_rdt), 428 | // Flash_read at a lower priority 429 | .b_cyc(f_cyc), 430 | .b_adr(f_adr), 431 | .b_ack(f_ack), 432 | .b_rdt(f_rdt), 433 | // Connect to the ibus SPI controller 434 | .x_cyc(s_cyc), 435 | .x_adr(s_adr), 436 | .x_ack(s_ack), 437 | .x_rdt(s_rdt), 438 | .busy(arb_busy) 439 | ); 440 | 441 | /* 442 | * Audio Engine 443 | */ 444 | 445 | `ifdef USE_AUDIO_ENGINE 446 | 447 | wire engine_ack; 448 | wire [31:0] engine_rdt; 449 | 450 | /* verilator lint_off UNUSED */ 451 | wire audio_ready; 452 | /* verilator lint_on UNUSED */ 453 | wire dma_done; 454 | wire dma_match; 455 | 456 | assign o_sck = sck; 457 | assign o_ws = ws; 458 | assign ext_sd = o_sd0; 459 | 460 | audio_engine #(.CK_HZ(CK_HZ)) audio_engine( 461 | .ck(ck), 462 | .wb_rst(wb_rst), 463 | .wb_dbus_cyc(wb_dbus_cyc), 464 | .wb_dbus_sel(wb_dbus_sel), 465 | .wb_dbus_we(wb_dbus_we), 466 | .wb_dbus_adr(wb_dbus_adr), 467 | .wb_dbus_dat(wb_dbus_dat), 468 | .ack(engine_ack), 469 | .rdt(engine_rdt), 470 | 471 | .dma_cyc(dma_cyc), 472 | .dma_we(dma_we), 473 | .dma_sel(dma_sel), 474 | .dma_adr(dma_adr), 475 | .dma_dat(dma_dat), 476 | .dma_ack(dma_ack), 477 | .dma_rdt(dma_rdt), 478 | .dma_done(dma_done), 479 | .dma_match(dma_match), 480 | 481 | .sck(sck), 482 | .ws(ws), 483 | .sd_out0(o_sd0), 484 | .sd_out1(o_sd1), 485 | .sd_in0(sd_in0), 486 | .sd_in1(sd_in1), 487 | .sd_in2(sd_in2), 488 | .sd_in3(sd_in3), 489 | 490 | .ext_sck(ext_sck), 491 | .ext_ws(ext_ws), 492 | 493 | .ready(audio_ready), 494 | .test(test) 495 | ); 496 | 497 | `else 498 | 499 | wire dma_match; 500 | wire dma_done; 501 | wire engine_ack; 502 | wire [31:0] engine_rdt; 503 | 504 | assign engine_ack = 0; 505 | assign engine_rdt = 0; 506 | assign dma_done = 0; 507 | assign dma_match = 0; 508 | 509 | // Outputs all driven lo 510 | assign test = 0; 511 | assign sck = 0; 512 | assign ws = 0; 513 | assign o_sck = 0; 514 | assign o_ws = 0; 515 | assign o_sd = 0; 516 | assign ext_sd = 0; 517 | 518 | `endif 519 | 520 | // Interrupt controller 521 | 522 | wire irq_ack; 523 | wire [31:0] irq_rdt; 524 | 525 | wire [2:0] irqs; 526 | assign irqs = { dma_match, dma_done, timer_irq }; 527 | 528 | wire soc_irq; 529 | 530 | irq_reg #(.ADDR(IRQ_ADDR), .ADDR_W(8), .REG_WIDTH(3)) 531 | irq_reg 532 | ( 533 | .wb_clk(wb_clk), 534 | .wb_rst(wb_rst), 535 | .wb_dbus_adr(wb_dbus_adr), 536 | .wb_dbus_dat(wb_dbus_dat), 537 | .wb_dbus_we(wb_dbus_we), 538 | .wb_dbus_cyc(wb_dbus_cyc), 539 | .ack(irq_ack), 540 | .rdt(irq_rdt), 541 | .irq_in(irqs), 542 | .irq(soc_irq) 543 | ); 544 | 545 | // OR the dbus peripherals *_rdt & *_ack together 546 | // They must be 0 when not active. 547 | 548 | assign wb_dbus_rdt = irq_rdt | timer_rdt | ram_rdt | uart_rdt | gpio_rdt | flash_rdt | engine_rdt; 549 | assign wb_dbus_ack = irq_ack | timer_ack | ram_ack | uart_ack | gpio_ack | flash_ack | engine_ack | led_ack; 550 | 551 | // SERV CPU 552 | 553 | parameter with_csr = 1; 554 | 555 | serv_rf_top #(.RESET_PC(RESET_PC), .WITH_CSR(with_csr)) 556 | cpu ( 557 | .clk(wb_clk), 558 | .i_rst(wb_rst), 559 | .i_timer_irq(soc_irq), 560 | // iBus 561 | .o_ibus_adr(wb_ibus_adr), 562 | .o_ibus_cyc(wb_ibus_cyc), 563 | .i_ibus_rdt(wb_ibus_rdt), 564 | .i_ibus_ack(wb_ibus_ack), 565 | // dBus 566 | .o_dbus_adr(wb_dbus_adr), 567 | .o_dbus_dat(wb_dbus_dat), 568 | .o_dbus_sel(wb_dbus_sel), 569 | .o_dbus_we(wb_dbus_we), 570 | .o_dbus_cyc(wb_dbus_cyc), 571 | .i_dbus_rdt(wb_dbus_rdt), 572 | .i_dbus_ack(wb_dbus_ack) 573 | ); 574 | 575 | endmodule 576 | -------------------------------------------------------------------------------- /dsp/audio_engine.v: -------------------------------------------------------------------------------- 1 | 2 | `default_nettype none 3 | 4 | module i2s_offset 5 | #(parameter WIDTH=4) 6 | ( 7 | input wire ck, 8 | input wire i2s_en, 9 | input wire [WIDTH-1:0] offset, 10 | output wire en 11 | ); 12 | 13 | reg [WIDTH-1:0] counter = 0; 14 | 15 | always @(posedge ck) begin 16 | 17 | if (i2s_en) begin 18 | counter <= 0; 19 | end else begin 20 | counter <= counter + 1; 21 | end 22 | 23 | end 24 | 25 | assign en = offset == counter; 26 | 27 | 28 | endmodule 29 | 30 | /* 31 | * Audio Perihperal 32 | */ 33 | 34 | module audio_engine ( 35 | input wire ck, 36 | 37 | // CPU bus interface 38 | input wire wb_rst, 39 | input wire wb_dbus_cyc, 40 | output wire ack, 41 | input wire wb_dbus_we, 42 | /* verilator lint_off UNUSED */ 43 | input wire [3:0] wb_dbus_sel, 44 | input wire [31:0] wb_dbus_adr, 45 | /* verilator lint_on UNUSED */ 46 | input wire [31:0] wb_dbus_dat, 47 | output wire [31:0] rdt, 48 | 49 | // DMA interface 50 | output reg dma_cyc, 51 | output reg dma_we, 52 | output reg [3:0] dma_sel, 53 | output reg [31:0] dma_adr, 54 | output reg [31:0] dma_dat, 55 | /* verilator lint_off UNUSED */ 56 | input wire dma_ack, 57 | input wire [31:0] dma_rdt, 58 | /* verilator lint_on UNUSED */ 59 | // DMA status 60 | output wire dma_done, 61 | output wire dma_match, 62 | 63 | // I2S interface 64 | output wire sck, // I2S clock 65 | output wire ws, // I2S word select 66 | output wire sd_out0, // I2S data out 67 | output wire sd_out1, // I2S data out 68 | input wire sd_in0, // I2S data in 69 | input wire sd_in1, // I2S data in 70 | input wire sd_in2, // I2S data in 71 | input wire sd_in3, // I2S data in 72 | 73 | input wire ext_sck, // I2S ext sync 74 | input wire ext_ws, // I2S ext sync 75 | 76 | output wire ready, 77 | output wire [7:0] test 78 | ); 79 | 80 | parameter CK_HZ = 32000000; 81 | 82 | parameter ADDR = 8'h60; 83 | 84 | localparam ADDR_COEF = ADDR; 85 | localparam ADDR_RESULT = ADDR + 8'h01; 86 | localparam ADDR_STATUS = ADDR + 8'h02; 87 | localparam ADDR_INPUT = ADDR + 8'h04; 88 | localparam ADDR_DMA = ADDR + 8'h05; 89 | 90 | localparam CHANNELS = 8; 91 | localparam FRAMES = 256; 92 | 93 | localparam CODE = 256; // but there are 2 banks of this 94 | localparam CODE_W = $clog2(CODE); 95 | localparam COEF_W = CODE_W + 1; // includes 2 banks 96 | 97 | localparam CHAN_W = $clog2(CHANNELS); 98 | localparam FRAME_W = $clog2(FRAMES); 99 | localparam AUDIO = CHANNELS * FRAMES; 100 | localparam AUDIO_W = $clog2(AUDIO); 101 | 102 | // Send an extended reset pulse to the audio engine 103 | 104 | reg [1:0] resetx = 0; 105 | reg reset_req = 0; 106 | 107 | always @(posedge ck) begin 108 | if (reset_req || frame_reset_req) begin 109 | resetx <= 0; 110 | end else begin 111 | if (resetx != 2'b10) begin 112 | resetx <= resetx + 1; 113 | end 114 | end 115 | end 116 | 117 | wire reset; 118 | assign reset = !((!wb_rst) && (resetx == 2'b10)); 119 | 120 | reg [(FRAME_W-1):0] frame_counter = 0; 121 | wire [(FRAME_W-1):0] frame; 122 | 123 | // Control Register 124 | 125 | reg [FRAME_W-1:0] control_reg_frame = 0; 126 | reg allow_audio_writes = 0; 127 | 128 | assign frame = allow_audio_writes ? control_reg_frame : frame_counter; 129 | 130 | // I2S clock generation 131 | 132 | wire i2s_clock; 133 | 134 | // Divide the clock down to 2MHz 135 | // Gives 2e6/64 = 31250 Hz frame rate 136 | /* verilator lint_off WIDTH */ 137 | //localparam [4:0] I2S_DIVIDER = CK_HZ / (64 * 31250); 138 | `ifdef MAKE_HIFI 139 | localparam [5:0] I2S_DIVIDER = 20; // CK_HZ / (32 * 41100); 140 | `endif 141 | /* verilator lint_on WIDTH */ 142 | assign i2s_clock = ck; 143 | 144 | wire [5:0] frame_posn; 145 | wire i2s_en; 146 | wire i2s_external; 147 | 148 | i2s_dual #(.DIVIDER(I2S_DIVIDER)) 149 | i2s_dual( 150 | .ck(i2s_clock), 151 | .rst(wb_rst), 152 | .ext_sck(ext_sck), 153 | .ext_ws(ext_ws), 154 | .en(i2s_en), 155 | .sck(sck), 156 | .ws(ws), 157 | .frame_posn(frame_posn), 158 | .external(i2s_external) 159 | ); 160 | 161 | wire start_of_frame; 162 | assign start_of_frame = ws & (frame_posn == 0); 163 | 164 | // I2S Input 165 | 166 | reg writing = 0; 167 | reg frame_reset_req = 0; 168 | reg [(CHAN_W-1):0] chan_addr = 0; 169 | wire [(AUDIO_W-1):0] write_addr; 170 | wire write_en; 171 | wire [15:0] write_data; 172 | 173 | assign write_addr = { chan_addr, frame_counter }; 174 | assign write_data = writing ? mic_source(chan_addr) : 0; 175 | assign write_en = writing; 176 | 177 | localparam MIC_W = 24; 178 | 179 | /* verilator lint_off UNUSED */ 180 | wire [MIC_W-1:0] mic_0; 181 | wire [MIC_W-1:0] mic_1; 182 | wire [MIC_W-1:0] mic_2; 183 | wire [MIC_W-1:0] mic_3; 184 | wire [MIC_W-1:0] mic_4; 185 | wire [MIC_W-1:0] mic_5; 186 | wire [MIC_W-1:0] mic_6; 187 | wire [MIC_W-1:0] mic_7; 188 | /* verilator lint_on UNUSED */ 189 | 190 | // Delay the I2S data input sample point from the start of the clock 191 | wire i2s_in_sample; 192 | wire i2s_out_sample; 193 | reg [3:0] i2s_in_offset = 0; 194 | reg [3:0] i2s_out_offset = 0; 195 | 196 | i2s_offset #(.WIDTH(4)) 197 | i2s_offset_in( 198 | .ck(ck), 199 | .i2s_en(i2s_en), 200 | .offset(i2s_in_offset), 201 | .en(i2s_in_sample) 202 | ); 203 | 204 | i2s_offset #(.WIDTH(4)) 205 | i2s_offset_out( 206 | .ck(ck), 207 | .i2s_en(i2s_en), 208 | .offset(i2s_out_offset), 209 | .en(i2s_out_sample) 210 | ); 211 | 212 | `ifdef MAKE_HIFI 213 | localparam I2S_BITS = 32; 214 | `endif 215 | `ifdef MAKE_DSP 216 | localparam I2S_BITS = 64; 217 | `endif 218 | 219 | i2s_rx #(.BITS(MIC_W), .CLOCKS(I2S_BITS)) 220 | rx_0(.ck(ck), .sample(i2s_in_sample), 221 | .frame_posn(frame_posn), .sd(sd_in0), .left(mic_0), .right(mic_1)); 222 | i2s_rx #(.BITS(MIC_W), .CLOCKS(I2S_BITS)) 223 | rx_1(.ck(ck), .sample(i2s_in_sample), 224 | .frame_posn(frame_posn), .sd(sd_in1), .left(mic_2), .right(mic_3)); 225 | i2s_rx #(.BITS(MIC_W), .CLOCKS(I2S_BITS)) 226 | rx_2(.ck(ck), .sample(i2s_in_sample), 227 | .frame_posn(frame_posn), .sd(sd_in2), .left(mic_4), .right(mic_5)); 228 | i2s_rx #(.BITS(MIC_W), .CLOCKS(I2S_BITS)) 229 | rx_3(.ck(ck), .sample(i2s_in_sample), 230 | .frame_posn(frame_posn), .sd(sd_in3), .left(mic_6), .right(mic_7)); 231 | 232 | // I2S Output 233 | 234 | reg [15:0] left_0 = 0; 235 | reg [15:0] right_0 = 0; 236 | reg [15:0] left_1 = 0; 237 | reg [15:0] right_1 = 0; 238 | 239 | i2s_tx #(.CLOCKS(I2S_BITS)) tx_0( 240 | .ck(ck), 241 | .en(i2s_out_sample), 242 | .frame_posn(frame_posn), 243 | .left(left_0), 244 | .right(right_0), 245 | .sd(sd_out0) 246 | ); 247 | 248 | i2s_tx #(.CLOCKS(I2S_BITS)) tx_1( 249 | .ck(ck), 250 | .en(i2s_out_sample), 251 | .frame_posn(frame_posn), 252 | .left(left_1), 253 | .right(right_1), 254 | .sd(sd_out1) 255 | ); 256 | 257 | // Write Input data to the Audio RAM 258 | // 259 | // At start_of_frame the mic_x input from the I2S input 260 | // is written into the audio RAM. 261 | // 262 | // The sequencer is then reset to start the DSP command sequence. 263 | 264 | function [15:0] get_source(input [2:0] chan, 265 | input [15:0] s0, 266 | input [15:0] s1, 267 | input [15:0] s2, 268 | input [15:0] s3, 269 | input [15:0] s4, 270 | input [15:0] s5, 271 | input [15:0] s6, 272 | input [15:0] s7 273 | ); 274 | 275 | begin 276 | case (chan) 277 | 0 : get_source = s0; 278 | 1 : get_source = s1; 279 | 2 : get_source = s2; 280 | 3 : get_source = s3; 281 | 4 : get_source = s4; 282 | 5 : get_source = s5; 283 | 6 : get_source = s6; 284 | 7 : get_source = s7; 285 | endcase 286 | end 287 | 288 | endfunction 289 | 290 | localparam MIC_SHIFT = 0; 291 | localparam MIC_HI = MIC_W-(1+MIC_SHIFT); 292 | localparam MIC_LO = MIC_W-(16+MIC_SHIFT); 293 | 294 | function [15:0] mic_source(input [(CHAN_W-1):0] chan); 295 | 296 | begin 297 | mic_source = get_source(chan, 298 | mic_0[MIC_HI:MIC_LO], 299 | mic_1[MIC_HI:MIC_LO], 300 | mic_2[MIC_HI:MIC_LO], 301 | mic_3[MIC_HI:MIC_LO], 302 | mic_4[MIC_HI:MIC_LO], 303 | mic_5[MIC_HI:MIC_LO], 304 | mic_6[MIC_HI:MIC_LO], 305 | mic_7[MIC_HI:MIC_LO] 306 | ); 307 | end 308 | 309 | endfunction 310 | 311 | // Write microphone data into DP_RAM 312 | 313 | always @(posedge ck) begin 314 | // Check that the host processor isn't in write mode 315 | if (!allow_audio_writes) begin 316 | 317 | if (start_of_frame) begin 318 | chan_addr <= 0; 319 | writing <= 1; 320 | frame_counter <= frame_counter - 1; 321 | end else begin 322 | chan_addr <= chan_addr + 1; 323 | end 324 | 325 | /* verilator lint_off WIDTH */ 326 | if (writing && (chan_addr == (CHANNELS-1))) begin 327 | writing <= 0; 328 | frame_reset_req <= 1; 329 | end 330 | /* verilator lint_on WIDTH */ 331 | 332 | if (frame_reset_req) 333 | frame_reset_req <= 0; 334 | 335 | end 336 | end 337 | 338 | // Drive the engine 339 | 340 | wire [7:0] cs_adr; 341 | assign cs_adr = wb_dbus_adr[31:24]; 342 | 343 | wire coef_ack, coef_cyc; 344 | 345 | chip_select #(.ADDR(ADDR_COEF)) 346 | cs_coef( 347 | .wb_ck(ck), 348 | .addr(cs_adr), 349 | .wb_cyc(wb_dbus_cyc), 350 | .wb_rst(wb_rst), 351 | .ack(coef_ack), 352 | .cyc(coef_cyc) 353 | ); 354 | 355 | // Coefficient / Program DP RAM 356 | // This is written to by the host, read by the engine. 357 | 358 | wire [CODE_W-1:0] code_raddr; 359 | 360 | wire coef_we; 361 | wire [31:0] coef_rdata; 362 | wire [COEF_W-1:0] coef_waddr; 363 | wire [COEF_W-1:0] coef_raddr; 364 | 365 | reg bank_addr = 0; 366 | reg bank_done = 0; 367 | 368 | assign coef_we = wb_dbus_we & coef_cyc; 369 | assign coef_waddr = { !bank_addr, wb_dbus_adr[CODE_W+2-1:2] }; 370 | assign coef_raddr = { bank_addr, code_raddr }; 371 | 372 | dpram #(.BITS(32), .SIZE(CODE*2)) 373 | coef ( 374 | .ck(ck), 375 | .we(coef_we), 376 | .waddr(coef_waddr), 377 | .wdata(wb_dbus_dat), 378 | .re(1'h1), 379 | .raddr(coef_raddr), 380 | .rdata(coef_rdata) 381 | ); 382 | 383 | // Audio Input DP RAM 384 | // Audio Input data is written into this RAM 385 | // and read out by the audio engine. 386 | 387 | wire input_ack, input_cyc; 388 | 389 | chip_select #(.ADDR(ADDR_INPUT)) 390 | cs_input( 391 | .wb_ck(ck), 392 | .addr(cs_adr), 393 | .wb_cyc(wb_dbus_cyc), 394 | .wb_rst(wb_rst), 395 | .ack(input_ack), 396 | .cyc(input_cyc) 397 | ); 398 | 399 | wire [15:0] audio_wdata; 400 | wire [(AUDIO_W-1):0] audio_waddr; 401 | wire [15:0] audio_rdata; 402 | wire [(AUDIO_W-1):0] audio_raddr; 403 | 404 | wire input_we; 405 | assign input_we = wb_dbus_we & input_cyc; 406 | 407 | wire audio_we; 408 | // allow audio writes from I2S input or from host processor 409 | assign audio_we = allow_audio_writes ? input_we : write_en; 410 | assign audio_waddr = allow_audio_writes ? wb_dbus_adr[(AUDIO_W+2-1):2] : write_addr; 411 | assign audio_wdata = allow_audio_writes ? wb_dbus_dat[15:0] : write_data; 412 | 413 | dpram #(.BITS(16), .SIZE(AUDIO)) 414 | audio_in (.ck(ck), 415 | .we(audio_we), 416 | .waddr(audio_waddr), 417 | .wdata(audio_wdata), 418 | .re(1'h1), 419 | .raddr(audio_raddr), 420 | .rdata(audio_rdata) 421 | ); 422 | 423 | // Sequencer : main DSP Engine 424 | 425 | wire [(CHAN_W-1):0] seq_wr_addr; 426 | wire [15:0] seq_audio; 427 | wire seq_we; 428 | wire error; 429 | wire seq_done; 430 | wire [31:0] capture; 431 | 432 | sequencer #(.CHAN_W(CHAN_W), .FRAME_W(FRAME_W), .AUDIO_W(AUDIO_W), .CODE_W(CODE_W)) 433 | seq ( 434 | .ck(ck), 435 | .rst(reset), 436 | .frame(frame), 437 | .coef_addr(code_raddr), 438 | .coef_data(coef_rdata), 439 | .audio_raddr(audio_raddr), 440 | .audio_in(audio_rdata), 441 | .out_addr(seq_wr_addr), 442 | .out_audio(seq_audio), 443 | .out_we(seq_we), 444 | .done(seq_done), 445 | .error(error), 446 | .capture_out(capture) 447 | ); 448 | 449 | // write sequencer output to the left & right output registers 450 | 451 | localparam LCHAN_0 = 0; 452 | localparam RCHAN_0 = 1; 453 | localparam LCHAN_1 = 2; 454 | localparam RCHAN_1 = 3; 455 | 456 | always @(posedge ck) begin 457 | if (seq_we) begin 458 | 459 | case (seq_wr_addr[1:0]) 460 | LCHAN_0 : left_0 <= seq_audio; 461 | RCHAN_0 : right_0 <= seq_audio; 462 | LCHAN_1 : left_1 <= seq_audio; 463 | RCHAN_1 : right_1 <= seq_audio; 464 | endcase 465 | 466 | end 467 | end 468 | 469 | wire done; 470 | assign done = seq_done; 471 | 472 | // Write Results to DP_RAM. 473 | // 474 | // Sequencer output is written to addr 0..7 475 | 476 | wire [CHAN_W:0] result_raddr; 477 | 478 | assign result_raddr = wb_dbus_adr[(CHAN_W+2):2]; 479 | 480 | wire result_ack, result_cyc; 481 | 482 | wire [CHAN_W:0] result_waddr; 483 | wire [15:0] result_wdata; 484 | wire result_we; 485 | 486 | assign result_we = seq_we; 487 | assign result_waddr = { 1'b0, seq_wr_addr }; 488 | assign result_wdata = seq_audio; 489 | 490 | chip_select #(.ADDR(ADDR_RESULT)) 491 | cs_result( 492 | .wb_ck(ck), 493 | .addr(cs_adr), 494 | .wb_cyc(wb_dbus_cyc), 495 | .wb_rst(wb_rst), 496 | .ack(result_ack), 497 | .cyc(result_cyc) 498 | ); 499 | 500 | wire [15:0] result_out; 501 | 502 | dpram #(.BITS(16), .SIZE(CHANNELS*2)) 503 | audio_out (.ck(ck), 504 | .we(result_we), 505 | .waddr(result_waddr), 506 | .wdata(result_wdata), 507 | .re(!wb_dbus_we), 508 | .raddr(result_raddr), 509 | .rdata(result_out) 510 | ); 511 | 512 | wire [31:0] result_rdt; 513 | 514 | assign result_rdt = (result_cyc & !wb_dbus_we) ? { 16'h0, result_out } : 0; 515 | 516 | // Read / Write the control reg 517 | // 518 | // Provides : 0 control_reg r/w 519 | // 1 status_reg r 520 | // 2 capture_reg r 521 | // 3 end_of_cmd w 522 | // 4 i2s_offsets r/w 523 | 524 | wire status_ack, status_cyc; 525 | 526 | chip_select #(.ADDR(ADDR_STATUS)) 527 | cs_status( 528 | .wb_ck(ck), 529 | .addr(cs_adr), 530 | .wb_cyc(wb_dbus_cyc), 531 | .wb_rst(wb_rst), 532 | .ack(status_ack), 533 | .cyc(status_cyc) 534 | ); 535 | 536 | wire [2:0] status_addr; 537 | wire status_we; 538 | wire status_re; 539 | 540 | assign status_addr = wb_dbus_adr[4:2]; 541 | assign status_we = status_cyc & wb_dbus_we; 542 | assign status_re = status_cyc & !wb_dbus_we; 543 | 544 | always @(posedge ck) begin 545 | 546 | if (status_we & (status_addr == 0)) begin 547 | allow_audio_writes <= wb_dbus_dat[0]; 548 | control_reg_frame <= wb_dbus_dat[FRAME_W+2-1:2]; 549 | end 550 | 551 | if (status_we & (status_addr == 3)) begin 552 | // End of Command request : ie request bank switch 553 | bank_done <= 0; 554 | if (allow_audio_writes) begin 555 | reset_req <= 1; 556 | end 557 | end 558 | 559 | if (status_we & (status_addr == 4)) begin 560 | i2s_in_offset <= wb_dbus_dat[3:0]; 561 | i2s_out_offset <= wb_dbus_dat[7:4]; 562 | end 563 | 564 | if (reset & !bank_done) begin 565 | // switch banks 566 | bank_done <= 1; 567 | bank_addr <= !bank_addr; 568 | end 569 | 570 | if (reset_req) begin 571 | reset_req <= 0; 572 | end 573 | 574 | end 575 | 576 | wire [31:0] control_reg; 577 | assign control_reg = { 578 | { (32-(FRAME_W+2)){ 1'b0 } }, 579 | control_reg_frame, 580 | i2s_external, 581 | allow_audio_writes 582 | }; 583 | 584 | function [31:0] sreg_rdt(input [2:0] s_addr); 585 | 586 | case (s_addr) 587 | 0 : sreg_rdt = control_reg; 588 | 1 : sreg_rdt = { 29'h0, bank_done, error, done }; 589 | 2 : sreg_rdt = capture; 590 | 3 : sreg_rdt = 32'h0; 591 | 4 : sreg_rdt = { 24'h0, i2s_out_offset, i2s_in_offset }; 592 | endcase 593 | 594 | endfunction 595 | 596 | wire [31:0] status_rdt; 597 | 598 | assign status_rdt = status_re ? sreg_rdt(status_addr) : 0; 599 | 600 | // DMA Test 601 | 602 | `ifdef USE_DMA 603 | 604 | localparam XFER_ADDR_W = 3; 605 | localparam XFER_DATA_W = 16; 606 | 607 | wire [31:0] dma_dbus_rdt; 608 | wire dma_dbus_ack; 609 | wire xfer_done; 610 | wire [XFER_ADDR_W-1:0] xfer_adr; 611 | /* verilator lint_off UNUSED */ 612 | wire block_done; 613 | wire xfer_re; 614 | /* verilator lint_on UNUSED */ 615 | wire xfer_match; 616 | 617 | assign dma_done = xfer_done; 618 | assign dma_match = xfer_match; 619 | 620 | wire [15:0] xfer_dat; 621 | assign xfer_dat = mic_source(xfer_adr); 622 | 623 | wire xfer_block; 624 | assign xfer_block = start_of_frame; 625 | 626 | dma #(.ADDR(ADDR_DMA), .WIDTH(8), .XFER_ADDR_W(XFER_ADDR_W)) 627 | dma ( 628 | .wb_clk(ck), 629 | .wb_rst(wb_rst), 630 | .wb_dbus_cyc(wb_dbus_cyc), 631 | .wb_dbus_we(wb_dbus_we), 632 | .wb_dbus_adr(wb_dbus_adr), 633 | .wb_dbus_dat(wb_dbus_dat), 634 | .dbus_rdt(dma_dbus_rdt), 635 | .dbus_ack(dma_dbus_ack), 636 | .xfer_block(xfer_block), 637 | .block_done(block_done), 638 | .xfer_done(xfer_done), 639 | .xfer_match(xfer_match), 640 | .xfer_adr(xfer_adr), 641 | .xfer_re(xfer_re), 642 | .xfer_dat(xfer_dat), 643 | .dma_cyc(dma_cyc), 644 | .dma_we(dma_we), 645 | .dma_sel(dma_sel), 646 | .dma_adr(dma_adr), 647 | .dma_dat(dma_dat), 648 | .dma_ack(dma_ack), 649 | .dma_rdt(dma_rdt) 650 | ); 651 | `else // USE_DMA 652 | 653 | initial begin 654 | dma_cyc = 0; 655 | dma_we = 0; 656 | dma_sel = 0; 657 | dma_dat = 0; 658 | dma_adr = 0; 659 | end 660 | 661 | wire [31:0] dma_dbus_rdt; 662 | wire dma_dbus_ack; 663 | assign dma_dbus_rdt = 0; 664 | assign dma_dbus_ack = 0; 665 | assign dma_done = 0; 666 | assign dma_match = 0; 667 | 668 | `endif // USE_DMA 669 | 670 | // OR the ACK and RST signals together 671 | 672 | assign ack = result_ack | status_ack | dma_dbus_ack | coef_ack | input_ack; 673 | assign rdt = result_rdt | status_rdt | dma_dbus_rdt; 674 | assign ready = done; 675 | 676 | // Test output 677 | 678 | assign test[0] = sck; 679 | assign test[1] = ws; 680 | assign test[2] = sd_in0; 681 | assign test[3] = sd_in1; 682 | assign test[4] = ext_sck; // sd_in2; 683 | assign test[5] = ext_ws; // sd_in3; 684 | assign test[6] = i2s_external; 685 | assign test[7] = 0; // not working? 686 | 687 | endmodule 688 | 689 | // FIN 690 | --------------------------------------------------------------------------------