├── busfabric ├── busfabric.f ├── ahbl_crossbar.f ├── apb_splitter.v ├── ahbl_to_apb.v └── ahbl_splitter.v ├── mem ├── ahb_sync_sram.f ├── ahb_async_sram.f ├── async_sram_phy.f ├── ahb_cache.f ├── ahb_async_sram_halfwidth.f ├── ahb_async_sram.v ├── sram_sync_1r1w.v ├── behav │ └── sram_async.v ├── ahb_async_sram_halfwidth.v ├── async_sram_phy.v ├── sram_sync.v └── cache_mem_directmapped.v ├── sdram ├── io │ ├── io.f │ ├── sdram_clk_buf.v │ ├── sdram_addr_buf.v │ ├── sdram_dq_buf.v │ └── sdram_phy.v ├── ahbl_sdram.f └── regs │ ├── sdram_ctrl_regs.yml │ ├── sdram_ctrl_regs.h │ └── sdram_ctrl_regs.v ├── common ├── activity_led.f ├── popcount.v ├── reset_sync.v ├── dffe_out.v ├── onehot_encoder.v ├── onehot_mux.v ├── delay_ff.v ├── debounce_ctr.v ├── pullup_input.v ├── onehot_priority.v ├── activity_led.v ├── blinky.v ├── clkdiv_frac.v ├── ddr_out.v ├── skid_buffer.v ├── fpga_reset.v ├── onehot_priority_dynamic.v ├── nbit_sync.v ├── sync_fifo.v ├── memdump.v └── tristate_io.v ├── test ├── .gitignore ├── ahb_cache_readonly │ ├── Makefile │ └── tb.f └── ahb_cache_writeback │ ├── Makefile │ ├── tb.f │ └── tag_zeroes.hex ├── peris ├── spi_03h_xip │ ├── spi_03h_xip.f │ ├── spi_03h_xip_regs.yml │ ├── spi_03h_xip_regs.h │ ├── spi_03h_xip_regs.v │ └── spi_03h_xip.v ├── spi │ ├── spi.f │ ├── spi_regs.yml │ ├── spi_regs.h │ ├── spi_regs.v │ └── spi_mini.v └── uart │ ├── uart.f │ ├── uart_regs.yml │ ├── uart_regs.h │ └── uart_regs.v ├── cdc ├── async_fifo.f ├── gray_decode.v ├── sync_1bit.v ├── gray_counter.v ├── async_fifo.v └── gearbox.v ├── video ├── dvi_serialiser.f ├── dvi_tx_parallel.f ├── dvi_clock_driver.v ├── dvi_serialiser.v ├── dvi_tx_parallel.v ├── tmds_encode.v ├── dvi_timing.v └── smoldvi_tmds_encode.v ├── Readme.md ├── License └── arith ├── wallace_mult.v ├── wallace_adder.v └── radix2_mult.v /busfabric/busfabric.f: -------------------------------------------------------------------------------- 1 | list ahbl_crossbar.f 2 | wildcard .v . -------------------------------------------------------------------------------- /mem/ahb_sync_sram.f: -------------------------------------------------------------------------------- 1 | file ahb_sync_sram.v 2 | file sram_sync.v -------------------------------------------------------------------------------- /sdram/io/io.f: -------------------------------------------------------------------------------- 1 | wildcard .v . 2 | file $LIBFPGA/common/ddr_out.v 3 | -------------------------------------------------------------------------------- /common/activity_led.f: -------------------------------------------------------------------------------- 1 | file activity_led.v 2 | file ../cdc/sync_1bit.v 3 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.smt2 3 | *.hex 4 | *.vcd 5 | *.smt2 6 | *.gtkw 7 | -------------------------------------------------------------------------------- /peris/spi_03h_xip/spi_03h_xip.f: -------------------------------------------------------------------------------- 1 | file spi_03h_xip.v 2 | file spi_03h_xip_regs.v 3 | -------------------------------------------------------------------------------- /peris/spi/spi.f: -------------------------------------------------------------------------------- 1 | wildcard .v . 2 | file ../../common/reset_sync.v 3 | file ../../common/sync_fifo.v 4 | -------------------------------------------------------------------------------- /cdc/async_fifo.f: -------------------------------------------------------------------------------- 1 | file async_fifo.v 2 | file gray_counter.v 3 | file gray_decode.v 4 | file sync_1bit.v 5 | -------------------------------------------------------------------------------- /mem/ahb_async_sram.f: -------------------------------------------------------------------------------- 1 | file ahb_async_sram.v 2 | file ../common/tristate_io.v 3 | file ../common/ddr_out.v 4 | -------------------------------------------------------------------------------- /mem/async_sram_phy.f: -------------------------------------------------------------------------------- 1 | file async_sram_phy.v 2 | file ../common/tristate_io.v 3 | file ../common/ddr_out.v 4 | -------------------------------------------------------------------------------- /test/ahb_cache_readonly/Makefile: -------------------------------------------------------------------------------- 1 | DOTF=tb.f 2 | TOP=tb 3 | DEPTH=60 4 | 5 | include $(SCRIPTS)/formal.mk 6 | -------------------------------------------------------------------------------- /test/ahb_cache_readonly/tb.f: -------------------------------------------------------------------------------- 1 | file tb.v 2 | list ../../mem/ahb_cache.f 3 | list ../../mem/ahb_sync_sram.f 4 | -------------------------------------------------------------------------------- /test/ahb_cache_writeback/Makefile: -------------------------------------------------------------------------------- 1 | DOTF=tb.f 2 | TOP=tb 3 | DEPTH=40 4 | 5 | include $(SCRIPTS)/formal.mk 6 | -------------------------------------------------------------------------------- /test/ahb_cache_writeback/tb.f: -------------------------------------------------------------------------------- 1 | file tb.v 2 | list ../../mem/ahb_cache.f 3 | list ../../mem/ahb_sync_sram.f 4 | -------------------------------------------------------------------------------- /video/dvi_serialiser.f: -------------------------------------------------------------------------------- 1 | file dvi_serialiser.v 2 | file dvi_clock_driver.v 3 | file ../cdc/gearbox.v 4 | file ../common/ddr_out.v 5 | -------------------------------------------------------------------------------- /mem/ahb_cache.f: -------------------------------------------------------------------------------- 1 | file ahb_cache_readonly.v 2 | file ahb_cache_writeback.v 3 | file cache_mem_set_associative.v 4 | file sram_sync.v 5 | -------------------------------------------------------------------------------- /mem/ahb_async_sram_halfwidth.f: -------------------------------------------------------------------------------- 1 | file ahb_async_sram_halfwidth.v 2 | file async_sram_phy.v 3 | file ../common/tristate_io.v 4 | file ../common/ddr_out.v 5 | -------------------------------------------------------------------------------- /video/dvi_tx_parallel.f: -------------------------------------------------------------------------------- 1 | file dvi_tx_parallel.v 2 | file dvi_timing.v 3 | file tmds_encode.v 4 | file smoldvi_tmds_encode.v 5 | file ../common/popcount.v 6 | -------------------------------------------------------------------------------- /busfabric/ahbl_crossbar.f: -------------------------------------------------------------------------------- 1 | file ahbl_crossbar.v 2 | file ahbl_splitter.v 3 | file ahbl_arbiter.v 4 | file ../common/onehot_mux.v 5 | file ../common/onehot_priority.v 6 | -------------------------------------------------------------------------------- /peris/uart/uart.f: -------------------------------------------------------------------------------- 1 | wildcard .v . 2 | file ../../common/clkdiv_frac.v 3 | file ../../common/sync_fifo.v 4 | file ../../common/reset_sync.v 5 | file ../../cdc/sync_1bit.v 6 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | libfpga 2 | ======= 3 | 4 | This is a collection of components I've accumulated from FPGA projects (mainly RISCBoy). 5 | 6 | They're written in synthesisable Verilog 2005. 7 | -------------------------------------------------------------------------------- /sdram/ahbl_sdram.f: -------------------------------------------------------------------------------- 1 | file ahbl_sdram.v 2 | file ahbl_sdram_bus_interface.v 3 | file regs/sdram_ctrl_regs.v 4 | file sdram_scheduler.v 5 | 6 | file $LIBFPGA/common/onehot_priority.v 7 | file $LIBFPGA/common/onehot_mux.v 8 | file $LIBFPGA/common/onehot_encoder.v 9 | 10 | list io/io.f 11 | -------------------------------------------------------------------------------- /sdram/io/sdram_clk_buf.v: -------------------------------------------------------------------------------- 1 | module sdram_clk_buf ( 2 | input wire clk, 3 | input wire rst_n, 4 | input wire e, 5 | output wire clkout 6 | ); 7 | 8 | // Inverted clock output to get centre-aligned SDR 9 | ddr_out ckbuf ( 10 | .clk (clk), 11 | .rst_n (rst_n), 12 | 13 | .d_rise (1'b0), 14 | .d_fall (e), 15 | .e (1'b1), 16 | .q (clkout) 17 | ); 18 | 19 | endmodule 20 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE 2 | Version 3, April 2008 3 | 4 | Copyright (C) 2020 Luke Wren 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document and accompanying software, and 8 | changing either is allowed. 9 | 10 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 11 | 12 | 0. You just DO WHAT THE FUCK YOU WANT TO. 13 | 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. 14 | -------------------------------------------------------------------------------- /sdram/io/sdram_addr_buf.v: -------------------------------------------------------------------------------- 1 | module sdram_addr_buf ( 2 | input wire clk, 3 | input wire rst_n, 4 | input wire d, 5 | output wire q 6 | ); 7 | 8 | `ifdef FPGA_ECP5 9 | 10 | (*syn_useioff*) (*keep*) TRELLIS_FF #( 11 | .GSR("DISABLED"), 12 | .CEMUX("1"), 13 | .CLKMUX("CLK"), 14 | .LSRMUX("LSR"), 15 | .REGSET("RESET") 16 | ) o_reg ( 17 | .CLK (clk), 18 | .LSR (1'b0), 19 | .DI (d), 20 | .Q (q) 21 | ); 22 | 23 | `else 24 | 25 | reg q_r; 26 | 27 | always @ (posedge clk or negedge rst_n) begin 28 | if (!rst_n) begin 29 | q_r <= 1'b0; 30 | end else begin 31 | q_r <= d; 32 | end 33 | end 34 | 35 | assign q = q_r; 36 | 37 | `endif 38 | 39 | endmodule 40 | -------------------------------------------------------------------------------- /arith/wallace_mult.v: -------------------------------------------------------------------------------- 1 | module wallace_mult #( 2 | parameter W = 32 3 | ) ( 4 | input wire sext_a, 5 | input wire sext_b, 6 | input wire [W-1:0] a, 7 | input wire [W-1:0] b, 8 | output wire [W*2-1:0] out 9 | ); 10 | 11 | 12 | reg [W*W*2-1:0] pprod_noinv; 13 | reg [W*W*2-1:0] pprod; 14 | integer i; 15 | 16 | always @ (*) begin 17 | for (i = 0; i < W; i = i + 1) begin 18 | pprod_noinv[i * W * 2 +: W * 2] = ({2*W{b[i]}} & {{W{sext_a && a[W-1]}}, a}) << i; 19 | if (sext_b && i == W - 1) begin 20 | pprod[i * W * 2 +: W * 2] = -pprod_noinv[i * W * 2 +: W * 2]; 21 | end else begin 22 | pprod[i * W * 2 +: W * 2] = pprod_noinv[i * W * 2 +: W * 2]; 23 | end 24 | end 25 | end 26 | 27 | wallace_adder #( 28 | .W(W * 2), 29 | .N(W) 30 | ) add0 ( 31 | .in(pprod), 32 | .out(out) 33 | ); 34 | 35 | endmodule 36 | -------------------------------------------------------------------------------- /peris/spi_03h_xip/spi_03h_xip_regs.yml: -------------------------------------------------------------------------------- 1 | name: xip 2 | bus: apb 3 | addr: 16 4 | data: 32 5 | regs: 6 | - name: csr 7 | info: Control and status register 8 | bits: 9 | - {b: 0, name: direct, access: rw, info: "If 1, enable direct mode. Chip 10 | select is held asserted until direct mode is disabled, and individual 11 | bytes can be written to TXDATA and then read from RXDATA. If you 12 | enable direct mode whilst executing from XIP, you're gonna have a bad 13 | time."} 14 | - {b: 1, name: busy, access: rov, info: "Reads as 1 when a direct mode 15 | transfer is in progress. Note a direct mode transfer takes precisely 16 | 16 cycles (in between the APB write and readback, so at least 19 17 | cycles total), so you could insert a precise delay in your code 18 | instead of polling this bit."} 19 | - name: txdata 20 | info: Direct mode transmit data 21 | bits: 22 | - {b: [7, 0], access: wf} 23 | - name: rxdata 24 | info: Direct mode receive data 25 | bits: 26 | - {b: [7, 0], access: rf} 27 | 28 | -------------------------------------------------------------------------------- /arith/wallace_adder.v: -------------------------------------------------------------------------------- 1 | module wallace_adder #( 2 | parameter W = 32, // valid for W >= 1 3 | parameter N = 2 // valid for N >= 2 4 | ) ( 5 | input wire [W*N-1:0] in, 6 | output wire [W-1:0] out 7 | ); 8 | 9 | generate 10 | if (N == 2) begin: base 11 | assign out = in[0 +: W] + in[W +: W]; 12 | end else begin: recurse 13 | localparam N_NEXT = N / 3 * 2 + N % 3; 14 | integer i; 15 | 16 | reg [N_NEXT*W-1:0] psum; 17 | 18 | wallace_adder #( 19 | .W(W), 20 | .N(N_NEXT) 21 | ) wadd ( 22 | .in(psum), 23 | .out(out) 24 | ); 25 | 26 | always @ (*) begin 27 | for (i = 0; i < N; i = i + 3) begin 28 | if (N - i >= 3) begin 29 | psum[(i / 3 * 2 + 0) * W +: W] = in[(i + 0) * W +: W] ^ in[(i + 1) * W +: W] ^ in[(i + 2) * W +: W]; 30 | psum[(i / 3 * 2 + 1) * W +: W] = ( 31 | (in[(i + 0) * W +: W] & in[(i + 1) * W +: W]) | 32 | (in[(i + 1) * W +: W] & in[(i + 2) * W +: W]) | 33 | (in[(i + 2) * W +: W] & in[(i + 0) * W +: W])) << 1; 34 | end else if (N - i == 2) begin 35 | psum[i / 3 * 2 * W +: 2 * W] = in[i * W +: 2 * W]; 36 | end else begin 37 | psum[i / 3 * 2 * W +: W] = in[i * W +: W]; 38 | end 39 | end 40 | end 41 | end 42 | endgenerate 43 | 44 | endmodule -------------------------------------------------------------------------------- /cdc/gray_decode.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | module gray_decode #( 19 | parameter N = 4 20 | ) ( 21 | input wire [N-1:0] i, 22 | output reg [N-1:0] o 23 | ); 24 | 25 | always @ (*) begin: decode 26 | integer j; 27 | o[N-1] = i[N-1]; 28 | for (j = N - 2; j >= 0; j = j - 1) 29 | o[j] = i[j] ^ o[j + 1]; 30 | end 31 | 32 | endmodule 33 | -------------------------------------------------------------------------------- /arith/radix2_mult.v: -------------------------------------------------------------------------------- 1 | // Radix-2 multiplier, based on Karatsuba method 2 | // May cause your synthesis tool to shit a brick 3 | 4 | module radix2_mult #( 5 | parameter W = 32 6 | ) ( 7 | input wire [W-1:0] a, 8 | input wire [W-1:0] b, 9 | output reg [W*2-1:0] out 10 | ); 11 | 12 | generate 13 | if (W <= 4) begin 14 | always @ (*) begin 15 | out = a * b; 16 | end 17 | end else if (W % 2) begin: odd 18 | wire [W-2:0] pp0; 19 | wire [W+2:0] pp1; 20 | wire [W+0:0] pp2; 21 | 22 | radix2_mult #(.W(W / 2)) mult0 23 | ( 24 | .a (a[0 +: W/2]), 25 | .b (b[0 +: W/2]), 26 | .out (pp0) 27 | ); 28 | radix2_mult #(.W(W / 2 + 1)) mult1 29 | ( 30 | .a ({2'b00, a[0 +: W/2]} + a[W/2 +: W/2 + 1]), 31 | .b ({2'b00, b[0 +: W/2]} + b[W/2 +: W/2 + 1]), 32 | .out (pp1) 33 | ); 34 | radix2_mult #(.W(W / 2 + 1)) mult2 35 | ( 36 | .a (a[W/2 +: W/2 + 1]), 37 | .b (b[W/2 +: W/2 + 1]), 38 | .out (pp2) 39 | ); 40 | always @ (*) begin 41 | out = pp0 + (pp1 - pp0 - pp2 << W/2) + (pp2 << W - 1); 42 | end 43 | end else begin: even 44 | wire [W-1:0] pp0; 45 | wire [W+1:0] pp1; 46 | wire [W-1:0] pp2; 47 | 48 | radix2_mult #(.W(W / 2)) mult0 49 | ( 50 | .a (a[ 0 +: W/2]), 51 | .b (b[ 0 +: W/2]), 52 | .out (pp0) 53 | ); 54 | radix2_mult #(.W(W / 2)) mult1 55 | ( 56 | .a (a[ 0 +: W/2] + a[W/2 +: W/2]), 57 | .b (b[ 0 +: W/2] + b[W/2 +: W/2]), 58 | .out (pp1) 59 | ); 60 | radix2_mult #(.W(W / 2)) mult2 61 | ( 62 | .a (a[W/2 +: W/2]), 63 | .b (b[W/2 +: W/2]), 64 | .out (pp2) 65 | ); 66 | 67 | always @ (*) begin 68 | out = pp0 + (pp1 - pp0 - pp2 << W/2) + (pp2 << W); 69 | end 70 | end 71 | endgenerate 72 | 73 | endmodule -------------------------------------------------------------------------------- /peris/uart/uart_regs.yml: -------------------------------------------------------------------------------- 1 | name: uart 2 | bus: apb 3 | addr: 16 4 | data: 32 5 | params: 6 | W_DIV_INT: 10 7 | W_DIV_FRAC: 4 8 | regs: 9 | - name: csr 10 | info: Control and status register 11 | bits: 12 | - {b: 0, name: en, access: rw, 13 | info: UART runs when en is high. Synchronous reset (excluding FIFOs) when low.} 14 | - {b: 1, name: busy, access: rov, info: UART TX is still sending data} 15 | - {b: 2, name: txie, access: rw, info: Enable TX FIFO interrupt} 16 | - {b: 3, name: rxie, access: rw, info: Enable RX FIFO interrupt} 17 | - {b: 4, name: ctsen, access: rw, info: Enable pausing of TX while CTS is not asserted} 18 | - {b: 8, name: loopback, access: rw, info: "Connect TX -> RX and RTS -> CTS internally (for testing)."} 19 | - name: div 20 | info: Clock divider control fields 21 | bits: 22 | - {b: [W_DIV_INT + W_DIV_FRAC - 1, W_DIV_FRAC], name: int, access: wo, rst: 0x1} 23 | - {b: [W_DIV_FRAC - 1, 0], name: frac, access: wo} 24 | - name: fstat 25 | info: FIFO status register 26 | bits: 27 | - {b: [7, 0], name: txlevel, access: rov} 28 | - {b: 8, name: txfull, access: rov} 29 | - {b: 9, name: txempty, access: rov} 30 | - {b: 10, name: txover, access: w1c} 31 | - {b: 11, name: txunder, access: w1c} 32 | - {b: [23, 16], name: rxlevel, access: rov} 33 | - {b: 24, name: rxfull, access: rov} 34 | - {b: 25, name: rxempty, access: rov} 35 | - {b: 26, name: rxover, access: w1c} 36 | - {b: 27, name: rxunder, access: w1c} 37 | - name: tx 38 | info: "TX data FIFO" 39 | bits: 40 | - {b: [7, 0], access: wf} 41 | - name: rx 42 | info: "RX data FIFO" 43 | bits: 44 | - {b: [7, 0], access: rf} 45 | -------------------------------------------------------------------------------- /common/popcount.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | module popcount #( 19 | parameter W_IN = 8, 20 | parameter W_OUT = $clog2(W_IN + 1) // Do not modify 21 | ) ( 22 | input wire [W_IN-1:0] din, 23 | output wire [W_OUT-1:0] dout 24 | ); 25 | 26 | // If it's stupid but it works, it's not stupid 27 | // (this actually gives reasonable synthesis results, though FPGAs can do much 28 | // better in some cases using e.g. compressor trees) 29 | 30 | reg [W_OUT-1:0] accum; 31 | integer i; 32 | 33 | always @ (*) begin 34 | accum = {W_OUT{1'b0}}; 35 | for (i = 0; i < W_IN; i = i + 1) 36 | accum = accum + din[i]; 37 | end 38 | 39 | assign dout = accum; 40 | 41 | endmodule 42 | -------------------------------------------------------------------------------- /peris/spi/spi_regs.yml: -------------------------------------------------------------------------------- 1 | name: spi 2 | bus: apb 3 | addr: 16 4 | data: 32 5 | regs: 6 | - name: csr 7 | info: Control and status register 8 | bits: 9 | - {b: 9, name: csauto, access: rw, rst: 1, 10 | info: "If 1, CS pin is driven automatically (low during data transfer, else high)"} 11 | - {b: 8, name: cs, access: rw, 12 | info: "If automatic CS is disabled, use this bit to control CS signal."} 13 | - {b: 5, name: loopback, access: rw, 14 | info: "If 1, connect MOSI to MISO internally, for debugging purposes"} 15 | - {b: 4, name: read_en, access: rw, rst: 1, 16 | info: "If 0, the received data will not be pushed to RX FIFO. (Transmit only)"} 17 | - {b: 3, name: cpol, access: rw, 18 | info: "If 0, SCLK low when idle. If 1, high when idle."} 19 | - {b: 2, name: cpha, access: rw, 20 | info: "If 0, data captured on leading edge of SCLK pulse. If 1, trailing edge."} 21 | - {b: 0, name: busy, access: rov, info: A transfer is in progress} 22 | - name: div 23 | info: Clock divider register 24 | bits: 25 | - {b: [5, 0], access: rw, rst: 1} 26 | - name: fstat 27 | info: FIFO status register 28 | bits: 29 | - {b: [7, 0], name: txlevel, access: rov} 30 | - {b: 8, name: txfull, access: rov} 31 | - {b: 9, name: txempty, access: rov} 32 | - {b: 10, name: txover, access: w1c} 33 | - {b: [23, 16], name: rxlevel, access: rov} 34 | - {b: 24, name: rxfull, access: rov} 35 | - {b: 25, name: rxempty, access: rov} 36 | - {b: 26, name: rxover, access: w1c} 37 | - {b: 27, name: rxunder, access: w1c} 38 | - name: tx 39 | info: "TX data FIFO" 40 | bits: 41 | - {b: [7, 0], access: wf} 42 | - name: rx 43 | info: "RX data FIFO" 44 | bits: 45 | - {b: [7, 0], access: rf} -------------------------------------------------------------------------------- /common/reset_sync.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // The output is asserted asynchronously when the input is asserted, 19 | // but deasserted synchronously when clocked with the input deasserted. 20 | // Input and output are both active-low. 21 | 22 | module reset_sync #( 23 | parameter N_CYCLES = 2 // must be >= 2 24 | ) ( 25 | input wire clk, 26 | input wire rst_n_in, 27 | output wire rst_n_out 28 | ); 29 | 30 | (* keep = 1'b1 *) reg [N_CYCLES-1:0] delay; 31 | 32 | always @ (posedge clk or negedge rst_n_in) 33 | if (!rst_n_in) 34 | delay <= {N_CYCLES{1'b0}}; 35 | else 36 | delay <= {delay[N_CYCLES-2:0], 1'b1}; 37 | 38 | assign rst_n_out = delay[N_CYCLES-1]; 39 | 40 | endmodule 41 | -------------------------------------------------------------------------------- /common/dffe_out.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | module dffe_out ( 19 | input wire clk, 20 | input wire d, 21 | input wire e, 22 | output wire q 23 | ); 24 | 25 | `ifdef FPGA_ICE40 26 | 27 | SB_IO #( 28 | .PIN_TYPE (6'b01_01_00), 29 | // | | | 30 | // | | \----- Registered input (and no clock!) 31 | // | \-------- Registered output 32 | // \----------- Permanent output enable 33 | .PULLUP (1'b 0) 34 | ) buffer ( 35 | .PACKAGE_PIN (q), 36 | .OUTPUT_CLK (clk), 37 | .CLOCK_ENABLE (e), 38 | .D_OUT_0 (d) 39 | ); 40 | 41 | `else 42 | 43 | reg q_r; 44 | assign q = q_r; 45 | 46 | always @ (posedge clk) 47 | if (e) 48 | q_r <= d; 49 | 50 | `endif 51 | 52 | endmodule 53 | -------------------------------------------------------------------------------- /cdc/sync_1bit.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // A standard 2FF synchronizer; used to mitigate metastabilities as part 19 | // of more-comprehensive async handshakes. 20 | // The implementation provided here is... ok... but you should use 21 | // this wrapper to inject your own FPGA- or library-specific cells. 22 | 23 | module sync_1bit #( 24 | parameter N_STAGES = 2 // Should be >=2 25 | ) ( 26 | input wire clk, 27 | input wire rst_n, 28 | input wire i, 29 | output wire o 30 | ); 31 | 32 | (* keep = 1'b1 *) reg [N_STAGES-1:0] sync_flops; 33 | 34 | always @ (posedge clk or negedge rst_n) 35 | if (!rst_n) 36 | sync_flops <= {N_STAGES{1'b0}}; 37 | else 38 | sync_flops <= {sync_flops[N_STAGES-2:0], i}; 39 | 40 | assign o = sync_flops[N_STAGES-1]; 41 | 42 | endmodule 43 | -------------------------------------------------------------------------------- /common/onehot_encoder.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Encodes a one-hot vector at the input as a binary integer at the output. 19 | // Results are invalid if the input is not one-hot or zero. 20 | // (Perhaps filter input with a onehot_priority first, forming a priority encoder) 21 | 22 | module onehot_encoder #( 23 | parameter W_INPUT = 8, 24 | parameter W_OUTPUT = $clog2(W_INPUT) // it's best to let this default 25 | ) ( 26 | input wire [W_INPUT-1:0] in, 27 | output wire [W_OUTPUT-1:0] out 28 | ); 29 | 30 | reg [W_OUTPUT-1:0] out_r; 31 | assign out = out_r; 32 | 33 | always @ (*) begin: encode 34 | reg [W_OUTPUT:0] i; 35 | out_r = {W_OUTPUT{1'b0}}; 36 | for (i = 0; i < W_INPUT; i = i + 1) 37 | if (in[i]) 38 | out_r = out_r | i[W_OUTPUT-1:0]; 39 | end 40 | 41 | endmodule 42 | 43 | -------------------------------------------------------------------------------- /busfabric/apb_splitter.v: -------------------------------------------------------------------------------- 1 | module apb_splitter #( 2 | parameter W_ADDR = 16, 3 | parameter W_DATA = 32, 4 | parameter N_SLAVES = 2, 5 | parameter ADDR_MAP = 32'h0000_4000, 6 | parameter ADDR_MASK = 32'hc000_c000 7 | ) ( 8 | input wire [W_ADDR-1:0] apbs_paddr, 9 | input wire apbs_psel, 10 | input wire apbs_penable, 11 | input wire apbs_pwrite, 12 | input wire [W_DATA-1:0] apbs_pwdata, 13 | output wire apbs_pready, 14 | output wire [W_DATA-1:0] apbs_prdata, 15 | output wire apbs_pslverr, 16 | 17 | output wire [N_SLAVES*W_ADDR-1:0] apbm_paddr, 18 | output wire [N_SLAVES-1:0] apbm_psel, 19 | output wire [N_SLAVES-1:0] apbm_penable, 20 | output wire [N_SLAVES-1:0] apbm_pwrite, 21 | output wire [N_SLAVES*W_DATA-1:0] apbm_pwdata, 22 | input wire [N_SLAVES-1:0] apbm_pready, 23 | input wire [N_SLAVES*W_DATA-1:0] apbm_prdata, 24 | input wire [N_SLAVES-1:0] apbm_pslverr 25 | ); 26 | 27 | integer i; 28 | 29 | reg [N_SLAVES-1:0] decode_mask; 30 | 31 | always @ (*) begin 32 | for (i = 0; i < N_SLAVES; i = i + 1) begin 33 | decode_mask[i] = (apbs_paddr & ADDR_MASK[i * W_ADDR +: W_ADDR]) 34 | == ADDR_MAP[i * W_ADDR +: W_ADDR]; 35 | end 36 | end 37 | 38 | assign apbs_pready = ~|decode_mask || |(decode_mask & apbm_pready); 39 | assign apbs_pslverr = ~|decode_mask || |(decode_mask & apbm_pslverr); 40 | 41 | assign apbm_paddr = {N_SLAVES{apbs_paddr}}; 42 | assign apbm_psel = decode_mask & {N_SLAVES{apbs_psel}}; 43 | assign apbm_penable = decode_mask & {N_SLAVES{apbs_penable}}; 44 | assign apbm_pwrite = decode_mask & {N_SLAVES{apbs_pwrite}}; 45 | assign apbm_pwdata = {N_SLAVES{apbs_pwdata}}; 46 | 47 | onehot_mux #( 48 | .N_INPUTS (N_SLAVES), 49 | .W_INPUT (W_DATA) 50 | ) prdata_mux ( 51 | .in (apbm_prdata), 52 | .sel (decode_mask), 53 | .out (apbs_prdata) 54 | ); 55 | 56 | endmodule 57 | -------------------------------------------------------------------------------- /common/onehot_mux.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Multiplex based on a bitmap selector, rather than an index selector. 19 | // Generates a fast and->or mux structure rather than a tree of dmuxes. 20 | // The selector must be one-hot, else the result is meaningless. 21 | 22 | module onehot_mux #( 23 | parameter N_INPUTS = 2, 24 | parameter W_INPUT = 32 25 | ) ( 26 | input wire [N_INPUTS*W_INPUT-1:0] in, 27 | input wire [N_INPUTS-1:0] sel, 28 | output wire [W_INPUT-1:0] out 29 | ); 30 | 31 | integer i; 32 | 33 | reg [W_INPUT-1:0] mux_accum; 34 | 35 | always @ (*) begin 36 | mux_accum = {W_INPUT{1'b0}}; 37 | for (i = 0; i < N_INPUTS; i = i + 1) begin 38 | mux_accum = mux_accum | (in[i * W_INPUT +: W_INPUT] & {W_INPUT{sel[i]}}); 39 | end 40 | end 41 | 42 | assign out = mux_accum; 43 | 44 | endmodule 45 | -------------------------------------------------------------------------------- /common/delay_ff.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | module delay_ff #( 19 | parameter W = 1, 20 | parameter N = 1 21 | ) ( 22 | input wire clk, 23 | input wire rst_n, 24 | 25 | input wire [W-1:0] d, 26 | output wire [W-1:0] q 27 | ); 28 | 29 | generate 30 | if (N == 0) begin: nodelay 31 | 32 | assign q = d; 33 | 34 | end else begin: delay 35 | 36 | reg [W-1:0] delay_regs [0:N-1]; 37 | integer i; 38 | always @ (posedge clk or negedge rst_n) begin 39 | if (!rst_n) begin 40 | for (i = 0; i < N; i = i + 1) begin 41 | delay_regs[i] <= {W{1'b0}}; 42 | end 43 | end else begin 44 | delay_regs[0] <= d; 45 | for (i = 0; i < N - 1; i = i + 1) begin 46 | delay_regs[i + 1] <= delay_regs[i]; 47 | end 48 | end 49 | end 50 | 51 | assign q = delay_regs[N - 1]; 52 | 53 | end 54 | endgenerate 55 | 56 | endmodule 57 | -------------------------------------------------------------------------------- /common/debounce_ctr.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // i is an input which may be glitchy. 19 | // o tracks the state of i, but does not toggle 20 | // until i has been stable for n cycles. 21 | 22 | module debounce_ctr #( 23 | parameter N_CYCLES = 100, 24 | parameter W_CTR = $clog2(N_CYCLES) // let this default 25 | ) ( 26 | input wire clk, 27 | input wire rst_n, 28 | input wire i, 29 | output reg o 30 | ); 31 | 32 | reg [W_CTR-1:0] ctr; 33 | 34 | always @ (posedge clk or negedge rst_n) begin 35 | if (!rst_n) begin 36 | ctr <= {W_CTR{1'b0}}; 37 | o <= 1'b0; 38 | end else begin 39 | if (o == i) begin 40 | ctr <= {W_CTR{1'b0}}; 41 | end else begin 42 | ctr <= ctr + 1'b1; 43 | if (ctr == N_CYCLES - 1) begin 44 | o <= i; 45 | ctr <= {W_CTR{1'b0}}; 46 | end 47 | end 48 | end 49 | end 50 | 51 | endmodule 52 | -------------------------------------------------------------------------------- /common/pullup_input.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | module pullup_input #( 19 | parameter INVERT = 1 20 | ) ( 21 | output wire in, 22 | inout wire pad 23 | ); 24 | 25 | `ifdef FPGA_ICE40 26 | 27 | wire padin; 28 | assign in = padin ^ INVERT; 29 | 30 | SB_IO #( 31 | .PIN_TYPE(6'b00_00_01), 32 | // | | | 33 | // | | \----- Unregistered input 34 | // | \-------- Registered output (don't care) 35 | // \----------- Permanent output disable 36 | .PULLUP(1'b1) 37 | ) input_buffer ( 38 | .PACKAGE_PIN (pad), 39 | .D_IN_0 (padin) 40 | ); 41 | 42 | `elsif FPGA_ECP5 43 | 44 | wire padin; 45 | assign in = padin ^ INVERT; 46 | 47 | IBPU input_buffer( 48 | .I (pad), 49 | .O (padin) 50 | ); 51 | 52 | `else 53 | 54 | assign (pull0, pull1) pad = 1'b1; 55 | assign in = pad ^ INVERT; 56 | 57 | `endif 58 | 59 | endmodule 60 | -------------------------------------------------------------------------------- /common/onehot_priority.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Input a bitmap. The output will have at most 1 bit set, which will 19 | // be the least-significant set bit of the input. 20 | // e.g. 'b011100 -> 'b000100 21 | // If HIGHEST_WINS is 1, it will instead be the most-significant bit of the output. 22 | 23 | module onehot_priority #( 24 | parameter W_INPUT = 8, 25 | parameter HIGHEST_WINS = 0 26 | ) ( 27 | input wire [W_INPUT-1:0] in, 28 | output reg [W_INPUT-1:0] out 29 | ); 30 | 31 | integer i; 32 | reg deny; 33 | 34 | always @ (*) begin 35 | deny = 1'b0; 36 | if (HIGHEST_WINS) begin 37 | for (i = W_INPUT - 1; i >= 0; i = i - 1) begin 38 | out[i] = in[i] && !deny; 39 | deny = deny || in[i]; 40 | end 41 | end else begin 42 | for (i = 0; i < W_INPUT; i = i + 1) begin 43 | out[i] = in[i] && !deny; 44 | deny = deny || in[i]; 45 | end 46 | end 47 | end 48 | 49 | endmodule 50 | -------------------------------------------------------------------------------- /cdc/gray_counter.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // A fully-synchronous Gray + binary dual up-counter 19 | 20 | module gray_counter #( 21 | parameter W_CTR = 4 22 | ) ( 23 | input wire clk, 24 | input wire rst_n, 25 | 26 | input wire en, 27 | input wire clr, 28 | output wire [W_CTR-1:0] count_bin, 29 | output wire [W_CTR-1:0] count_bin_next, 30 | output wire [W_CTR-1:0] count_gry 31 | ); 32 | 33 | reg [W_CTR-1:0] ctr_bin; 34 | (* keep = 1'b1 *)(* no_retiming = 1'b1 *) reg [W_CTR-1:0] ctr_gry; 35 | 36 | assign count_bin = ctr_bin; 37 | assign count_gry = ctr_gry; 38 | 39 | assign count_bin_next = ctr_bin + 1'b1; 40 | 41 | always @ (posedge clk or negedge rst_n) begin 42 | if (!rst_n) begin 43 | ctr_bin <= {W_CTR{1'b0}}; 44 | ctr_gry <= {W_CTR{1'b0}}; 45 | end else if (clr) begin 46 | ctr_bin <= {W_CTR{1'b0}}; 47 | ctr_gry <= {W_CTR{1'b0}}; 48 | end else if (en) begin 49 | ctr_bin <= count_bin_next; 50 | ctr_gry <= count_bin_next ^ (count_bin_next >> 1); 51 | end 52 | end 53 | 54 | endmodule 55 | -------------------------------------------------------------------------------- /common/activity_led.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2021 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Monostable, generates a pulse of at least WIDTH cycles every time the input 19 | // signal is seen to change. 20 | 21 | module activity_led #( 22 | parameter WIDTH = 1 << 16, 23 | parameter ACTIVE_LEVEL = 1'b1, 24 | parameter W_CTR = $clog2(WIDTH) // do not modify 25 | ) ( 26 | input wire clk, 27 | input wire rst_n, 28 | input wire i, 29 | output reg o 30 | ); 31 | 32 | wire i_sync; 33 | 34 | // Signal may be asynchronous to clk, e.g. a TCK signal from a debug probe 35 | sync_1bit inst_sync_1bit ( 36 | .clk (clk), 37 | .rst_n (rst_n), 38 | .i (i), 39 | .o (i_sync) 40 | ); 41 | 42 | reg i_prev; 43 | reg [W_CTR-1:0] ctr; 44 | 45 | always @ (posedge clk or negedge rst_n) begin 46 | if (!rst_n) begin 47 | i_prev <= 1'b0; 48 | ctr <= {W_CTR{1'b0}}; 49 | o <= !ACTIVE_LEVEL; 50 | end else begin 51 | i_prev <= i_sync; 52 | if (i_prev != i_sync) begin 53 | o <= ACTIVE_LEVEL; 54 | ctr <= WIDTH - 1; 55 | end else if (|ctr) begin 56 | ctr <= ctr - 1'b1; 57 | end else begin 58 | o <= !ACTIVE_LEVEL; 59 | end 60 | end 61 | end 62 | 63 | endmodule 64 | -------------------------------------------------------------------------------- /video/dvi_clock_driver.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2020 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // We can drive a clock by passing 10'b11111_00000 into a 10:1 serialiser, but this 19 | // is wasteful, because the tools won't trim the CDC hardware. It's worth it 20 | // (area-wise) to specialise this. 21 | // 22 | // This module takes a half-rate bit clock (5x pixel clock) and drives a 23 | // pseudodifferential pixel clock using DDR outputs. 24 | 25 | module dvi_clock_driver ( 26 | input wire clk_x5, 27 | input wire rst_n_x5, 28 | 29 | output wire qp, 30 | output wire qn 31 | ); 32 | 33 | reg [9:0] ring_ctr; 34 | 35 | always @ (posedge clk_x5 or negedge rst_n_x5) begin 36 | if (!rst_n_x5) begin 37 | ring_ctr <= 10'b11111_00000; 38 | end else begin 39 | ring_ctr <= {ring_ctr[1:0], ring_ctr[9:2]}; 40 | end 41 | end 42 | 43 | 44 | ddr_out ddrp ( 45 | .clk (clk_x5), 46 | .rst_n (rst_n_x5), 47 | 48 | .d_rise (ring_ctr[0]), 49 | .d_fall (ring_ctr[1]), 50 | .q (qp) 51 | ); 52 | 53 | ddr_out ddrn ( 54 | .clk (clk_x5), 55 | .rst_n (rst_n_x5), 56 | 57 | .d_rise (ring_ctr[5]), 58 | .d_fall (ring_ctr[6]), 59 | .q (qn) 60 | ); 61 | 62 | endmodule 63 | -------------------------------------------------------------------------------- /sdram/regs/sdram_ctrl_regs.yml: -------------------------------------------------------------------------------- 1 | name: sdram 2 | bus: apb 3 | addr: 16 4 | data: 32 5 | regs: 6 | - name: csr 7 | info: Control and status register 8 | bits: 9 | - {b: 0, name: en, access: rw, info: "Enable bus access to SDRAM, and start issuing refresh commands. Should not be asserted until after the SDRAM initialisation sequence has been issued (e.g. a PrechargeAll, some AutoRefreshes, and a ModeRegisterSet)."} 10 | - {b: 1, name: pu, access: rw, info: "Power up (start driving clock and assert clock enable). Must be asserted before using CMD_DIRECT for start-of-day initialisation."} 11 | - name: time 12 | info: | 13 | Configure SDRAM timing parameters. All times given in clock cycles. 14 | Unless otherwise specified, the minimum timing is 1 cycle, and this is 15 | encoded by a value of *0* in the relevant register field. Your SDRAM 16 | datasheet should provide these timings. 17 | bits: 18 | - {b: [2, 0], name: rc, access: rw, 19 | info: "tRC: Row cycle time, row activate to row activate (same bank). tRFC, refresh cycle time, is assumed to be equal to this value. If these values are different in your datasheet, take the larger one."} 20 | - {b: [6, 4], name: rcd, access: rw, 21 | info: "tRCD: RAS to CAS delay (same bank)."} 22 | - {b: [10, 8], name: rp, access: rw, 23 | info: "tRP: Precharge to refresh/row activate command (same bank)."} 24 | - {b: [14, 12], name: rrd, access: rw, 25 | info: "tRRD: Row activate to row activate delay (different banks)."} 26 | - {b: [18, 16], name: ras, access: rw, 27 | info: "tRAS: Row activate to precharge time (same bank)."} 28 | - {b: [22, 20], name: wr, access: rw, 29 | info: "tWR: Write recovery time. Last Write data to Precharge (same bank)"} 30 | - {b: [25, 24], name: cas, access: rw, 31 | info: "CAS latency. Should match the value programmed into SDRAM mode register."} 32 | - name: refresh 33 | info: "tREFI: Average refresh interval, in SDRAM clock cycles." 34 | bits: 35 | - {b: [11, 0], access: rw} 36 | - name: cmd_direct 37 | info: | 38 | Write to assert a command directly onto SDRAM e.g. Load Mode Register. 39 | Only to be used when bus is idle and CSR_EN is low (e.g. for start-of-day initialisation) 40 | bits: 41 | - {b: 0, name: we_n, access: wf} 42 | - {b: 1, name: cas_n, access: wf} 43 | - {b: 2, name: ras_n, access: wf} 44 | - {b: [15, 3], name: addr, access: wf} 45 | - {b: [29, 28], name: ba, access: wf} 46 | -------------------------------------------------------------------------------- /common/blinky.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // FPGA heartbeat light 19 | // (hence lack of reset!) 20 | 21 | module blinky #( 22 | parameter CLK_HZ = 12_000_000, 23 | parameter BLINK_HZ = 1, 24 | parameter FANCY = 0 25 | ) ( 26 | input wire clk, 27 | output wire blink 28 | ); 29 | 30 | localparam COUNT = CLK_HZ / BLINK_HZ / 2; 31 | parameter W_CTR = $clog2(COUNT); 32 | reg [W_CTR-1:0] ctr = {W_CTR{1'b0}}; 33 | 34 | reg blink_r = 1'b0; 35 | assign blink = blink_r; 36 | 37 | generate 38 | if (FANCY) begin: breathe 39 | localparam W_ACCUM = W_CTR > 8 ? 8 : W_CTR; 40 | 41 | reg rising = 1'b1; 42 | reg [W_ACCUM-1:0] accum = {W_ACCUM{1'b0}}; 43 | 44 | wire [W_CTR-1:0] ctr_next = rising ? ctr + 1'b1 : ctr - 1'b1; 45 | wire [W_ACCUM-1:0] brightness_linear = ctr[W_CTR-1 -: W_ACCUM]; 46 | wire [2*W_ACCUM-1:0] brightness_sq = brightness_linear * brightness_linear; 47 | 48 | always @ (posedge clk) begin 49 | ctr <= ctr_next; 50 | if (rising && ctr_next == COUNT - 1) 51 | rising <= 1'b0; 52 | else if (!rising && ctr_next == 0) 53 | rising <= 1'b1; 54 | {blink_r, accum} <= accum + brightness_sq[W_ACCUM +: W_ACCUM]; 55 | end 56 | end else begin: flash 57 | always @ (posedge clk) begin 58 | if (|ctr) begin 59 | ctr <= ctr - 1'b1; 60 | end else begin 61 | ctr <= COUNT - 1; 62 | blink_r <= !blink_r; 63 | end 64 | end 65 | end 66 | endgenerate 67 | 68 | endmodule 69 | -------------------------------------------------------------------------------- /common/clkdiv_frac.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Integer + fractional divider with 1st-order delta sigma pulse swallowing 19 | 20 | module clkdiv_frac #( 21 | parameter W_DIV_INT = 16, 22 | parameter W_DIV_FRAC = 8 23 | ) ( 24 | input wire clk, 25 | input wire rst_n, 26 | 27 | input wire en, 28 | input wire [W_DIV_INT-1:0] div_int, 29 | input wire [W_DIV_FRAC-1:0] div_frac, 30 | 31 | output reg clk_en 32 | ); 33 | 34 | reg [W_DIV_INT-1:0] ctr_int; 35 | reg [W_DIV_FRAC-1:0] ctr_frac; 36 | reg frac_carry; 37 | 38 | always @ (posedge clk or negedge rst_n) begin 39 | if (!rst_n) begin 40 | clk_en <= 1'b0; 41 | ctr_int <= {{W_DIV_INT-1{1'b0}}, 1'b1}; 42 | ctr_frac <= {W_DIV_FRAC{1'b0}}; 43 | frac_carry <= 1'b0; 44 | end else if (!en) begin 45 | // Keep everything clear so that we raise 46 | // clk_en on the cycle immediately following being enabled 47 | clk_en <= 1'b0; 48 | ctr_int <= {{W_DIV_INT-1{1'b0}}, 1'b1}; 49 | ctr_frac <= {W_DIV_FRAC{1'b0}}; 50 | frac_carry <= 1'b0; 51 | end else begin 52 | if (ctr_int == {{W_DIV_INT-1{1'b0}}, 1'b1}) begin 53 | {frac_carry, ctr_frac} <= ctr_frac + div_frac; 54 | ctr_int <= div_int + {{W_DIV_INT-1{1'b0}}, frac_carry}; 55 | clk_en <= 1'b1; 56 | end else begin 57 | clk_en <= 1'b0; 58 | ctr_int <= ctr_int - {{W_DIV_INT-1{1'b0}}, 1'b1}; 59 | end 60 | end 61 | end 62 | 63 | endmodule 64 | -------------------------------------------------------------------------------- /common/ddr_out.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Timing: 19 | // d_rise, d_fall are both sampled on the same rising clk edge. 20 | // d_rise goes straight to the pad, and d_fall follows a half-cycle later. 21 | 22 | module ddr_out ( 23 | input wire clk, 24 | input wire rst_n, 25 | 26 | input wire d_rise, 27 | input wire d_fall, 28 | output reg q 29 | ); 30 | 31 | `ifdef FPGA_ICE40 32 | 33 | reg d_fall_r; 34 | always @ (posedge clk or negedge rst_n) 35 | if (!rst_n) 36 | d_fall_r <= 1'b0; 37 | else 38 | d_fall_r <= d_fall; 39 | 40 | SB_IO #( 41 | .PIN_TYPE (6'b01_00_00), 42 | // | | | 43 | // | | \----- Registered input (and no clock!) 44 | // | \-------- DDR output 45 | // \----------- Permanent output enable 46 | .PULLUP (1'b 0) 47 | ) buffer ( 48 | .PACKAGE_PIN (q), 49 | .OUTPUT_CLK (clk), 50 | .INPUT_CLK (clk), 51 | .D_OUT_0 (d_rise), 52 | .D_OUT_1 (d_fall_r) 53 | ); 54 | 55 | `elsif FPGA_ECP5 56 | 57 | ODDRX1F oddr ( 58 | .D0 (d_rise), 59 | .D1 (d_fall), 60 | .SCLK (clk), 61 | .RST (0), 62 | .Q (q) 63 | ); 64 | 65 | `else 66 | 67 | // Blocking to intermediates, nonblocking to output, to avoid multiple NBA 68 | // deltas at the output 69 | reg q0, q1; 70 | always @ (posedge clk or negedge rst_n) 71 | if (!rst_n) 72 | {q0, q1} = 2'd0; 73 | else 74 | {q0, q1} = {d_rise, d_fall}; 75 | 76 | always @ (*) 77 | q <= clk ? q0 : q1; 78 | 79 | `endif 80 | 81 | endmodule 82 | -------------------------------------------------------------------------------- /common/skid_buffer.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2020 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // A pipestage register with buffered handshake 19 | // Similar to a DEPTH=2 FIFO, but no mux on the output side. 20 | 21 | module skid_buffer #( 22 | parameter WIDTH = 8 23 | ) ( 24 | input wire clk, 25 | input wire rst_n, 26 | 27 | input wire [WIDTH-1:0] wdata, 28 | input wire wen, 29 | output reg [WIDTH-1:0] rdata, 30 | input wire ren, 31 | 32 | input wire flush, 33 | 34 | output reg full, 35 | output reg empty, 36 | output wire [1:0] level 37 | ); 38 | 39 | // Flags 40 | 41 | always @ (posedge clk or negedge rst_n) begin 42 | if (!rst_n) begin 43 | empty <= 1'b1; 44 | full <= 1'b0; 45 | end else if (flush) begin 46 | empty <= 1'b1; 47 | full <= 1'b0; 48 | end else begin 49 | full <= (full || wen && !ren && !empty) && !(ren && !wen); 50 | empty <= (empty || ren && !wen && !full ) && !(wen && !ren); 51 | `ifdef FORMAL 52 | assert(!(full && empty)); 53 | assert(!(wen && full)); 54 | assert(!(ren && empty)); 55 | `endif 56 | end 57 | end 58 | 59 | assign level = {full, !(full || empty)}; 60 | 61 | // Datapath 62 | 63 | reg [WIDTH-1:0] skidbuf; 64 | 65 | always @ (posedge clk or negedge rst_n) begin 66 | if (!rst_n) begin 67 | rdata <= {WIDTH{1'b0}}; 68 | skidbuf <= {WIDTH{1'b0}}; 69 | end else begin 70 | if (wen && (ren || empty)) 71 | rdata <= wdata; 72 | else if (wen) 73 | skidbuf <= wdata; 74 | 75 | if (ren && full) 76 | rdata <= skidbuf; 77 | end 78 | end 79 | 80 | endmodule -------------------------------------------------------------------------------- /peris/spi_03h_xip/spi_03h_xip_regs.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * AUTOGENERATED BY REGBLOCK * 3 | * Do not edit manually. * 4 | * Edit the source file (or regblock utility) and regenerate. * 5 | *******************************************************************************/ 6 | 7 | #ifndef _XIP_REGS_H_ 8 | #define _XIP_REGS_H_ 9 | 10 | // Block name : xip 11 | // Bus type : apb 12 | // Bus data width : 32 13 | // Bus address width : 16 14 | 15 | #define XIP_CSR_OFFS 0 16 | #define XIP_TXDATA_OFFS 4 17 | #define XIP_RXDATA_OFFS 8 18 | 19 | /******************************************************************************* 20 | * CSR * 21 | *******************************************************************************/ 22 | 23 | // Control and status register 24 | 25 | // Field: CSR_DIRECT Access: RW 26 | // If 1, enable direct mode. Chip select is held asserted until direct mode is 27 | // disabled, and individual bytes can be written to TXDATA and then read from 28 | // RXDATA. If you enable direct mode whilst executing from XIP, you're gonna 29 | // have a bad time. 30 | #define XIP_CSR_DIRECT_LSB 0 31 | #define XIP_CSR_DIRECT_BITS 1 32 | #define XIP_CSR_DIRECT_MASK 0x1 33 | // Field: CSR_BUSY Access: ROV 34 | // Reads as 1 when a direct mode transfer is in progress. Note a direct mode 35 | // transfer takes precisely 16 cycles (in between the APB write and readback, so 36 | // at least 19 cycles total), so you could insert a precise delay in your code 37 | // instead of polling this bit. 38 | #define XIP_CSR_BUSY_LSB 1 39 | #define XIP_CSR_BUSY_BITS 1 40 | #define XIP_CSR_BUSY_MASK 0x2 41 | 42 | /******************************************************************************* 43 | * TXDATA * 44 | *******************************************************************************/ 45 | 46 | // Direct mode transmit data 47 | 48 | // Field: TXDATA Access: WF 49 | #define XIP_TXDATA_LSB 0 50 | #define XIP_TXDATA_BITS 8 51 | #define XIP_TXDATA_MASK 0xff 52 | 53 | /******************************************************************************* 54 | * RXDATA * 55 | *******************************************************************************/ 56 | 57 | // Direct mode receive data 58 | 59 | // Field: RXDATA Access: RF 60 | #define XIP_RXDATA_LSB 0 61 | #define XIP_RXDATA_BITS 8 62 | #define XIP_RXDATA_MASK 0xff 63 | 64 | #endif // _XIP_REGS_H_ 65 | -------------------------------------------------------------------------------- /mem/ahb_async_sram.v: -------------------------------------------------------------------------------- 1 | module ahb_async_sram #( 2 | parameter W_DATA = 32, 3 | parameter W_ADDR = 32, 4 | parameter DEPTH = 1 << 11, 5 | parameter W_SRAM_ADDR = $clog2(DEPTH) // Let this default 6 | ) ( 7 | // Globals 8 | input wire clk, 9 | input wire rst_n, 10 | 11 | // AHB lite slave interface 12 | output wire ahbls_hready_resp, 13 | input wire ahbls_hready, 14 | output wire ahbls_hresp, 15 | input wire [W_ADDR-1:0] ahbls_haddr, 16 | input wire ahbls_hwrite, 17 | input wire [1:0] ahbls_htrans, 18 | input wire [2:0] ahbls_hsize, 19 | input wire [2:0] ahbls_hburst, 20 | input wire [3:0] ahbls_hprot, 21 | input wire ahbls_hmastlock, 22 | input wire [W_DATA-1:0] ahbls_hwdata, 23 | output wire [W_DATA-1:0] ahbls_hrdata, 24 | 25 | output reg [W_SRAM_ADDR-1:0] sram_addr, 26 | inout wire [W_DATA-1:0] sram_dq, 27 | output reg sram_ce_n, 28 | output wire sram_we_n, // DDR output 29 | output reg sram_oe_n, 30 | output reg [W_DATA/8-1:0] sram_byte_n 31 | ); 32 | 33 | parameter W_BYTEADDR = $clog2(W_DATA / 8); 34 | 35 | // Tie off unused AHBL signals 36 | 37 | assign ahbls_hready_resp = 1'b1; 38 | assign ahbls_hresp = 1'b0; 39 | 40 | // Combinatorially generate the byte strobes from address + size buses 41 | 42 | wire [W_DATA/8-1:0] bytemask_noshift = ~({W_DATA/8{1'b1}} << (8'h1 << ahbls_hsize)); 43 | wire [W_DATA/8-1:0] bytemask = bytemask_noshift << ahbls_haddr[W_BYTEADDR-1:0]; 44 | 45 | // AHBL request marshalling/translation 46 | 47 | wire we_next = ahbls_htrans[1] && ahbls_hwrite && ahbls_hready; 48 | 49 | always @ (posedge clk or negedge rst_n) begin 50 | if (!rst_n) begin 51 | sram_addr <= {W_SRAM_ADDR{1'b0}}; 52 | sram_ce_n <= 1'b1; 53 | sram_oe_n <= 1'b1; 54 | sram_byte_n <= {W_DATA/8{1'b1}}; 55 | end else if (ahbls_hready) begin 56 | if (ahbls_htrans[1]) begin 57 | sram_addr <= ahbls_haddr[W_BYTEADDR +: W_SRAM_ADDR]; 58 | sram_ce_n <= 1'b0; 59 | sram_oe_n <= ahbls_hwrite; 60 | sram_byte_n <= ~bytemask; 61 | end else begin 62 | sram_ce_n <= 1'b1; 63 | sram_oe_n <= 1'b1; 64 | sram_byte_n <= {W_DATA/8{1'b1}}; 65 | end 66 | end 67 | end 68 | 69 | ddr_out we_ddr ( 70 | .clk (clk), 71 | .rst_n (rst_n), 72 | .d_rise (1'b1), 73 | .d_fall (!we_next), 74 | .q (sram_we_n) 75 | ); 76 | 77 | // SRAM tristating 78 | 79 | wire [W_DATA-1:0] sram_q; 80 | assign ahbls_hrdata = sram_q & {W_DATA{!sram_oe_n}}; 81 | 82 | tristate_io iobuf [W_DATA-1:0] ( 83 | .out (ahbls_hwdata), 84 | .oe (sram_oe_n), 85 | .in (sram_q), 86 | .pad (sram_dq) 87 | ); 88 | 89 | endmodule -------------------------------------------------------------------------------- /common/fpga_reset.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Two-stage reset generator. 19 | // First stage consists of a shift register, which is more reliable 20 | // immediately after power-on when PLLs and external resets can be glitchy. 21 | // Second stage is a counter, which is more efficient for long reset delays 22 | // (e.g. on iCE40 where the BRAMs are invalid for ~3 us after reset) 23 | 24 | module fpga_reset #( 25 | parameter SHIFT = 5, 26 | parameter COUNT = 0, 27 | parameter W_CTR = $clog2(COUNT + 1) // let this default 28 | ) ( 29 | input wire clk, 30 | input wire force_rst_n, // tie to e.g. PLL locks, (synchronised) external button 31 | output wire rst_n 32 | ); 33 | 34 | (* keep = 1'b1 *) wire stage1_out; 35 | 36 | generate 37 | if (SHIFT != 0) begin: has_shifter 38 | (* keep = 1'b1 *) reg [SHIFT-1:0] shift = {SHIFT{1'b0}}; 39 | always @ (posedge clk or negedge force_rst_n) begin 40 | if (!force_rst_n) begin 41 | shift <= {SHIFT{1'b0}}; 42 | end else begin 43 | shift <= (shift << 1) | 1'b1; 44 | end 45 | end 46 | assign stage1_out = shift[SHIFT-1]; 47 | end else begin: no_shifter 48 | assign stage1_out = force_rst_n; 49 | end 50 | endgenerate 51 | 52 | generate 53 | if (COUNT != 0) begin: has_counter 54 | (* keep = 1'b1 *) reg [W_CTR-1:0] ctr = COUNT; 55 | (* keep = 1'b1 *) reg ctr_zero = 1'b0; 56 | always @ (posedge clk or negedge stage1_out) begin 57 | if (!stage1_out) begin 58 | ctr <= COUNT; 59 | ctr_zero <= 1'b0; 60 | end else begin 61 | ctr <= ctr - |ctr; 62 | ctr_zero <= ~|ctr; 63 | end 64 | end 65 | assign rst_n = ctr_zero; 66 | end else begin: no_counter 67 | assign rst_n = stage1_out; 68 | end 69 | endgenerate 70 | 71 | endmodule 72 | -------------------------------------------------------------------------------- /sdram/io/sdram_dq_buf.v: -------------------------------------------------------------------------------- 1 | // Fully-registered tristate IO, for driving DQs on SDR SDRAM. Uses internal 2 | // registers of IO cell, where applicable. 3 | 4 | module sdram_dq_buf ( 5 | input wire clk, 6 | input wire rst_n, 7 | 8 | input wire o, // output from core to pad 9 | input wire oe, // active-high output enable 10 | output wire i, // input to core from pad 11 | inout wire dq // pad connection 12 | ); 13 | 14 | `ifdef FPGA_ECP5 15 | 16 | wire o_pad; 17 | wire oe_pad; 18 | wire i_pad; 19 | 20 | // The syn_useioff attribute tells nextpnr to pack these flops into the IO 21 | // cell (or die trying). The IO cell must be the flop's only load. 22 | // Flops driven with identical signals (e.g. the direction of a 23 | // parallel data bus) may be merged during synthesis, which breaks the 24 | // single-load requirement for IO packing. 25 | // 26 | // Putting a keep attribute on a `reg` doesn't prevent flop merging. Yosys 27 | // does check for this attribute in opt_merge, but it sees its own $dff cell 28 | // created during proc, and the keep attribute doesn't seem to be propagated. 29 | // Dodgy workaround is to instantiate TRELLIS_FF directly. 30 | 31 | (*syn_useioff*) (*keep*) TRELLIS_FF #( 32 | .GSR("DISABLED"), 33 | .CEMUX("1"), 34 | .CLKMUX("CLK"), 35 | .LSRMUX("LSR"), 36 | .REGSET("RESET") 37 | ) o_reg ( 38 | .CLK (clk), 39 | .LSR (1'b0), 40 | .DI (o), 41 | .Q (o_pad) 42 | ); 43 | 44 | (*syn_useioff*) (*keep*) TRELLIS_FF #( 45 | .GSR("DISABLED"), 46 | .CEMUX("1"), 47 | .CLKMUX("CLK"), 48 | .LSRMUX("LSR"), 49 | .REGSET("RESET") 50 | ) oe_reg ( 51 | .CLK (clk), 52 | .LSR (1'b0), 53 | .DI (!oe), // pad signal is active-low 54 | .Q (oe_pad) 55 | ); 56 | 57 | // Capture is aligned with outgoing SDCLK posedge (which is on clk negedge, so 58 | // that SDCLK is centre-aligned with our outputs) 59 | IDDRX1F iddr ( 60 | .D (i_pad), 61 | .SCLK (clk), 62 | .RST (1'b0), 63 | .Q0 (/* unused */), 64 | .Q1 (i) 65 | ); 66 | 67 | TRELLIS_IO #( 68 | .DIR("BIDIR") 69 | ) iobuf ( 70 | .B (dq), 71 | .I (o_pad), // Lattice use I for core->pad for some fuckawful reason 72 | .O (i_pad), 73 | .T (oe_pad) 74 | ); 75 | 76 | `else 77 | 78 | reg i_negedge; 79 | 80 | always @ (negedge clk or negedge rst_n) begin 81 | if (!rst_n) begin 82 | i_negedge <= 1'b0; 83 | end else begin 84 | i_negedge <= dq; 85 | end 86 | end 87 | 88 | reg o_reg; 89 | reg oe_reg; 90 | reg i_reg; 91 | 92 | always @ (posedge clk or negedge rst_n) begin 93 | if (!rst_n) begin 94 | o_reg <= 1'b0; 95 | oe_reg <= 1'b0; 96 | i_reg <= 1'b0; 97 | end else begin 98 | o_reg <= o; 99 | oe_reg <= oe; 100 | i_reg <= i_negedge; 101 | end 102 | end 103 | 104 | assign dq = oe_reg ? o_reg : 1'bz; 105 | assign i = i_reg; 106 | 107 | `endif 108 | 109 | endmodule 110 | -------------------------------------------------------------------------------- /video/dvi_serialiser.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2020 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | module dvi_serialiser #( 19 | // Commoning up the ring counters on iCE40 gives much better PLB packing due 20 | // to larger CE groups (best to leave alone if not at the ragged edge): 21 | parameter EXTERNAL_RING_COUNTERS = 0 22 | ) ( 23 | input wire clk_pix, 24 | input wire rst_n_pix, 25 | input wire [1:0] external_ctr_pix, 26 | input wire clk_x5, 27 | input wire rst_n_x5, 28 | input wire [9:0] external_ctr_x5, 29 | 30 | input wire [9:0] d, 31 | output wire qp, 32 | output wire qn 33 | ); 34 | 35 | reg [9:0] d_delay; 36 | wire [1:0] data_x5; 37 | 38 | always @ (posedge clk_pix) begin 39 | d_delay <= d; 40 | end 41 | 42 | gearbox #( 43 | .W_IN (10), 44 | .W_OUT (2), 45 | `ifdef FPGA_ICE40 46 | .CE_GROUPING_FACTOR (5), 47 | `endif 48 | .USE_EXTERNAL_COUNTERS (EXTERNAL_RING_COUNTERS), 49 | .STORAGE_SIZE (20) 50 | ) gearbox_u ( 51 | .clk_in (clk_pix), 52 | .rst_n_in (rst_n_pix), 53 | .din (d_delay), 54 | 55 | .clk_out (clk_x5), 56 | .rst_n_out (rst_n_x5), 57 | .dout (data_x5), 58 | 59 | .external_ctr_in (external_ctr_pix), 60 | .external_ctr_out (external_ctr_x5) 61 | ); 62 | 63 | reg [1:0] data_x5_delay; 64 | reg [1:0] data_x5_ndelay; 65 | 66 | always @ (posedge clk_x5) begin 67 | data_x5_delay <= data_x5; 68 | data_x5_ndelay <= ~data_x5; 69 | end 70 | 71 | ddr_out ddrp ( 72 | .clk (clk_x5), 73 | .rst_n (rst_n_x5), 74 | 75 | .d_rise (data_x5_delay[0]), 76 | .d_fall (data_x5_delay[1]), 77 | .q (qp) 78 | ); 79 | 80 | ddr_out ddrn ( 81 | .clk (clk_x5), 82 | .rst_n (rst_n_x5), 83 | 84 | .d_rise (data_x5_ndelay[0]), 85 | .d_fall (data_x5_ndelay[1]), 86 | .q (qn) 87 | ); 88 | 89 | endmodule 90 | -------------------------------------------------------------------------------- /common/onehot_priority_dynamic.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | module onehot_priority_dynamic #( 19 | parameter N_REQ = 8, 20 | parameter N_PRIORITIES = 2, 21 | parameter HIGHEST_WINS = 1, // If 1, numerically highest level has greatest priority. Otherwise, level 0 wins. 22 | parameter W_PRIORITY = $clog2(N_PRIORITIES) // do not modify 23 | ) ( 24 | input wire [N_REQ*W_PRIORITY-1:0] level, 25 | input wire [N_REQ-1:0] req, 26 | input wire [N_REQ-1:0] gnt 27 | ); 28 | 29 | // The steps are: 30 | // - Stratify requests according to their level 31 | // - Select the highest level with active requests 32 | // - Mask only those requests at this level 33 | // - Do a standard priority select on those requests as a tie break 34 | 35 | reg [N_REQ-1:0] req_stratified [0:N_PRIORITIES-1]; 36 | reg [N_PRIORITIES-1:0] level_has_req; 37 | 38 | always @ (*) begin: stratify 39 | integer i, j; 40 | for (i = 0; i < N_PRIORITIES; i = i + 1) begin 41 | for (j = 0; j < N_REQ; j = j + 1) begin 42 | req_stratified[i][j] = req[j] && level[W_PRIORITY * j +: W_PRIORITY] == i; 43 | end 44 | level_has_req[i] = |req_stratified[i]; 45 | end 46 | end 47 | 48 | wire [N_PRIORITIES-1:0] active_layer_sel; 49 | 50 | onehot_priority #( 51 | .W_INPUT (N_PRIORITIES), 52 | .HIGHEST_WINS (HIGHEST_WINS) 53 | ) prisel_layer ( 54 | .in (level_has_req), 55 | .out (active_layer_sel) 56 | ); 57 | 58 | reg [N_REQ-1:0] reqs_from_highest_layer; 59 | 60 | always @ (*) begin: mux_reqs_by_layer 61 | integer i; 62 | reqs_from_highest_layer = {N_REQ{1'b0}}; 63 | for (i = 0; i < N_PRIORITIES; i = i + 1) 64 | reqs_from_highest_layer = reqs_from_highest_layer | 65 | (req_stratified[i] & {N_REQ{active_layer_sel[i]}}); 66 | end 67 | 68 | onehot_priority #( 69 | .W_INPUT (N_REQ) 70 | ) prisel_tiebreak ( 71 | .in (reqs_from_highest_layer), 72 | .out (gnt) 73 | ); 74 | 75 | endmodule 76 | -------------------------------------------------------------------------------- /common/nbit_sync.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // N-bit synchroniser 19 | 20 | // Shepherd a multibit signal safely between two clock domains, with some delay. 21 | // Uses valid/ack handshake (aka 2-bit Gray counter, 1 bit per clock domain) 22 | // Both clocks must be free-running! 23 | 24 | module nbit_sync #( 25 | parameter W_DATA = 32, 26 | parameter SYNC_STAGES = 1 // must be >= 1 27 | ) ( 28 | input wire wrst_n, 29 | input wire wclk, 30 | input wire [W_DATA-1:0] wdata, 31 | 32 | input wire rrst_n, 33 | input wire rclk, 34 | output reg [W_DATA-1:0] rdata 35 | ); 36 | 37 | reg wvalid; // Data valid, driven in W 38 | reg [SYNC_STAGES-1:0] wack; // Data acknowledge, sync'd 39 | reg [SYNC_STAGES-1:0] rvalid; // Data valid, sync'd 40 | reg rack; // Data acknowledge, driven in R 41 | reg [W_DATA-1:0] cross_reg; // The signal being synchronised 42 | 43 | // Write state machine 44 | 45 | always @ (posedge wclk or negedge wrst_n) begin 46 | if (!wrst_n) begin 47 | wvalid <= 1'b0; 48 | wack <= {SYNC_STAGES{1'b0}}; 49 | cross_reg <= {W_DATA{1'b0}}; 50 | end else begin 51 | wack <= (wack >> 1) | (rack << SYNC_STAGES - 1); 52 | if (wvalid && wack[0]) begin 53 | wvalid <= 1'b0; 54 | end else if (!wvalid && !wack[0]) begin 55 | wvalid <= 1'b1; 56 | cross_reg <= wdata; 57 | end 58 | end 59 | end 60 | 61 | // Read state machine 62 | 63 | always @ (posedge rclk or negedge rrst_n) begin 64 | if (!rrst_n) begin 65 | rvalid <= {SYNC_STAGES{1'b0}}; 66 | rack <= 1'b0; 67 | rdata <= {W_DATA{1'b0}}; 68 | end else begin 69 | rvalid <= (rvalid >> 1 ) | (wvalid << SYNC_STAGES - 1); 70 | if (rack && !rvalid[0]) begin 71 | rack <= 1'b0; 72 | end else if (rvalid[0] && !rack) begin 73 | rack <= 1'b1; 74 | rdata <= cross_reg; 75 | end 76 | end 77 | end 78 | 79 | endmodule -------------------------------------------------------------------------------- /peris/spi_03h_xip/spi_03h_xip_regs.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * AUTOGENERATED BY REGBLOCK * 3 | * Do not edit manually. * 4 | * Edit the source file (or regblock utility) and regenerate. * 5 | *******************************************************************************/ 6 | 7 | // Block name : xip 8 | // Bus type : apb 9 | // Bus data width : 32 10 | // Bus address width : 16 11 | 12 | module xip_regs ( 13 | input wire clk, 14 | input wire rst_n, 15 | 16 | // APB Port 17 | input wire apbs_psel, 18 | input wire apbs_penable, 19 | input wire apbs_pwrite, 20 | input wire [15:0] apbs_paddr, 21 | input wire [31:0] apbs_pwdata, 22 | output wire [31:0] apbs_prdata, 23 | output wire apbs_pready, 24 | output wire apbs_pslverr, 25 | 26 | // Register interfaces 27 | output reg csr_direct_o, 28 | input wire csr_busy_i, 29 | output reg [7:0] txdata_o, 30 | output reg txdata_wen, 31 | input wire [7:0] rxdata_i, 32 | output reg rxdata_ren 33 | ); 34 | 35 | // APB adapter 36 | wire [31:0] wdata = apbs_pwdata; 37 | reg [31:0] rdata; 38 | wire wen = apbs_psel && apbs_penable && apbs_pwrite; 39 | wire ren = apbs_psel && apbs_penable && !apbs_pwrite; 40 | wire [15:0] addr = apbs_paddr & 16'hc; 41 | assign apbs_prdata = rdata; 42 | assign apbs_pready = 1'b1; 43 | assign apbs_pslverr = 1'b0; 44 | 45 | localparam ADDR_CSR = 0; 46 | localparam ADDR_TXDATA = 4; 47 | localparam ADDR_RXDATA = 8; 48 | 49 | wire __csr_wen = wen && addr == ADDR_CSR; 50 | wire __csr_ren = ren && addr == ADDR_CSR; 51 | wire __txdata_wen = wen && addr == ADDR_TXDATA; 52 | wire __txdata_ren = ren && addr == ADDR_TXDATA; 53 | wire __rxdata_wen = wen && addr == ADDR_RXDATA; 54 | wire __rxdata_ren = ren && addr == ADDR_RXDATA; 55 | 56 | wire csr_direct_wdata = wdata[0]; 57 | wire csr_direct_rdata; 58 | wire csr_busy_wdata = wdata[1]; 59 | wire csr_busy_rdata; 60 | wire [31:0] __csr_rdata = {30'h0, csr_busy_rdata, csr_direct_rdata}; 61 | assign csr_direct_rdata = csr_direct_o; 62 | assign csr_busy_rdata = csr_busy_i; 63 | 64 | wire [7:0] txdata_wdata = wdata[7:0]; 65 | wire [7:0] txdata_rdata; 66 | wire [31:0] __txdata_rdata = {24'h0, txdata_rdata}; 67 | assign txdata_rdata = 8'h0; 68 | 69 | wire [7:0] rxdata_wdata = wdata[7:0]; 70 | wire [7:0] rxdata_rdata; 71 | wire [31:0] __rxdata_rdata = {24'h0, rxdata_rdata}; 72 | assign rxdata_rdata = rxdata_i; 73 | 74 | always @ (*) begin 75 | case (addr) 76 | ADDR_CSR: rdata = __csr_rdata; 77 | ADDR_TXDATA: rdata = __txdata_rdata; 78 | ADDR_RXDATA: rdata = __rxdata_rdata; 79 | default: rdata = 32'h0; 80 | endcase 81 | txdata_wen = __txdata_wen; 82 | txdata_o = txdata_wdata; 83 | rxdata_ren = __rxdata_ren; 84 | end 85 | 86 | always @ (posedge clk or negedge rst_n) begin 87 | if (!rst_n) begin 88 | csr_direct_o <= 1'h0; 89 | end else begin 90 | if (__csr_wen) 91 | csr_direct_o <= csr_direct_wdata; 92 | end 93 | end 94 | 95 | endmodule 96 | -------------------------------------------------------------------------------- /mem/sram_sync_1r1w.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2020 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Inference/injection wrapper for one-write one-read synchronous memory 19 | 20 | `default_nettype none 21 | 22 | module sram_sync_1r1w #( 23 | parameter WIDTH = 16, 24 | parameter DEPTH = 1 << 8, 25 | parameter WRITE_GRANULE = WIDTH, 26 | parameter R2W_FORWARDING = 0, 27 | parameter PRELOAD_FILE = "", 28 | parameter W_ADDR = $clog2(DEPTH) // let this default 29 | ) ( 30 | input wire clk, 31 | 32 | input wire [W_ADDR-1:0] waddr, 33 | input wire [WIDTH-1:0] wdata, 34 | input wire [WIDTH/WRITE_GRANULE-1:0] wen, 35 | 36 | input wire [W_ADDR-1:0] raddr, 37 | output wire [WIDTH-1:0] rdata, 38 | input wire ren 39 | ); 40 | 41 | `ifdef YOSYS 42 | (* no_rw_check *) 43 | `endif 44 | reg [WIDTH-1:0] mem [0:DEPTH-1]; 45 | 46 | initial if (PRELOAD_FILE != "" ) begin: preload 47 | $readmemh(PRELOAD_FILE, mem); 48 | end 49 | 50 | reg [WIDTH-1:0] rdata_raw; 51 | always @ (posedge clk) begin: read_port 52 | if (ren) begin 53 | rdata_raw <= mem[raddr]; 54 | end 55 | end 56 | 57 | always @ (posedge clk) begin: write_port 58 | integer i; 59 | for (i = 0; i < WIDTH / WRITE_GRANULE; i = i + 1) begin 60 | if (wen[i]) begin 61 | mem[waddr][i * WRITE_GRANULE +: WRITE_GRANULE] <= wdata[i * WRITE_GRANULE +: WRITE_GRANULE]; 62 | end 63 | end 64 | end 65 | 66 | // Optional forwarding of write to read data when a read and write of the same 67 | // address are coincident (without this logic you can get garbage) 68 | 69 | generate 70 | if (R2W_FORWARDING == 0) begin: no_r2w_forwarding 71 | assign rdata = rdata_raw; 72 | end else begin: r2w_forwarding 73 | genvar g; 74 | 75 | reg [W_ADDR-1:0] raddr_prev; 76 | reg [W_ADDR-1:0] waddr_prev; 77 | reg [WIDTH-1:0] wdata_prev; 78 | reg [WIDTH/WRITE_GRANULE-1:0] wen_prev; 79 | 80 | always @ (posedge clk) begin 81 | raddr_prev <= raddr; 82 | waddr_prev <= waddr; 83 | wdata_prev <= wdata; 84 | wen_prev <= wen; 85 | end 86 | 87 | for (g = 0; g < WIDTH / WRITE_GRANULE; g = g + 1) begin 88 | assign rdata[g * WRITE_GRANULE +: WRITE_GRANULE] = raddr_prev == waddr_prev && wen_prev[g] ? 89 | wdata_prev[g * WRITE_GRANULE +: WRITE_GRANULE] : rdata_raw[g * WRITE_GRANULE +: WRITE_GRANULE]; 90 | end 91 | 92 | end 93 | endgenerate 94 | 95 | endmodule 96 | 97 | `ifndef YOSYS 98 | `default_nettype wire 99 | `endif 100 | 101 | -------------------------------------------------------------------------------- /test/ahb_cache_writeback/tag_zeroes.hex: -------------------------------------------------------------------------------- 1 | 00000000 2 | 00000000 3 | 00000000 4 | 00000000 5 | 00000000 6 | 00000000 7 | 00000000 8 | 00000000 9 | 00000000 10 | 00000000 11 | 00000000 12 | 00000000 13 | 00000000 14 | 00000000 15 | 00000000 16 | 00000000 17 | 00000000 18 | 00000000 19 | 00000000 20 | 00000000 21 | 00000000 22 | 00000000 23 | 00000000 24 | 00000000 25 | 00000000 26 | 00000000 27 | 00000000 28 | 00000000 29 | 00000000 30 | 00000000 31 | 00000000 32 | 00000000 33 | 00000000 34 | 00000000 35 | 00000000 36 | 00000000 37 | 00000000 38 | 00000000 39 | 00000000 40 | 00000000 41 | 00000000 42 | 00000000 43 | 00000000 44 | 00000000 45 | 00000000 46 | 00000000 47 | 00000000 48 | 00000000 49 | 00000000 50 | 00000000 51 | 00000000 52 | 00000000 53 | 00000000 54 | 00000000 55 | 00000000 56 | 00000000 57 | 00000000 58 | 00000000 59 | 00000000 60 | 00000000 61 | 00000000 62 | 00000000 63 | 00000000 64 | 00000000 65 | 00000000 66 | 00000000 67 | 00000000 68 | 00000000 69 | 00000000 70 | 00000000 71 | 00000000 72 | 00000000 73 | 00000000 74 | 00000000 75 | 00000000 76 | 00000000 77 | 00000000 78 | 00000000 79 | 00000000 80 | 00000000 81 | 00000000 82 | 00000000 83 | 00000000 84 | 00000000 85 | 00000000 86 | 00000000 87 | 00000000 88 | 00000000 89 | 00000000 90 | 00000000 91 | 00000000 92 | 00000000 93 | 00000000 94 | 00000000 95 | 00000000 96 | 00000000 97 | 00000000 98 | 00000000 99 | 00000000 100 | 00000000 101 | 00000000 102 | 00000000 103 | 00000000 104 | 00000000 105 | 00000000 106 | 00000000 107 | 00000000 108 | 00000000 109 | 00000000 110 | 00000000 111 | 00000000 112 | 00000000 113 | 00000000 114 | 00000000 115 | 00000000 116 | 00000000 117 | 00000000 118 | 00000000 119 | 00000000 120 | 00000000 121 | 00000000 122 | 00000000 123 | 00000000 124 | 00000000 125 | 00000000 126 | 00000000 127 | 00000000 128 | 00000000 129 | 00000000 130 | 00000000 131 | 00000000 132 | 00000000 133 | 00000000 134 | 00000000 135 | 00000000 136 | 00000000 137 | 00000000 138 | 00000000 139 | 00000000 140 | 00000000 141 | 00000000 142 | 00000000 143 | 00000000 144 | 00000000 145 | 00000000 146 | 00000000 147 | 00000000 148 | 00000000 149 | 00000000 150 | 00000000 151 | 00000000 152 | 00000000 153 | 00000000 154 | 00000000 155 | 00000000 156 | 00000000 157 | 00000000 158 | 00000000 159 | 00000000 160 | 00000000 161 | 00000000 162 | 00000000 163 | 00000000 164 | 00000000 165 | 00000000 166 | 00000000 167 | 00000000 168 | 00000000 169 | 00000000 170 | 00000000 171 | 00000000 172 | 00000000 173 | 00000000 174 | 00000000 175 | 00000000 176 | 00000000 177 | 00000000 178 | 00000000 179 | 00000000 180 | 00000000 181 | 00000000 182 | 00000000 183 | 00000000 184 | 00000000 185 | 00000000 186 | 00000000 187 | 00000000 188 | 00000000 189 | 00000000 190 | 00000000 191 | 00000000 192 | 00000000 193 | 00000000 194 | 00000000 195 | 00000000 196 | 00000000 197 | 00000000 198 | 00000000 199 | 00000000 200 | 00000000 201 | 00000000 202 | 00000000 203 | 00000000 204 | 00000000 205 | 00000000 206 | 00000000 207 | 00000000 208 | 00000000 209 | 00000000 210 | 00000000 211 | 00000000 212 | 00000000 213 | 00000000 214 | 00000000 215 | 00000000 216 | 00000000 217 | 00000000 218 | 00000000 219 | 00000000 220 | 00000000 221 | 00000000 222 | 00000000 223 | 00000000 224 | 00000000 225 | 00000000 226 | 00000000 227 | 00000000 228 | 00000000 229 | 00000000 230 | 00000000 231 | 00000000 232 | 00000000 233 | 00000000 234 | 00000000 235 | 00000000 236 | 00000000 237 | 00000000 238 | 00000000 239 | 00000000 240 | 00000000 241 | 00000000 242 | 00000000 243 | 00000000 244 | 00000000 245 | 00000000 246 | 00000000 247 | 00000000 248 | 00000000 249 | 00000000 250 | 00000000 251 | 00000000 252 | 00000000 253 | 00000000 254 | 00000000 255 | 00000000 256 | 00000000 257 | -------------------------------------------------------------------------------- /mem/behav/sram_async.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // 19 | // Simulation model for GS74116AGP SRAM (and similar) 20 | // It might also be synthesisable, but I really don't recommend it 21 | // 22 | // Truth table from datasheet 23 | // 24 | // -----+------+------+------+------+---------+--------- 25 | // CE_n | OE_n | WE_n | LB_n | UB_n | DQ[7:0] | DQ[15:8] 26 | // -----+------+------+------+------+---------+--------- 27 | // 1 | X | X | X | X | Hi-Z | Hi-Z 28 | // -----+------+------+------+------+---------+--------- 29 | // 0 | 0 | 1 | 0 | 0 | Read | Read 30 | // 0 | 0 | 1 | 1 | 0 | Hi-Z | Read 31 | // 0 | 0 | 1 | 0 | 1 | Read | Hi-Z 32 | // -----+------+------+------+------+---------+--------- 33 | // 0 | X | 0 | 0 | 0 | Write | Write 34 | // 0 | X | 0 | 1 | 0 | Hi-Z | Write 35 | // 0 | X | 0 | 0 | 1 | Write | Hi-Z 36 | // -----+------+------+------+------+---------+--------- 37 | // 0 | 1 | 1 | X | X | Hi-Z | Hi-Z 38 | // 0 | X | X | 1 | 1 | Hi-Z | Hi-Z 39 | // 40 | // Read timing: assert address, CE, OE and byte enables, and wait for 10 ns 41 | // Write timing: assert address, CE, byte enables, data. Wait 3 ns. 42 | // Assert WE. Wait 7 ns. 43 | // Data sampled by real SRAM on WE rising edge, (deassertion; active low!) 44 | // but to avoid races due to lack of datapath delay, 45 | // this model captures on falling edge. 46 | 47 | module sram_async #( 48 | parameter W_DATA = 16, // Must be power of 2, >= 8 49 | parameter DEPTH = 1 << 18, // == 0.5 MiB for 16 bit interface 50 | parameter PRELOAD_FILE = "", 51 | parameter W_ADDR = $clog2(DEPTH), // Let this default 52 | parameter W_BYTES = W_DATA / 8 // Let this default 53 | ) ( 54 | input wire [W_ADDR-1:0] addr, 55 | inout wire [W_DATA-1:0] dq, 56 | 57 | input wire ce_n, 58 | input wire oe_n, 59 | input wire we_n, 60 | input wire [W_BYTES-1:0] ben_n 61 | ); 62 | 63 | reg [W_DATA-1:0] dq_r; 64 | assign dq = dq_r; 65 | 66 | reg [W_DATA-1:0] mem [0:DEPTH-1]; 67 | 68 | initial begin: preload 69 | `ifdef SIM 70 | integer n; 71 | for (n = 0; n < DEPTH; n = n + 1) 72 | mem[n] = {W_DATA{1'b0}}; 73 | `endif 74 | if (PRELOAD_FILE != "") 75 | $readmemh(PRELOAD_FILE, mem); 76 | end 77 | 78 | always @ (*) begin: readport 79 | integer i; 80 | for (i = 0; i < W_BYTES; i = i + 1) begin 81 | dq_r[i * 8 +: 8] = !ce_n && !oe_n && we_n && !ben_n[i] ? 82 | mem[addr][i * 8 +: 8] : 8'hz; 83 | end 84 | end 85 | 86 | always @ (negedge we_n) begin: writeport 87 | integer i; 88 | for (i = 0; i < W_BYTES; i = i + 1) begin 89 | if (!ce_n && !ben_n[i]) 90 | mem[addr][i * 8 +: 8] <= dq[i * 8 +: 8]; 91 | end 92 | end 93 | 94 | endmodule 95 | -------------------------------------------------------------------------------- /sdram/io/sdram_phy.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2020 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // IO instantiations for ahbl_sdram. These are separated out so that they can 19 | // be instantiated in the top-level FPGA wrapper, which allows full-system 20 | // simulation using 2-state simulators like CXXRTL. 21 | 22 | `default_nettype none 23 | 24 | module sdram_phy #( 25 | parameter W_SDRAM_BANKSEL = 2, 26 | parameter W_SDRAM_ADDR = 13, 27 | parameter W_SDRAM_DATA = 16 28 | ) ( 29 | input wire clk, 30 | input wire rst_n, 31 | 32 | // Interface to SDRAM controller 33 | input wire ctrl_clk_enable, 34 | input wire [W_SDRAM_BANKSEL-1:0] ctrl_ba_next, 35 | input wire [W_SDRAM_ADDR-1:0] ctrl_a_next, 36 | input wire [W_SDRAM_DATA/8-1:0] ctrl_dqm_next, 37 | 38 | input wire [W_SDRAM_DATA-1:0] ctrl_dq_o_next, 39 | input wire ctrl_dq_oe_next, 40 | output wire [W_SDRAM_DATA-1:0] ctrl_dq_i, 41 | 42 | input wire ctrl_clke_next, 43 | input wire ctrl_cs_n_next, 44 | input wire ctrl_ras_n_next, 45 | input wire ctrl_cas_n_next, 46 | input wire ctrl_we_n_next, 47 | 48 | // Connection to external SDRAM device 49 | output wire sdram_clk, 50 | output wire [W_SDRAM_ADDR-1:0] sdram_a, 51 | inout wire [W_SDRAM_DATA-1:0] sdram_dq, 52 | output wire [W_SDRAM_BANKSEL-1:0] sdram_ba, 53 | output wire [W_SDRAM_DATA/8-1:0] sdram_dqm, 54 | output wire sdram_clke, 55 | output wire sdram_cs_n, 56 | output wire sdram_ras_n, 57 | output wire sdram_cas_n, 58 | output wire sdram_we_n 59 | ); 60 | 61 | sdram_dq_buf dq_buf [W_SDRAM_DATA-1:0] ( 62 | .clk (clk), 63 | .rst_n (rst_n), 64 | .o (ctrl_dq_o_next), 65 | .oe (ctrl_dq_oe_next), 66 | .i (ctrl_dq_i), 67 | .dq (sdram_dq) 68 | ); 69 | 70 | sdram_clk_buf clk_buf ( 71 | .clk (clk), 72 | .rst_n (rst_n), 73 | .e (ctrl_clk_enable), 74 | .clkout (sdram_clk) 75 | ); 76 | 77 | sdram_addr_buf addr_buf [W_SDRAM_ADDR-1:0] ( 78 | .clk (clk), 79 | .rst_n (rst_n), 80 | .d (ctrl_a_next), 81 | .q (sdram_a) 82 | ); 83 | 84 | sdram_addr_buf ctrl_buf [W_SDRAM_BANKSEL + W_SDRAM_DATA / 8 + 5 - 1 : 0] ( 85 | .clk (clk), 86 | .rst_n (rst_n), 87 | .d ({ ctrl_ba_next, ctrl_dqm_next, ctrl_clke_next, ctrl_cs_n_next, ctrl_ras_n_next, ctrl_cas_n_next, ctrl_we_n_next}), 88 | .q ({sdram_ba, sdram_dqm, sdram_clke, sdram_cs_n, sdram_ras_n, sdram_cas_n, sdram_we_n }) 89 | ); 90 | 91 | endmodule 92 | 93 | `ifndef YOSYS 94 | `default_nettype wire 95 | `endif 96 | -------------------------------------------------------------------------------- /video/dvi_tx_parallel.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2020 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Input a stream of RGB pixels. The clk input is the pixel clock. Source 19 | // *must* keep r, g, b valid at all times, as there is no forward handshake. 20 | // rgb_rdy is high on cycles where the dvi_tx consumes a pixel, and a fresh 21 | // pixel must be presented on r, g, b on the next cycle. 22 | // 23 | // Output 3 streams of 10 bit TMDS symbols. Each of these must go through a 24 | // 10:1 serialiser. 25 | 26 | module dvi_tx_parallel #( 27 | // Defaults are for 640x480p 60 Hz (from CEA 861D). 28 | // All horizontal timings are in pixels. 29 | // All vertical timings are in scanlines. 30 | parameter H_SYNC_POLARITY = 1'b0, // 0 for active-low pulse 31 | parameter H_FRONT_PORCH = 16, 32 | parameter H_SYNC_WIDTH = 96, 33 | parameter H_BACK_PORCH = 48, 34 | parameter H_ACTIVE_PIXELS = 640, 35 | 36 | parameter V_SYNC_POLARITY = 1'b0, // 0 for active-low pulse 37 | parameter V_FRONT_PORCH = 10, 38 | parameter V_SYNC_WIDTH = 2, 39 | parameter V_BACK_PORCH = 33, 40 | parameter V_ACTIVE_LINES = 480, 41 | 42 | // If 1, use the much smaller pixel-doubled encoder: 43 | parameter SMOL_TMDS_ENCODE = 0 44 | ) ( 45 | input wire clk, 46 | input wire rst_n, 47 | input wire en, // synchronous reset if low 48 | 49 | input wire [7:0] r, 50 | input wire [7:0] g, 51 | input wire [7:0] b, 52 | output wire rgb_rdy, 53 | 54 | output wire [9:0] tmds2, 55 | output wire [9:0] tmds1, 56 | output wire [9:0] tmds0 57 | ); 58 | 59 | wire hsync; 60 | wire vsync; 61 | wire den; 62 | 63 | dvi_timing #( 64 | .H_SYNC_POLARITY (H_SYNC_POLARITY), 65 | .H_FRONT_PORCH (H_FRONT_PORCH), 66 | .H_SYNC_WIDTH (H_SYNC_WIDTH), 67 | .H_BACK_PORCH (H_BACK_PORCH), 68 | .H_ACTIVE_PIXELS (H_ACTIVE_PIXELS), 69 | 70 | .V_SYNC_POLARITY (V_SYNC_POLARITY), 71 | .V_FRONT_PORCH (V_FRONT_PORCH), 72 | .V_SYNC_WIDTH (V_SYNC_WIDTH), 73 | .V_BACK_PORCH (V_BACK_PORCH), 74 | .V_ACTIVE_LINES (V_ACTIVE_LINES) 75 | ) inst_dvi_timing ( 76 | .clk (clk), 77 | .rst_n (rst_n), 78 | .en (en), 79 | 80 | .vsync (vsync), 81 | .hsync (hsync), 82 | .den (den) 83 | ); 84 | 85 | generate 86 | if (SMOL_TMDS_ENCODE) begin: smol_encode 87 | 88 | smoldvi_tmds_encode tmds2_encoder ( 89 | .clk (clk), 90 | .rst_n (rst_n), 91 | .c (2'b00), 92 | .d (r), 93 | .den (den), 94 | .q (tmds2) 95 | ); 96 | 97 | smoldvi_tmds_encode tmds1_encoder ( 98 | .clk (clk), 99 | .rst_n (rst_n), 100 | .c (2'b00), 101 | .d (g), 102 | .den (den), 103 | .q (tmds1) 104 | ); 105 | 106 | smoldvi_tmds_encode tmds0_encoder ( 107 | .clk (clk), 108 | .rst_n (rst_n), 109 | .c ({vsync, hsync}), 110 | .d (b), 111 | .den (den), 112 | .q (tmds0) 113 | ); 114 | 115 | end else begin: full_encode 116 | 117 | 118 | tmds_encode tmds2_encoder ( 119 | .clk (clk), 120 | .rst_n (rst_n), 121 | .c (2'b00), 122 | .d (r), 123 | .den (den), 124 | .q (tmds2) 125 | ); 126 | 127 | tmds_encode tmds1_encoder ( 128 | .clk (clk), 129 | .rst_n (rst_n), 130 | .c (2'b00), 131 | .d (g), 132 | .den (den), 133 | .q (tmds1) 134 | ); 135 | 136 | tmds_encode tmds0_encoder ( 137 | .clk (clk), 138 | .rst_n (rst_n), 139 | .c ({vsync, hsync}), 140 | .d (b), 141 | .den (den), 142 | .q (tmds0) 143 | ); 144 | 145 | end 146 | endgenerate 147 | 148 | assign rgb_rdy = den; 149 | 150 | endmodule 151 | -------------------------------------------------------------------------------- /mem/ahb_async_sram_halfwidth.v: -------------------------------------------------------------------------------- 1 | // Adapt AHB bus to an async SRAM with half width. 2 | // Feels like there is a loss of generality/parameterisation here, 3 | // but for RISCBoy there is some scope to do e.g. double-pumped reads 4 | // to improve performance, so makes sense to have a special-case 5 | // half-width-only controller to inject these. 6 | 7 | // Size of memory is DEPTH * W_SRAM_DATA 8 | 9 | `default_nettype none 10 | 11 | module ahb_async_sram_halfwidth #( 12 | parameter W_DATA = 32, 13 | parameter W_ADDR = 32, 14 | parameter DEPTH = 1 << 11, 15 | parameter W_SRAM_ADDR = $clog2(DEPTH), // Let this default 16 | parameter W_SRAM_DATA = W_DATA / 2 // Let this default 17 | ) ( 18 | // Globals 19 | input wire clk, 20 | input wire rst_n, 21 | 22 | // AHB lite slave interface 23 | output wire ahbls_hready_resp, 24 | input wire ahbls_hready, 25 | output wire ahbls_hresp, 26 | input wire [W_ADDR-1:0] ahbls_haddr, 27 | input wire ahbls_hwrite, 28 | input wire [1:0] ahbls_htrans, 29 | input wire [2:0] ahbls_hsize, 30 | input wire [2:0] ahbls_hburst, 31 | input wire [3:0] ahbls_hprot, 32 | input wire ahbls_hmastlock, 33 | input wire [W_DATA-1:0] ahbls_hwdata, 34 | output wire [W_DATA-1:0] ahbls_hrdata, 35 | 36 | output wire [W_SRAM_ADDR-1:0] sram_addr, 37 | output wire [W_SRAM_DATA-1:0] sram_dq_out, 38 | output wire [W_SRAM_DATA-1:0] sram_dq_oe, 39 | input wire [W_SRAM_DATA-1:0] sram_dq_in, 40 | output wire sram_ce_n, 41 | output wire sram_we_n, // DDR output 42 | output wire sram_oe_n, 43 | output wire [W_SRAM_DATA/8-1:0] sram_byte_n 44 | ); 45 | 46 | parameter W_BYTEADDR = $clog2(W_SRAM_DATA / 8); 47 | 48 | assign ahbls_hresp = 1'b0; 49 | 50 | reg hready_r; 51 | reg long_dphase; 52 | reg write_dph; 53 | reg read_dph; 54 | reg addr_lsb; 55 | 56 | // AHBL decode and muxing 57 | 58 | wire [W_SRAM_DATA/8-1:0] bytemask_noshift = ~({W_SRAM_DATA/8{1'b1}} << (8'h1 << ahbls_hsize)); 59 | wire [W_SRAM_DATA/8-1:0] bytemask_aph = bytemask_noshift << ahbls_haddr[W_BYTEADDR-1:0]; 60 | wire aphase_full_width = (8'h1 << ahbls_hsize) == W_DATA / 8; // indicates next dphase will be long 61 | 62 | wire [W_SRAM_DATA-1:0] sram_rdata; 63 | wire [W_SRAM_DATA-1:0] sram_wdata = ahbls_hwdata[(addr_lsb ? W_SRAM_DATA : 0) +: W_SRAM_DATA]; 64 | reg [W_SRAM_DATA-1:0] rdata_buf; 65 | assign ahbls_hrdata = {sram_rdata, long_dphase ? rdata_buf : sram_rdata}; 66 | 67 | assign ahbls_hready_resp = hready_r; 68 | 69 | // AHBL state machine 70 | 71 | always @ (posedge clk or negedge rst_n) begin 72 | if (!rst_n) begin 73 | hready_r <= 1'b1; 74 | long_dphase <= 1'b0; 75 | write_dph <= 1'b0; 76 | read_dph <= 1'b0; 77 | addr_lsb <= 1'b0; 78 | end else if (ahbls_hready) begin 79 | if (ahbls_htrans[1]) begin 80 | long_dphase <= aphase_full_width; 81 | hready_r <= !aphase_full_width; 82 | write_dph <= ahbls_hwrite; 83 | read_dph <= !ahbls_hwrite; 84 | addr_lsb <= ahbls_haddr[W_BYTEADDR]; 85 | end else begin 86 | write_dph <= 1'b0; 87 | long_dphase <= 1'b0; 88 | read_dph <= 1'b0; 89 | hready_r <= 1'b1; 90 | end 91 | end else if (long_dphase && !hready_r) begin 92 | rdata_buf <= sram_rdata; 93 | hready_r <= 1'b1; 94 | addr_lsb <= 1'b1; 95 | end 96 | end 97 | 98 | // SRAM PHY hookup 99 | 100 | wire ce_aph = ahbls_htrans[1] && ahbls_hready; 101 | wire ce_dph = long_dphase && !hready_r; 102 | 103 | reg [W_SRAM_ADDR-1:0] addr_dph; 104 | always @ (posedge clk or negedge rst_n) begin 105 | if (!rst_n) begin 106 | addr_dph <= {W_SRAM_ADDR{1'b0}}; 107 | end else if (ahbls_hready) begin 108 | addr_dph <= ahbls_haddr[W_BYTEADDR +: W_SRAM_ADDR] | {{W_SRAM_ADDR-1{1'b0}}, 1'b1}; 109 | end 110 | end 111 | 112 | assign sram_ce_n = !( ce_aph || ce_dph ); 113 | assign sram_we_n = !((ce_aph && ahbls_hwrite) || (ce_dph && write_dph)); 114 | assign sram_oe_n = !((ce_aph && !ahbls_hwrite) || (ce_dph && !write_dph)); 115 | 116 | assign sram_addr = ce_dph ? addr_dph : ahbls_haddr[W_BYTEADDR +: W_SRAM_ADDR]; 117 | assign sram_byte_n = ~(bytemask_aph | {W_SRAM_DATA/8{ce_dph}}); 118 | 119 | assign sram_rdata = sram_dq_in; 120 | assign sram_dq_out = sram_wdata; 121 | `ifdef FPGA_ICE40 122 | // Output registers are built into pad (relies on the negedge trick for DQ wdata) 123 | assign sram_dq_oe = {W_SRAM_DATA{!sram_we_n}}; 124 | `else 125 | // No output registers on DQ 126 | assign sram_dq_oe = {W_SRAM_DATA{write_dph}}; 127 | `endif 128 | endmodule 129 | 130 | `ifndef YOSYS 131 | `default_nettype wire 132 | `endif 133 | -------------------------------------------------------------------------------- /video/tmds_encode.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2020 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | module tmds_encode ( 19 | input wire clk, // Must be == pixel clock. 20 | input wire rst_n, 21 | 22 | input wire [1:0] c, 23 | input wire [7:0] d, 24 | input wire den, 25 | 26 | output reg [9:0] q 27 | ); 28 | 29 | // This is a direct implementation of Figure 3-5 on page 29 of DVI v1.0 spec. 30 | 31 | // ---------------------------------------------------------------------------- 32 | // 1. Transition minimisation 33 | 34 | reg [8:0] q_m; 35 | wire [3:0] d_count; 36 | 37 | popcount #( 38 | .W_IN (8) 39 | ) popcount_d ( 40 | .din (d), 41 | .dout (d_count) 42 | ); 43 | 44 | always @ (posedge clk or negedge rst_n) begin 45 | if (!rst_n) begin 46 | q_m <= 9'h0; 47 | end else if (d_count > 4'd4 || (d_count == 4'd4 && !d[0])) begin 48 | q_m <= {1'b0, ~^d[7:0], ^d[6:0], ~^d[5:0], ^d[4:0], ~^d[3:0], ^d[2:0], ~^d[1:0], d[0]}; 49 | end else begin 50 | q_m <= {1'b1, ^d[7:0], ^d[6:0], ^d[5:0], ^d[4:0], ^d[3:0], ^d[2:0], ^d[1:0], d[0]}; 51 | end 52 | end 53 | 54 | // ---------------------------------------------------------------------------- 55 | // 2. Running DC balance correction 56 | 57 | // The count is guaranteed to be between +/- 10 inclusive, as this is the 58 | // maximum symbol weight, and we always aim towards (and potentially past) 59 | // zero if current count is nonzero. 60 | 61 | localparam W_IMBALANCE = 5; 62 | reg [W_IMBALANCE-1:0] imbalance; 63 | wire [3:0] q_m_count; 64 | 65 | popcount #( 66 | .W_IN (8) 67 | ) popcount_q_m ( 68 | .din (q_m[7:0]), 69 | .dout (q_m_count) 70 | ); 71 | 72 | reg [1:0] den_delayed; 73 | 74 | always @ (posedge clk or negedge rst_n) begin 75 | if (!rst_n) begin 76 | den_delayed <= 2'h0; 77 | end else begin 78 | den_delayed <= {den_delayed[0], den}; 79 | end 80 | end 81 | 82 | reg [9:0] q_m_inv; 83 | 84 | always @ (posedge clk or negedge rst_n) begin 85 | if (!rst_n) begin 86 | imbalance <= {W_IMBALANCE{1'b0}}; 87 | q_m_inv <= 10'h0; 88 | end else begin 89 | if (~|imbalance || q_m_count == 4'd4) begin 90 | q_m_inv <= {!q_m[8], q_m[8], q_m[8] ? q_m[7:0] : ~q_m[7:0]}; 91 | if (!q_m[8]) 92 | imbalance <= imbalance + 5'd4 - q_m_count; 93 | else 94 | imbalance <= imbalance + q_m_count - 5'd4; 95 | end else if ($signed(imbalance) > 5'sh0 && q_m_count > 4'd4 96 | || $signed(imbalance) < 5'sh0 && q_m_count < 4'd4) begin 97 | q_m_inv <= {1'b1, q_m[8], ~q_m[7:0]}; 98 | imbalance <= imbalance + {4'h0, q_m[8]} - q_m_count + 5'd4; 99 | end else begin 100 | q_m_inv <= {1'b0, q_m[8], q_m[7:0]}; 101 | imbalance <= imbalance - {4'h0, !q_m[8]} + q_m_count - 5'd4; 102 | end 103 | // Override counter update during control period (but don't add extra muxing 104 | // to datapath in this pipestage) 105 | if (!den_delayed[0]) 106 | imbalance <= 5'd0; 107 | end 108 | end 109 | 110 | // ---------------------------------------------------------------------------- 111 | // 3. Control symbol insertion 112 | 113 | reg [1:0] c_delayed [0:1]; 114 | 115 | 116 | always @ (posedge clk or negedge rst_n) begin 117 | if (!rst_n) begin 118 | q <= 10'd0; 119 | c_delayed[0] <= 2'b00; 120 | c_delayed[1] <= 2'b00; 121 | end else begin 122 | {c_delayed[1], c_delayed[0]} <= {c_delayed[0], c}; 123 | if (den_delayed[1]) begin 124 | q <= q_m_inv; 125 | end else begin 126 | case (c_delayed[1]) 127 | 2'b00: q <= 10'b1101010100; 128 | 2'b01: q <= 10'b0010101011; 129 | 2'b10: q <= 10'b0101010100; 130 | 2'b11: q <= 10'b1010101011; 131 | endcase 132 | end 133 | end 134 | end 135 | 136 | endmodule 137 | -------------------------------------------------------------------------------- /common/sync_fifo.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018-2020 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Synchronous FIFO 19 | // DEPTH can be any integer >= 1. 20 | 21 | `default_nettype none 22 | 23 | module sync_fifo #( 24 | parameter DEPTH = 2, 25 | parameter WIDTH = 32, 26 | parameter W_LEVEL = $clog2(DEPTH + 1) 27 | ) ( 28 | input wire clk, 29 | input wire rst_n, 30 | 31 | input wire [WIDTH-1:0] wdata, 32 | input wire wen, 33 | output wire [WIDTH-1:0] rdata, 34 | input wire ren, 35 | 36 | input wire flush, 37 | 38 | output wire full, 39 | output wire empty, 40 | output reg [W_LEVEL-1:0] level 41 | ); 42 | 43 | // valid has an extra bit which should remain constant 0, and mem has an extra 44 | // entry which is wired through to wdata. This is just to handle the loop 45 | // boundary condition without tools complaining. 46 | reg [WIDTH-1:0] mem [0:DEPTH]; 47 | reg [DEPTH:0] valid; 48 | 49 | // ---------------------------------------------------------------------------- 50 | // Control and datapath 51 | 52 | wire push = wen && (ren || !full); 53 | wire pop = ren && !empty; 54 | 55 | always @ (posedge clk or negedge rst_n) begin 56 | if (!rst_n) begin 57 | valid <= {DEPTH+1{1'b0}}; 58 | end else if (flush) begin 59 | valid <= {DEPTH+1{1'b0}}; 60 | end else if (wen || ren) begin 61 | // 2 LUTs 1 FF per flag, all FFs have same clke 62 | valid <= (valid << push | {{DEPTH{1'b0}}, push}) >> pop; 63 | end 64 | end 65 | 66 | // No reset on datapath 67 | always @ (posedge clk) begin: shift_data 68 | integer i; 69 | for (i = 0; i < DEPTH; i = i + 1) begin: data_stage 70 | if (ren || (wen && !valid[i] && (i == DEPTH - 1 || !valid[i + 1]))) begin 71 | mem[i] <= valid[i + 1] ? mem[i + 1] : wdata; 72 | end 73 | end 74 | end 75 | 76 | always @ (*) mem[DEPTH] = wdata; 77 | assign rdata = mem[0]; 78 | 79 | // ---------------------------------------------------------------------------- 80 | // Flags 81 | 82 | assign full = valid[DEPTH-1]; 83 | assign empty = !valid[0]; 84 | 85 | always @ (posedge clk or negedge rst_n) begin 86 | if (!rst_n) begin 87 | level <= {W_LEVEL{1'b0}}; 88 | end else if (flush) begin 89 | level <= {W_LEVEL{1'b0}}; 90 | end else begin 91 | level <= (level + {{W_LEVEL-1{1'b0}}, push}) - {{W_LEVEL-1{1'b0}}, pop}; 92 | end 93 | end 94 | 95 | // ---------------------------------------------------------------------------- 96 | // Testbench junk vvv 97 | 98 | //synthesis translate_off 99 | always @ (posedge clk) 100 | if (wen && full) 101 | $display($time, ": WARNING %m: push on full"); 102 | always @ (posedge clk) 103 | if (ren && empty) 104 | $display($time, ": WARNING %m: pop on empty"); 105 | //synthesis translate_on 106 | 107 | 108 | `ifdef FORMAL_CHECK_FIFO 109 | initial assume(!rst_n); 110 | always @ (posedge clk) begin 111 | assume(!(wen && full && !ren)); 112 | assume(!(ren && empty)); 113 | assume(!flush); 114 | assume(rst_n); 115 | 116 | assert((full) ~^ (level == DEPTH)); 117 | assert((empty) ~^ (level == 0)); 118 | assert(level <= DEPTH); 119 | assert((w_ptr == r_ptr) ~^ (full || empty)); 120 | 121 | assert($past(ren) || (rdata == $past(rdata) || $past(empty))); 122 | assert($past(ren) || level >= $past(level)); 123 | assert($past(wen) || level <= $past(level)); 124 | assert(!($past(empty) && $past(wen) && rdata != $past(wdata))); 125 | assert(!($past(ren) && r_ptr == $past(r_ptr))); 126 | assert(!($past(wen) && w_ptr == $past(w_ptr))); 127 | end 128 | `elsif FORMAL 129 | always @ (posedge clk) if (rst_n) begin 130 | assert(!(wen && full && !ren)); 131 | assert(!(ren && empty)); 132 | end 133 | `endif 134 | 135 | endmodule 136 | 137 | `ifndef YOSYS 138 | `default_nettype wire 139 | `endif 140 | -------------------------------------------------------------------------------- /busfabric/ahbl_to_apb.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | 3 | module ahbl_to_apb #( 4 | parameter W_HADDR = 32, 5 | parameter W_PADDR = 16, 6 | parameter W_DATA = 32, 7 | // Set to 0 to remove reset from datapath flops: 8 | parameter FULL_RESET = 1 9 | ) ( 10 | input wire clk, 11 | input wire rst_n, 12 | 13 | input wire [W_HADDR-1:0] ahbls_haddr, 14 | input wire ahbls_hwrite, 15 | input wire [1:0] ahbls_htrans, 16 | input wire [2:0] ahbls_hsize, 17 | input wire [2:0] ahbls_hburst, 18 | input wire [3:0] ahbls_hprot, 19 | input wire ahbls_hmastlock, 20 | input wire [W_DATA-1:0] ahbls_hwdata, 21 | input wire ahbls_hready, 22 | output reg ahbls_hready_resp, 23 | output reg ahbls_hresp, 24 | output reg [W_DATA-1:0] ahbls_hrdata, 25 | 26 | output reg [W_PADDR-1:0] apbm_paddr, 27 | output reg apbm_psel, 28 | output reg apbm_penable, 29 | output reg apbm_pwrite, 30 | output reg [W_DATA-1:0] apbm_pwdata, 31 | input wire apbm_pready, 32 | input wire [W_DATA-1:0] apbm_prdata, 33 | input wire apbm_pslverr 34 | ); 35 | 36 | // Transfer state machine 37 | 38 | localparam W_APB_STATE = 3; 39 | localparam S_READY = 3'd0; // Idle upstream dphase or end of read/write dphase 40 | localparam S_RD0 = 3'd1; // Downstream setup phase (cannot stall) 41 | localparam S_RD1 = 3'd2; // Downstream access phase (may stall or error) 42 | localparam S_WR0 = 3'd3; // Sample hwdata 43 | localparam S_WR1 = 3'd4; // Downstream setup phase (cannot stall) 44 | localparam S_WR2 = 3'd5; // Downstream access phase (may stall or error) 45 | localparam S_ERR0 = 3'd6; // AHBL error response, first cycle 46 | localparam S_ERR1 = 3'd7; // AHBL error response, and accept new address phase if not deasserted. 47 | 48 | reg [W_APB_STATE-1:0] apb_state; 49 | reg [W_APB_STATE-1:0] apb_state_nxt; 50 | 51 | wire [W_APB_STATE-1:0] aphase_to_dphase = 52 | ahbls_htrans[1] && ahbls_hwrite ? S_WR0 : 53 | ahbls_htrans[1] && !ahbls_hwrite ? S_RD0 : S_READY; 54 | 55 | always @ (*) begin 56 | apb_state_nxt = apb_state; 57 | case (apb_state) 58 | S_READY: if (ahbls_hready) apb_state_nxt = aphase_to_dphase; 59 | S_WR0: apb_state_nxt = S_WR1; 60 | S_WR1: apb_state_nxt = S_WR2; 61 | S_WR2: if (apbm_pready) apb_state_nxt = apbm_pslverr ? S_ERR0 : S_READY; 62 | S_RD0: apb_state_nxt = S_RD1; 63 | S_RD1: if (apbm_pready) apb_state_nxt = apbm_pslverr ? S_ERR0 : S_READY; 64 | S_ERR0: apb_state_nxt = S_ERR1; 65 | S_ERR1: apb_state_nxt = aphase_to_dphase; 66 | endcase 67 | end 68 | 69 | always @ (posedge clk or negedge rst_n) begin 70 | if (!rst_n) begin 71 | apb_state <= S_READY; 72 | ahbls_hready_resp <= 1'b1; 73 | ahbls_hresp <= 1'b0; 74 | end else begin 75 | apb_state <= apb_state_nxt; 76 | ahbls_hready_resp <= 77 | apb_state_nxt == S_READY || 78 | apb_state_nxt == S_ERR1; 79 | ahbls_hresp <= 80 | apb_state_nxt == S_ERR0 || 81 | apb_state_nxt == S_ERR1; 82 | end 83 | end 84 | 85 | // Downstream request 86 | 87 | always @ (*) begin 88 | case (apb_state) 89 | S_RD0: {apbm_psel, apbm_penable, apbm_pwrite} = 3'b100; 90 | S_RD1: {apbm_psel, apbm_penable, apbm_pwrite} = 3'b110; 91 | S_WR1: {apbm_psel, apbm_penable, apbm_pwrite} = 3'b101; 92 | S_WR2: {apbm_psel, apbm_penable, apbm_pwrite} = 3'b111; 93 | default: {apbm_psel, apbm_penable, apbm_pwrite} = 3'b000; 94 | endcase 95 | end 96 | 97 | generate 98 | if (FULL_RESET != 0) begin: reg_downstream_reset 99 | always @ (posedge clk or negedge rst_n) begin 100 | if (!rst_n) begin 101 | apbm_paddr <= {W_PADDR{1'b0}}; 102 | apbm_pwdata <= {W_DATA{1'b0}}; 103 | end else begin 104 | if (ahbls_htrans[1] && ahbls_hready) 105 | apbm_paddr <= ahbls_haddr[W_PADDR-1:0]; 106 | if (apb_state == S_WR0) 107 | apbm_pwdata <= ahbls_hwdata; 108 | end 109 | end 110 | end else begin: reg_downstream_noreset 111 | always @ (posedge clk) begin 112 | if (ahbls_htrans[1] && ahbls_hready) begin 113 | apbm_paddr <= ahbls_haddr[W_PADDR-1:0]; 114 | end 115 | if (apb_state == S_WR0) begin 116 | apbm_pwdata <= ahbls_hwdata; 117 | end 118 | end 119 | end 120 | endgenerate 121 | 122 | // Upstream response 123 | generate 124 | if (FULL_RESET != 0) begin: reg_upstream_reset 125 | always @ (posedge clk or negedge rst_n) begin 126 | if (!rst_n) begin 127 | ahbls_hrdata <= {W_DATA{1'b0}}; 128 | end else if (apb_state == S_RD1 && apbm_pready) begin 129 | ahbls_hrdata <= apbm_prdata; 130 | end 131 | end 132 | end else begin: reg_upstream_noreset 133 | always @ (posedge clk) begin 134 | ahbls_hrdata <= apbm_prdata; 135 | end 136 | end 137 | endgenerate 138 | 139 | endmodule 140 | 141 | `ifndef YOSYS 142 | `default_nettype wire 143 | `endif 144 | -------------------------------------------------------------------------------- /common/memdump.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | module memdump #( 19 | parameter W_ADDR = 32, 20 | parameter W_DATA = 32, 21 | parameter ADDR_START = 32'h20080000, 22 | parameter ADDR_STOP = ADDR_START + (1 << 13) 23 | ) ( 24 | // Global signals 25 | input wire clk, 26 | input wire rst_n, 27 | 28 | // AHB-lite Master port 29 | output wire [W_ADDR-1:0] ahblm_haddr, 30 | output wire ahblm_hwrite, 31 | output wire [1:0] ahblm_htrans, 32 | output wire [2:0] ahblm_hsize, 33 | output wire [2:0] ahblm_hburst, 34 | output wire [3:0] ahblm_hprot, 35 | output wire ahblm_hmastlock, 36 | input wire ahblm_hready, 37 | input wire ahblm_hresp, 38 | output wire [W_DATA-1:0] ahblm_hwdata, 39 | input wire [W_DATA-1:0] ahblm_hrdata, 40 | 41 | output reg serial_out 42 | ); 43 | 44 | // Sit in place of the processor. Read in memory and dump it out via raw biphase-mark-code serial. 45 | 46 | 47 | // ============================================================================ 48 | // FIFO decouples bus interface from data modulator 49 | // ============================================================================ 50 | 51 | wire fifo_wen; 52 | wire fifo_ren; 53 | wire fifo_full; 54 | wire fifo_empty; 55 | wire [W_DATA-1:0] fifo_rdata; 56 | 57 | sync_fifo #( 58 | .DEPTH(4), 59 | .WIDTH(W_DATA) 60 | ) inst_sync_fifo ( 61 | .clk (clk), 62 | .rst_n (rst_n), 63 | .wdata (ahblm_hrdata), 64 | .wen (fifo_wen), 65 | .rdata (fifo_rdata), 66 | .ren (fifo_ren), 67 | .flush (1'b0), 68 | .full (fifo_full), 69 | .empty (fifo_empty), 70 | .level () 71 | ); 72 | 73 | // ============================================================================ 74 | // Bus interface 75 | // ============================================================================ 76 | 77 | reg [W_ADDR-1:0] addr; 78 | reg dphase_active; 79 | 80 | always @ (posedge clk or negedge rst_n) begin 81 | if (!rst_n) begin 82 | dphase_active <= 1'b0; 83 | addr <= ADDR_START; 84 | end else if (ahblm_hready) begin 85 | dphase_active <= ahblm_htrans[1]; 86 | if (ahblm_htrans[1]) 87 | addr <= addr + W_DATA / 8; 88 | end 89 | end 90 | 91 | assign fifo_wen = dphase_active && ahblm_hready; 92 | 93 | assign ahblm_haddr = addr; 94 | assign ahblm_hwrite = 1'b0; 95 | assign ahblm_htrans = {!(fifo_full || addr == ADDR_STOP || dphase_active), 1'b0}; 96 | parameter HSIZE = $clog2(W_DATA/8); // fuck ISIM 97 | assign ahblm_hsize = HSIZE; 98 | assign ahblm_hprot = 0; 99 | assign ahblm_hburst = 0; 100 | assign ahblm_hwdata = 0; 101 | assign ahblm_hmastlock = 1'b0; 102 | 103 | // ============================================================================ 104 | // Data modulator 105 | // ============================================================================ 106 | 107 | parameter W_CTR = $clog2(W_DATA + 1); 108 | 109 | reg pingpong; 110 | reg [W_CTR-1:0] ctr; 111 | reg [W_DATA-1:0] shift; 112 | 113 | assign fifo_ren = !fifo_empty && (ctr == 0 || (ctr == 1 && pingpong)); 114 | 115 | // Shifting logic 116 | // MSB-first 117 | 118 | always @ (posedge clk or negedge rst_n) begin 119 | if (!rst_n) begin 120 | pingpong <= 1'b0; 121 | ctr <= {W_CTR{1'b0}}; 122 | shift <= {W_DATA{1'b0}}; 123 | end else if (fifo_ren) begin 124 | ctr <= W_DATA; 125 | shift <= fifo_rdata; 126 | pingpong <= 1'b0; 127 | end else if (|ctr) begin 128 | pingpong <= !pingpong; 129 | if (pingpong) begin 130 | ctr <= ctr - 1'b1; 131 | shift <= shift << 1; 132 | end 133 | end 134 | end 135 | 136 | // Actual BPMC 137 | 138 | always @ (posedge clk or negedge rst_n) begin 139 | if (!rst_n) begin 140 | serial_out <= 1'b0; 141 | end else if (|ctr) begin 142 | serial_out <= serial_out ^ (!pingpong || shift[W_DATA - 1]); 143 | end 144 | end 145 | 146 | endmodule 147 | -------------------------------------------------------------------------------- /video/dvi_timing.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2020 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | module dvi_timing #( 19 | // Defaults are for 640x480p 60 Hz (from CEA 861D). 20 | // All horizontal timings are in pixels. 21 | // All vertical timings are in scanlines. 22 | parameter H_SYNC_POLARITY = 1'b0, // 0 for active-low pulse 23 | parameter H_FRONT_PORCH = 16, 24 | parameter H_SYNC_WIDTH = 96, 25 | parameter H_BACK_PORCH = 48, 26 | parameter H_ACTIVE_PIXELS = 640, 27 | 28 | parameter V_SYNC_POLARITY = 1'b0, // 0 for active-low pulse 29 | parameter V_FRONT_PORCH = 10, 30 | parameter V_SYNC_WIDTH = 2, 31 | parameter V_BACK_PORCH = 33, 32 | parameter V_ACTIVE_LINES = 480 33 | ) ( 34 | input wire clk, 35 | input wire rst_n, 36 | 37 | input wire en, 38 | 39 | output reg vsync, 40 | output reg hsync, 41 | output reg den 42 | ); 43 | 44 | parameter W_H_CTR = $clog2(H_ACTIVE_PIXELS); 45 | parameter W_V_CTR = $clog2(V_ACTIVE_LINES); 46 | 47 | // ---------------------------------------------------------------------------- 48 | // Horizontal timing state machine 49 | 50 | localparam W_STATE = 2; 51 | localparam S_FRONT_PORCH = 2'h0; 52 | localparam S_SYNC = 2'h1; 53 | localparam S_BACK_PORCH = 2'h2; 54 | localparam S_ACTIVE = 2'h3; 55 | 56 | reg [W_H_CTR-1:0] h_ctr; 57 | reg [W_STATE-1:0] h_state; 58 | reg in_active_vertical_period; 59 | reg v_advance; 60 | 61 | always @ (posedge clk or negedge rst_n) begin 62 | if (!rst_n) begin 63 | h_state <= S_FRONT_PORCH; 64 | h_ctr <= {W_H_CTR{1'b0}}; 65 | hsync <= !H_SYNC_POLARITY; 66 | den <= 1'b0; 67 | v_advance <= 1'b0; 68 | end else if (!en) begin 69 | hsync <= !H_SYNC_POLARITY; 70 | den <= 1'b0; 71 | h_ctr <= {W_H_CTR{1'b0}}; 72 | h_state <= S_FRONT_PORCH; 73 | v_advance <= 1'b0; 74 | end else begin 75 | h_ctr <= h_ctr - 1'b1; 76 | v_advance <= h_state == S_ACTIVE && h_ctr == 1; 77 | case (h_state) 78 | S_FRONT_PORCH: if (h_ctr == 0) begin 79 | h_ctr <= H_SYNC_WIDTH - 1; 80 | h_state <= S_SYNC; 81 | hsync <= H_SYNC_POLARITY; 82 | end 83 | S_SYNC: if (h_ctr == 0) begin 84 | h_ctr <= H_BACK_PORCH - 1; 85 | h_state <= S_BACK_PORCH; 86 | hsync <= !H_SYNC_POLARITY; 87 | end 88 | S_BACK_PORCH: if (h_ctr == 0) begin 89 | h_ctr <= H_ACTIVE_PIXELS - 1; 90 | h_state <= S_ACTIVE; 91 | den <= in_active_vertical_period; 92 | end 93 | S_ACTIVE: if (h_ctr == 0) begin 94 | h_ctr <= H_FRONT_PORCH - 1; 95 | h_state <= S_FRONT_PORCH; 96 | den <= 1'b0; 97 | end 98 | endcase 99 | end 100 | end 101 | 102 | // ---------------------------------------------------------------------------- 103 | // Vertical timing state machine 104 | 105 | reg [W_V_CTR-1:0] v_ctr; 106 | reg [W_STATE-1:0] v_state; 107 | 108 | always @ (posedge clk or negedge rst_n) begin 109 | if (!rst_n) begin 110 | v_state <= S_FRONT_PORCH; 111 | v_ctr <= {W_V_CTR{1'b0}}; 112 | vsync <= !V_SYNC_POLARITY; 113 | in_active_vertical_period <= 1'b0; 114 | end else if (!en) begin 115 | vsync <= !V_SYNC_POLARITY; 116 | in_active_vertical_period <= 1'b0; 117 | v_ctr <= {W_V_CTR{1'b0}}; 118 | v_state <= S_FRONT_PORCH; 119 | end else if (v_advance) begin 120 | v_ctr <= v_ctr - 1'b1; 121 | case (v_state) 122 | S_FRONT_PORCH: if (v_ctr == 0) begin 123 | v_ctr <= V_SYNC_WIDTH - 1; 124 | v_state <= S_SYNC; 125 | vsync <= V_SYNC_POLARITY; 126 | end 127 | S_SYNC: if (v_ctr == 0) begin 128 | v_ctr <= V_BACK_PORCH - 1; 129 | v_state <= S_BACK_PORCH; 130 | vsync <= !V_SYNC_POLARITY; 131 | end 132 | S_BACK_PORCH: if (v_ctr == 0) begin 133 | v_ctr <= V_ACTIVE_LINES - 1; 134 | v_state <= S_ACTIVE; 135 | in_active_vertical_period <= 1'b1; 136 | end 137 | S_ACTIVE: if (v_ctr == 0) begin 138 | v_ctr <= V_FRONT_PORCH - 1; 139 | v_state <= S_FRONT_PORCH; 140 | in_active_vertical_period <= 1'b0; 141 | end 142 | endcase 143 | end 144 | end 145 | 146 | endmodule 147 | -------------------------------------------------------------------------------- /common/tristate_io.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // A pad, with optional input and output registers. Where possible, this uses 19 | // the registers built directly into the IO cell. 20 | 21 | // Note: rst_n may not be functional on FPGA. 22 | 23 | module tristate_io #( 24 | parameter SYNC_OUT = 0, 25 | parameter SYNC_IN = 0, 26 | parameter PULLUP = 0 27 | ) ( 28 | input wire clk, 29 | input wire rst_n, 30 | 31 | input wire out, 32 | input wire oe, 33 | output wire in, 34 | inout wire pad 35 | ); 36 | 37 | // ---------------------------------------------------------------------------- 38 | 39 | `ifdef FPGA_ICE40 40 | 41 | // Based on the SB_IO library description, PIN_TYPE breaks down as follows: 42 | // 43 | // - bits 5:4: OUTPUT_ENABLE muxing (note OUTPUT_ENABLE is active-*high*) 44 | // 45 | // - 00 Always disabled 46 | // - 01 Always enabled 47 | // - 10: Unregistered OUTPUT_ENABLE 48 | // - 11: Posedge-registered OUTPUT_ENABLE 49 | // 50 | // - bits 3:2: D_OUT_x muxing 51 | // 52 | // - 00: DDR, posedge-registered D_OUT_0 for half cycle following posedge, 53 | // then negedge-registered D_OUT_1 for next half cycle 54 | // - 01: Posedge-registered D_OUT_0 55 | // - 10: Unregistered D_OUT_0 56 | // - 11: Registered, inverted D_OUT_0 57 | // 58 | // - bits 1:0: D_IN_0 muxing (note D_IN_1 is always negedge-registered input) 59 | // 60 | // - 00: Posedge-registered input 61 | // - 01: Unregistered input 62 | // - 10: Posedge-registered input with latch (latch is transparent when 63 | // LATCH_INPUT_VALUE is low) 64 | // - 11: Unregistered input with latch (latch is transparent when 65 | // LATCH_INPUT_VALUE is low) 66 | 67 | localparam [5:0] PIN_TYPE = { 68 | SYNC_OUT ? 2'b11 : 2'b10, 69 | SYNC_OUT ? 2'b01 : 2'b10, 70 | SYNC_IN ? 2'b00 : 2'b01 71 | }; 72 | 73 | generate 74 | if (SYNC_OUT == 0 && SYNC_IN == 0) begin: no_clk 75 | // Do not connect the clock nets if not required, because it causes 76 | // packing issues with other IOs 77 | 78 | SB_IO #( 79 | .PIN_TYPE (PIN_TYPE), 80 | .PULLUP (|PULLUP) 81 | ) buffer ( 82 | .PACKAGE_PIN (pad), 83 | .OUTPUT_ENABLE (oe), 84 | .D_OUT_0 (out), 85 | .D_IN_0 (in) 86 | ); 87 | 88 | end else begin: have_clk 89 | 90 | SB_IO #( 91 | .PIN_TYPE (PIN_TYPE), 92 | .PULLUP (|PULLUP) 93 | ) buffer ( 94 | .OUTPUT_CLK (clk), 95 | .INPUT_CLK (clk), 96 | .PACKAGE_PIN (pad), 97 | .OUTPUT_ENABLE (oe), 98 | .D_OUT_0 (out), 99 | .D_IN_0 (in) 100 | ); 101 | 102 | end 103 | endgenerate 104 | 105 | // ---------------------------------------------------------------------------- 106 | 107 | `else 108 | 109 | // Synthesisable behavioural code 110 | 111 | reg out_pad; 112 | reg oe_pad; 113 | wire in_pad; 114 | 115 | generate 116 | if (SYNC_OUT == 0) begin: no_out_ff 117 | always @ (*) begin 118 | out_pad = out; 119 | oe_pad = oe; 120 | end 121 | end else begin: have_out_ff 122 | always @ (posedge clk or negedge rst_n) begin 123 | if (!rst_n) begin 124 | out_pad <= 1'b0; 125 | oe_pad <= 1'b0; 126 | end else begin 127 | out_pad <= out; 128 | oe_pad <= oe; 129 | end 130 | end 131 | end 132 | endgenerate 133 | 134 | generate 135 | if (SYNC_IN == 0) begin: no_in_ff 136 | assign in = in_pad; 137 | end else begin: have_in_ff 138 | reg in_r; 139 | always @ (posedge clk or negedge rst_n) begin 140 | if (!rst_n) begin 141 | in_r <= 1'b0; 142 | end else begin 143 | in_r <= in_pad; 144 | end 145 | end 146 | assign in = in_r; 147 | end 148 | endgenerate 149 | 150 | assign pad = oe_pad ? out_pad : 1'bz; 151 | assign in_pad = pad; 152 | 153 | `endif 154 | 155 | endmodule 156 | -------------------------------------------------------------------------------- /mem/async_sram_phy.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2023 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Async SRAM PHY: make an external, asynchronous SRAM appear like an 19 | // internal, synchronous SRAM. This also wraps all tristate signals, so that 20 | // tristate triples (in out oe) can be preserved up to the system top level, 21 | // allowing use of 2-state simulators like Verilator or CXXRTL. 22 | 23 | `default_nettype none 24 | 25 | module async_sram_phy #( 26 | parameter W_ADDR = 18, 27 | parameter W_DATA = 16, 28 | // If 1, register input paths, increasing read latency from 1 to 2 cycles: 29 | parameter DQ_SYNC_IN = 0 30 | ) ( 31 | // These should be the same clock/reset used by the controller 32 | input wire clk, 33 | input wire rst_n, 34 | 35 | // From SRAM controller 36 | input wire [W_ADDR-1:0] ctrl_addr, 37 | input wire [W_DATA-1:0] ctrl_dq_out, 38 | input wire [W_DATA-1:0] ctrl_dq_oe, 39 | output wire [W_DATA-1:0] ctrl_dq_in, 40 | input wire ctrl_ce_n, 41 | input wire ctrl_we_n, 42 | input wire ctrl_oe_n, 43 | input wire [W_DATA/8-1:0] ctrl_byte_n, 44 | 45 | // To external SRAM 46 | output wire [W_ADDR-1:0] sram_addr, 47 | inout wire [W_DATA-1:0] sram_dq, 48 | output wire sram_ce_n, 49 | output wire sram_we_n, 50 | output wire sram_oe_n, 51 | output wire [W_DATA/8-1:0] sram_byte_n 52 | ); 53 | 54 | tristate_io #( 55 | .SYNC_OUT (1), 56 | .SYNC_IN (1) 57 | ) addr_buf [W_ADDR-1:0] ( 58 | .clk (clk), 59 | .rst_n (rst_n), 60 | .out (ctrl_addr), 61 | .oe ({W_ADDR{1'b1}}), 62 | .in (), 63 | .pad (sram_addr) 64 | ); 65 | 66 | ddr_out we_ddr ( 67 | .clk (clk), 68 | .rst_n (rst_n), 69 | .d_rise (1'b1), 70 | .d_fall (ctrl_we_n), 71 | .q (sram_we_n) 72 | ); 73 | 74 | tristate_io #( 75 | .SYNC_OUT (1), 76 | .SYNC_IN (1) 77 | ) cmd_buf [1 + W_DATA / 8 -1:0] ( 78 | .clk (clk), 79 | .rst_n (rst_n), 80 | .out ({ctrl_oe_n, ctrl_byte_n}), 81 | .oe ({1 + W_DATA / 8{1'b1}}), 82 | .in (), 83 | .pad ({sram_oe_n, sram_byte_n}) 84 | ); 85 | 86 | // TODO this is grounded externally on the modified HX8k board, as a 87 | // workaround for a clock enable packing issue on a previous version of the 88 | // hardware. Should really be part of the cmd_buf above: 89 | assign sram_ce_n = 1'b0; 90 | 91 | `ifdef FPGA_ICE40 92 | 93 | localparam [5:0] DQ_PIN_TYPE = { 94 | // Posedge-registered output enable: 95 | 2'b11, 96 | // DDR (OPPOSITE_EDGE in Xilinx terms) output to allow negedge 97 | // registration of AHB HWDATA: 98 | 2'b00, 99 | // Optional input register 100 | DQ_SYNC_IN ? 2'b00 : 2'b01 101 | }; 102 | 103 | genvar g; 104 | generate 105 | for (g = 0; g < W_DATA; g = g + 1) begin: dq_buf_g 106 | // Note we can't use array instantiation for iCE40 cells, possibly because 107 | // Yosys doesn't know their type signature in advance 108 | SB_IO #( 109 | .PIN_TYPE (DQ_PIN_TYPE), 110 | .PULLUP (1'b0) 111 | ) dq_buf ( 112 | .OUTPUT_CLK (clk), 113 | .INPUT_CLK (clk), 114 | .PACKAGE_PIN (sram_dq[g]), 115 | .OUTPUT_ENABLE (ctrl_dq_oe[g]), 116 | // HWDATA presented on negedge, following half-cycle internal path: 117 | .D_OUT_1 (ctrl_dq_out[g]), 118 | // .. then repeated on the following posedge, to keep it stable as the 119 | // output driver turns off: 120 | .D_OUT_0 (ctrl_dq_out[g]), 121 | .D_IN_0 (ctrl_dq_in[g]) 122 | ); 123 | end 124 | endgenerate 125 | 126 | `else 127 | 128 | tristate_io #( 129 | .SYNC_OUT (0), 130 | .SYNC_IN (DQ_SYNC_IN) 131 | ) iobuf [W_DATA-1:0] ( 132 | .clk (clk), 133 | .rst_n (rst_n), 134 | .out (ctrl_dq_out), 135 | .oe (ctrl_dq_oe), 136 | .in (ctrl_dq_in), 137 | .pad (sram_dq) 138 | ); 139 | 140 | `endif 141 | 142 | endmodule 143 | 144 | `ifndef YOSYS 145 | `default_nettype wire 146 | `endif 147 | -------------------------------------------------------------------------------- /video/smoldvi_tmds_encode.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2020 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Encoder from the SmolDVI project: https://github.com/wren6991/smoldvi 19 | 20 | // This encoder is based on a property of the TMDS algorithm specified in DVI 21 | // spec: If the running balance is currently zero, and you encode data x 22 | // followed by x ^ 1, this produces a pair of TMDS symbols with net balance 23 | // zero, hence the running balance will *remain* at zero. Provided the input 24 | // follows this pattern (doubled pixels with alternating LSB), there is no 25 | // need to actually track the balance, which makes the encoder effectively 26 | // stateless. 27 | // 28 | // This leads to: 29 | // - Halving of horizontal resolution 30 | // - Loss of LSB (bit 0) of colour precision 31 | // - Toggling of colour LSBs (bit 0) across screen 32 | // 33 | // But this last effect is not noticeable in practice, and the first two are 34 | // acceptable for any pixel source that would fit onto a iCE40 UP5k or HX1k. 35 | // 36 | // Our TMDS algorithm: 37 | // 38 | // - Mask off d[0] 39 | // - If population count of d[7:0] less than 4: 40 | // - q[9:8] = 2'b01 for both output symbols 41 | // - First symbol q[n] = ^d[n:0] for n = 0...7 42 | // - Second symbol inverse of first q[7:0] (thanks to input LSB toggling) 43 | // - Else: 44 | // - q[9:8] = 2'b10 for both output symbols 45 | // - First symbol same as less than case but XOR'd with 'h55 (this 46 | // accounts for both XNOR-ness and q[9] complementing) 47 | // - Second symbol inverse of first q[7:0] (thanks to input LSB toggling) 48 | // 49 | // These rules *exactly* reproduce Figure 3-5 on page 29 of DVI v1.0 spec, if 50 | // the pixels input to that algorithm are manipulated properly. You can check 51 | // this by enumerating all possible input values, running them through the 52 | // original algorithm with initial balance = 0 (recalling that balance is 53 | // defined to be 0 at the start of each scanline), and noting that the balance 54 | // returns to 0 after each output pixel pair, forming the sketch of an 55 | // induction proof. 56 | // 57 | // To check that the output of our algorithm is DC-balanced, observe that bits 58 | // q[9:8] always have one bit set, and bits q[7:0] are complemented over 59 | // consecutive pixels, so have an average population count of 4 out of 8. 60 | // Therefore for every 20 bits we output (2 TMDS symbols), there are 10 1 bits 61 | // and 10 0 bits. 62 | // 63 | // Note that the instantiator is responsible for holding d[7:0] constant over 64 | // two cycles (it's not registered here) 65 | 66 | module smoldvi_tmds_encode ( 67 | input wire clk, 68 | input wire rst_n, 69 | 70 | input wire [1:0] c, 71 | input wire [7:0] d, 72 | input wire den, 73 | 74 | output reg [9:0] q 75 | ); 76 | 77 | reg [2:0] popcount; 78 | wire low_balance = !popcount[2]; 79 | 80 | always @ (*) begin: count_d_pop 81 | integer i; 82 | popcount = 3'd0; 83 | // Ignore d[0] as it's implicitly masked 84 | for (i = 1; i < 8; i = i + 1) 85 | popcount = popcount + {2'h0, d[i]}; 86 | end 87 | 88 | reg [7:0] d_reduced; 89 | reg symbol_is_second; 90 | 91 | always @ (*) begin: reduce_d 92 | integer i; 93 | d_reduced = 8'h0; 94 | for (i = 1; i < 8; i = i + 1) 95 | d_reduced[i] = d_reduced[i - 1] ^ d[i]; 96 | end 97 | 98 | wire [9:0] pixel_q = { 99 | !low_balance, 100 | low_balance, 101 | d_reduced ^ (8'h55 & {8{!low_balance}}) ^ {8{symbol_is_second}} 102 | }; 103 | 104 | always @ (posedge clk or negedge rst_n) begin 105 | if (!rst_n) begin 106 | symbol_is_second <= 1'b0; 107 | q <= 10'd0; 108 | end else begin 109 | if (den) begin 110 | symbol_is_second <= !symbol_is_second; 111 | q <= pixel_q; 112 | end else begin 113 | symbol_is_second <= 1'b0; 114 | case (c) 115 | 2'b00: q <= 10'b1101010100; 116 | 2'b01: q <= 10'b0010101011; 117 | 2'b10: q <= 10'b0101010100; 118 | 2'b11: q <= 10'b1010101011; 119 | endcase 120 | end 121 | end 122 | end 123 | 124 | endmodule 125 | -------------------------------------------------------------------------------- /mem/sram_sync.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Generate a (hopefully inference-compatible) memory with synchronous 19 | // read/write, and optional per-byte write enable 20 | 21 | module sram_sync #( 22 | parameter WIDTH = 32, 23 | parameter DEPTH = 1 << 11, 24 | parameter BYTE_ENABLE = 0, 25 | parameter PRELOAD_FILE = "", 26 | parameter ADDR_WIDTH = $clog2(DEPTH) // Let this default 27 | ) ( 28 | input wire clk, 29 | input wire [(BYTE_ENABLE ? WIDTH / 8 : 1)-1:0] wen, 30 | input wire ren, 31 | input wire [ADDR_WIDTH-1:0] addr, 32 | input wire [WIDTH-1:0] wdata, 33 | output reg [WIDTH-1:0] rdata 34 | ); 35 | 36 | `ifdef FPGA_ICE40 37 | localparam FPGA_ICE40_DEFINED = 1; 38 | `else 39 | localparam FPGA_ICE40_DEFINED = 0; 40 | `endif 41 | 42 | `ifdef SIM 43 | localparam SIM_DEFINED = 1; 44 | `else 45 | localparam SIM_DEFINED = 0; 46 | `endif 47 | 48 | generate 49 | if (FPGA_ICE40_DEFINED && WIDTH == 32 && DEPTH == 1 << 15) begin: up5k_spram 50 | // Special case: use all SPRAMs on UP5k 51 | 52 | wire [31:0] rdata0; 53 | wire [31:0] rdata1; 54 | 55 | SB_SPRAM256KA ram00 ( 56 | .ADDRESS (addr[13:0]), 57 | .DATAIN (wdata[15:0]), 58 | .MASKWREN ({wen[1], wen[1], wen[0], wen[0]}), 59 | .WREN (wen[1] || wen[0]), 60 | .CHIPSELECT ((wen[1] || wen[0] || ren) && !addr[14]), 61 | .CLOCK (clk), 62 | .STANDBY (1'b0), 63 | .SLEEP (1'b0), 64 | .POWEROFF (1'b1), 65 | .DATAOUT (rdata0[15:0]) 66 | ); 67 | 68 | SB_SPRAM256KA ram01 ( 69 | .ADDRESS (addr[13:0]), 70 | .DATAIN (wdata[31:16]), 71 | .MASKWREN ({wen[3], wen[3], wen[2], wen[2]}), 72 | .WREN (wen[3] || wen[2]), 73 | .CHIPSELECT ((wen[3] || wen[2] || ren) && !addr[14]), 74 | .CLOCK (clk), 75 | .STANDBY (1'b0), 76 | .SLEEP (1'b0), 77 | .POWEROFF (1'b1), 78 | .DATAOUT (rdata0[31:16]) 79 | ); 80 | 81 | SB_SPRAM256KA ram10 ( 82 | .ADDRESS (addr[13:0]), 83 | .DATAIN (wdata[15:0]), 84 | .MASKWREN ({wen[1], wen[1], wen[0], wen[0]}), 85 | .WREN (wen[1] || wen[0]), 86 | .CHIPSELECT ((wen[1] || wen[0] || ren) && addr[14]), 87 | .CLOCK (clk), 88 | .STANDBY (1'b0), 89 | .SLEEP (1'b0), 90 | .POWEROFF (1'b1), 91 | .DATAOUT (rdata1[15:0]) 92 | ); 93 | 94 | SB_SPRAM256KA ram11 ( 95 | .ADDRESS (addr[13:0]), 96 | .DATAIN (wdata[31:16]), 97 | .MASKWREN ({wen[3], wen[3], wen[2], wen[2]}), 98 | .WREN (wen[3] || wen[2]), 99 | .CHIPSELECT ((wen[3] || wen[2] || ren) && addr[14]), 100 | .CLOCK (clk), 101 | .STANDBY (1'b0), 102 | .SLEEP (1'b0), 103 | .POWEROFF (1'b1), 104 | .DATAOUT (rdata1[31:16]) 105 | ); 106 | 107 | reg chipselect_prev; 108 | always @ (posedge clk) 109 | if (|wen || ren) 110 | chipselect_prev <= addr[14]; 111 | 112 | always @ (*) rdata = chipselect_prev ? rdata1 : rdata0; 113 | 114 | end else begin: behav_mem 115 | // Behavioural model, but Yosys does a great job of this on ECP5 and iCE40. 116 | 117 | genvar i; 118 | 119 | `ifdef YOSYS 120 | (* no_rw_check *) 121 | `endif 122 | reg [WIDTH-1:0] mem [0:DEPTH-1]; 123 | 124 | if (PRELOAD_FILE != "" || SIM_DEFINED) begin: preload 125 | initial begin: preload_initial 126 | `ifdef SIM 127 | integer n; 128 | for (n = 0; n < DEPTH; n = n + 1) 129 | mem[n] = {WIDTH{1'b0}}; 130 | `endif 131 | if (PRELOAD_FILE != "") 132 | $readmemh(PRELOAD_FILE, mem); 133 | end 134 | end 135 | 136 | 137 | if (BYTE_ENABLE) begin: has_byte_enable 138 | for (i = 0; i < WIDTH / 8; i = i + 1) begin: byte_mem 139 | always @ (posedge clk) begin 140 | if (wen[i]) 141 | mem[addr][8 * i +: 8] <= wdata[8 * i +: 8]; 142 | if (ren) 143 | rdata[8 * i +: 8] <= mem[addr][8 * i +: 8]; 144 | end 145 | end 146 | end else begin: no_byte_enable 147 | always @ (posedge clk) begin 148 | if (wen) 149 | mem[addr] <= wdata; 150 | if (ren) 151 | rdata <= mem[addr]; 152 | end 153 | end 154 | 155 | end 156 | endgenerate 157 | 158 | endmodule 159 | -------------------------------------------------------------------------------- /peris/spi/spi_regs.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * AUTOGENERATED BY REGBLOCK * 3 | * Do not edit manually. * 4 | * Edit the source file (or regblock utility) and regenerate. * 5 | *******************************************************************************/ 6 | 7 | #ifndef _SPI_REGS_H_ 8 | #define _SPI_REGS_H_ 9 | 10 | // Block name : spi 11 | // Bus type : apb 12 | // Bus data width : 32 13 | // Bus address width : 16 14 | 15 | #define SPI_CSR_OFFS 0 16 | #define SPI_DIV_OFFS 4 17 | #define SPI_FSTAT_OFFS 8 18 | #define SPI_TX_OFFS 12 19 | #define SPI_RX_OFFS 16 20 | 21 | /******************************************************************************* 22 | * CSR * 23 | *******************************************************************************/ 24 | 25 | // Control and status register 26 | 27 | // Field: CSR_CSAUTO Access: RW 28 | // If 1, CS pin is driven automatically (low during data transfer, else high) 29 | #define SPI_CSR_CSAUTO_LSB 9 30 | #define SPI_CSR_CSAUTO_BITS 1 31 | #define SPI_CSR_CSAUTO_MASK 0x200 32 | // Field: CSR_CS Access: RW 33 | // If automatic CS is disabled, use this bit to control CS signal. 34 | #define SPI_CSR_CS_LSB 8 35 | #define SPI_CSR_CS_BITS 1 36 | #define SPI_CSR_CS_MASK 0x100 37 | // Field: CSR_LOOPBACK Access: RW 38 | // If 1, connect MOSI to MISO internally, for debugging purposes 39 | #define SPI_CSR_LOOPBACK_LSB 5 40 | #define SPI_CSR_LOOPBACK_BITS 1 41 | #define SPI_CSR_LOOPBACK_MASK 0x20 42 | // Field: CSR_READ_EN Access: RW 43 | // If 0, the received data will not be pushed to RX FIFO. (Transmit only) 44 | #define SPI_CSR_READ_EN_LSB 4 45 | #define SPI_CSR_READ_EN_BITS 1 46 | #define SPI_CSR_READ_EN_MASK 0x10 47 | // Field: CSR_CPOL Access: RW 48 | // If 0, SCLK low when idle. If 1, high when idle. 49 | #define SPI_CSR_CPOL_LSB 3 50 | #define SPI_CSR_CPOL_BITS 1 51 | #define SPI_CSR_CPOL_MASK 0x8 52 | // Field: CSR_CPHA Access: RW 53 | // If 0, data captured on leading edge of SCLK pulse. If 1, trailing edge. 54 | #define SPI_CSR_CPHA_LSB 2 55 | #define SPI_CSR_CPHA_BITS 1 56 | #define SPI_CSR_CPHA_MASK 0x4 57 | // Field: CSR_BUSY Access: ROV 58 | // A transfer is in progress 59 | #define SPI_CSR_BUSY_LSB 0 60 | #define SPI_CSR_BUSY_BITS 1 61 | #define SPI_CSR_BUSY_MASK 0x1 62 | 63 | /******************************************************************************* 64 | * DIV * 65 | *******************************************************************************/ 66 | 67 | // Clock divider register 68 | 69 | // Field: DIV Access: RW 70 | #define SPI_DIV_LSB 0 71 | #define SPI_DIV_BITS 6 72 | #define SPI_DIV_MASK 0x3f 73 | 74 | /******************************************************************************* 75 | * FSTAT * 76 | *******************************************************************************/ 77 | 78 | // FIFO status register 79 | 80 | // Field: FSTAT_TXLEVEL Access: ROV 81 | #define SPI_FSTAT_TXLEVEL_LSB 0 82 | #define SPI_FSTAT_TXLEVEL_BITS 8 83 | #define SPI_FSTAT_TXLEVEL_MASK 0xff 84 | // Field: FSTAT_TXFULL Access: ROV 85 | #define SPI_FSTAT_TXFULL_LSB 8 86 | #define SPI_FSTAT_TXFULL_BITS 1 87 | #define SPI_FSTAT_TXFULL_MASK 0x100 88 | // Field: FSTAT_TXEMPTY Access: ROV 89 | #define SPI_FSTAT_TXEMPTY_LSB 9 90 | #define SPI_FSTAT_TXEMPTY_BITS 1 91 | #define SPI_FSTAT_TXEMPTY_MASK 0x200 92 | // Field: FSTAT_TXOVER Access: W1C 93 | #define SPI_FSTAT_TXOVER_LSB 10 94 | #define SPI_FSTAT_TXOVER_BITS 1 95 | #define SPI_FSTAT_TXOVER_MASK 0x400 96 | // Field: FSTAT_RXLEVEL Access: ROV 97 | #define SPI_FSTAT_RXLEVEL_LSB 16 98 | #define SPI_FSTAT_RXLEVEL_BITS 8 99 | #define SPI_FSTAT_RXLEVEL_MASK 0xff0000 100 | // Field: FSTAT_RXFULL Access: ROV 101 | #define SPI_FSTAT_RXFULL_LSB 24 102 | #define SPI_FSTAT_RXFULL_BITS 1 103 | #define SPI_FSTAT_RXFULL_MASK 0x1000000 104 | // Field: FSTAT_RXEMPTY Access: ROV 105 | #define SPI_FSTAT_RXEMPTY_LSB 25 106 | #define SPI_FSTAT_RXEMPTY_BITS 1 107 | #define SPI_FSTAT_RXEMPTY_MASK 0x2000000 108 | // Field: FSTAT_RXOVER Access: W1C 109 | #define SPI_FSTAT_RXOVER_LSB 26 110 | #define SPI_FSTAT_RXOVER_BITS 1 111 | #define SPI_FSTAT_RXOVER_MASK 0x4000000 112 | // Field: FSTAT_RXUNDER Access: W1C 113 | #define SPI_FSTAT_RXUNDER_LSB 27 114 | #define SPI_FSTAT_RXUNDER_BITS 1 115 | #define SPI_FSTAT_RXUNDER_MASK 0x8000000 116 | 117 | /******************************************************************************* 118 | * TX * 119 | *******************************************************************************/ 120 | 121 | // TX data FIFO 122 | 123 | // Field: TX Access: WF 124 | #define SPI_TX_LSB 0 125 | #define SPI_TX_BITS 8 126 | #define SPI_TX_MASK 0xff 127 | 128 | /******************************************************************************* 129 | * RX * 130 | *******************************************************************************/ 131 | 132 | // RX data FIFO 133 | 134 | // Field: RX Access: RF 135 | #define SPI_RX_LSB 0 136 | #define SPI_RX_BITS 8 137 | #define SPI_RX_MASK 0xff 138 | 139 | #endif // _SPI_REGS_H_ 140 | -------------------------------------------------------------------------------- /peris/uart/uart_regs.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * AUTOGENERATED BY REGBLOCK * 3 | * Do not edit manually. * 4 | * Edit the source file (or regblock utility) and regenerate. * 5 | *******************************************************************************/ 6 | 7 | #ifndef _UART_REGS_H_ 8 | #define _UART_REGS_H_ 9 | 10 | // Block name : uart 11 | // Bus type : apb 12 | // Bus data width : 32 13 | // Bus address width : 16 14 | 15 | #define UART_CSR_OFFS 0 16 | #define UART_DIV_OFFS 4 17 | #define UART_FSTAT_OFFS 8 18 | #define UART_TX_OFFS 12 19 | #define UART_RX_OFFS 16 20 | 21 | /******************************************************************************* 22 | * CSR * 23 | *******************************************************************************/ 24 | 25 | // Control and status register 26 | 27 | // Field: CSR_EN Access: RW 28 | // UART runs when en is high. Synchronous reset (excluding FIFOs) when low. 29 | #define UART_CSR_EN_LSB 0 30 | #define UART_CSR_EN_BITS 1 31 | #define UART_CSR_EN_MASK 0x1 32 | // Field: CSR_BUSY Access: ROV 33 | // UART TX is still sending data 34 | #define UART_CSR_BUSY_LSB 1 35 | #define UART_CSR_BUSY_BITS 1 36 | #define UART_CSR_BUSY_MASK 0x2 37 | // Field: CSR_TXIE Access: RW 38 | // Enable TX FIFO interrupt 39 | #define UART_CSR_TXIE_LSB 2 40 | #define UART_CSR_TXIE_BITS 1 41 | #define UART_CSR_TXIE_MASK 0x4 42 | // Field: CSR_RXIE Access: RW 43 | // Enable RX FIFO interrupt 44 | #define UART_CSR_RXIE_LSB 3 45 | #define UART_CSR_RXIE_BITS 1 46 | #define UART_CSR_RXIE_MASK 0x8 47 | // Field: CSR_CTSEN Access: RW 48 | // Enable pausing of TX while CTS is not asserted 49 | #define UART_CSR_CTSEN_LSB 4 50 | #define UART_CSR_CTSEN_BITS 1 51 | #define UART_CSR_CTSEN_MASK 0x10 52 | // Field: CSR_LOOPBACK Access: RW 53 | // Connect TX -> RX and RTS -> CTS internally (for testing). 54 | #define UART_CSR_LOOPBACK_LSB 8 55 | #define UART_CSR_LOOPBACK_BITS 1 56 | #define UART_CSR_LOOPBACK_MASK 0x100 57 | 58 | /******************************************************************************* 59 | * DIV * 60 | *******************************************************************************/ 61 | 62 | // Clock divider control fields 63 | 64 | // Field: DIV_INT Access: WO 65 | #define UART_DIV_INT_LSB 4 66 | #define UART_DIV_INT_BITS 10 67 | #define UART_DIV_INT_MASK 0x3ff0 68 | // Field: DIV_FRAC Access: WO 69 | #define UART_DIV_FRAC_LSB 0 70 | #define UART_DIV_FRAC_BITS 4 71 | #define UART_DIV_FRAC_MASK 0xf 72 | 73 | /******************************************************************************* 74 | * FSTAT * 75 | *******************************************************************************/ 76 | 77 | // FIFO status register 78 | 79 | // Field: FSTAT_TXLEVEL Access: ROV 80 | #define UART_FSTAT_TXLEVEL_LSB 0 81 | #define UART_FSTAT_TXLEVEL_BITS 8 82 | #define UART_FSTAT_TXLEVEL_MASK 0xff 83 | // Field: FSTAT_TXFULL Access: ROV 84 | #define UART_FSTAT_TXFULL_LSB 8 85 | #define UART_FSTAT_TXFULL_BITS 1 86 | #define UART_FSTAT_TXFULL_MASK 0x100 87 | // Field: FSTAT_TXEMPTY Access: ROV 88 | #define UART_FSTAT_TXEMPTY_LSB 9 89 | #define UART_FSTAT_TXEMPTY_BITS 1 90 | #define UART_FSTAT_TXEMPTY_MASK 0x200 91 | // Field: FSTAT_TXOVER Access: W1C 92 | #define UART_FSTAT_TXOVER_LSB 10 93 | #define UART_FSTAT_TXOVER_BITS 1 94 | #define UART_FSTAT_TXOVER_MASK 0x400 95 | // Field: FSTAT_TXUNDER Access: W1C 96 | #define UART_FSTAT_TXUNDER_LSB 11 97 | #define UART_FSTAT_TXUNDER_BITS 1 98 | #define UART_FSTAT_TXUNDER_MASK 0x800 99 | // Field: FSTAT_RXLEVEL Access: ROV 100 | #define UART_FSTAT_RXLEVEL_LSB 16 101 | #define UART_FSTAT_RXLEVEL_BITS 8 102 | #define UART_FSTAT_RXLEVEL_MASK 0xff0000 103 | // Field: FSTAT_RXFULL Access: ROV 104 | #define UART_FSTAT_RXFULL_LSB 24 105 | #define UART_FSTAT_RXFULL_BITS 1 106 | #define UART_FSTAT_RXFULL_MASK 0x1000000 107 | // Field: FSTAT_RXEMPTY Access: ROV 108 | #define UART_FSTAT_RXEMPTY_LSB 25 109 | #define UART_FSTAT_RXEMPTY_BITS 1 110 | #define UART_FSTAT_RXEMPTY_MASK 0x2000000 111 | // Field: FSTAT_RXOVER Access: W1C 112 | #define UART_FSTAT_RXOVER_LSB 26 113 | #define UART_FSTAT_RXOVER_BITS 1 114 | #define UART_FSTAT_RXOVER_MASK 0x4000000 115 | // Field: FSTAT_RXUNDER Access: W1C 116 | #define UART_FSTAT_RXUNDER_LSB 27 117 | #define UART_FSTAT_RXUNDER_BITS 1 118 | #define UART_FSTAT_RXUNDER_MASK 0x8000000 119 | 120 | /******************************************************************************* 121 | * TX * 122 | *******************************************************************************/ 123 | 124 | // TX data FIFO 125 | 126 | // Field: TX Access: WF 127 | #define UART_TX_LSB 0 128 | #define UART_TX_BITS 8 129 | #define UART_TX_MASK 0xff 130 | 131 | /******************************************************************************* 132 | * RX * 133 | *******************************************************************************/ 134 | 135 | // RX data FIFO 136 | 137 | // Field: RX Access: RF 138 | #define UART_RX_LSB 0 139 | #define UART_RX_BITS 8 140 | #define UART_RX_MASK 0xff 141 | 142 | #endif // _UART_REGS_H_ 143 | -------------------------------------------------------------------------------- /sdram/regs/sdram_ctrl_regs.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * AUTOGENERATED BY REGBLOCK * 3 | * Do not edit manually. * 4 | * Edit the source file (or regblock utility) and regenerate. * 5 | *******************************************************************************/ 6 | 7 | #ifndef _SDRAM_REGS_H_ 8 | #define _SDRAM_REGS_H_ 9 | 10 | // Block name : sdram 11 | // Bus type : apb 12 | // Bus data width : 32 13 | // Bus address width : 16 14 | 15 | #define SDRAM_CSR_OFFS 0 16 | #define SDRAM_TIME_OFFS 4 17 | #define SDRAM_REFRESH_OFFS 8 18 | #define SDRAM_CMD_DIRECT_OFFS 12 19 | 20 | /******************************************************************************* 21 | * CSR * 22 | *******************************************************************************/ 23 | 24 | // Control and status register 25 | 26 | // Field: CSR_EN Access: RW 27 | // Enable bus access to SDRAM, and start issuing refresh commands. Should not be 28 | // asserted until after the SDRAM initialisation sequence has been issued (e.g. 29 | // a PrechargeAll, some AutoRefreshes, and a ModeRegisterSet). 30 | #define SDRAM_CSR_EN_LSB 0 31 | #define SDRAM_CSR_EN_BITS 1 32 | #define SDRAM_CSR_EN_MASK 0x1 33 | // Field: CSR_PU Access: RW 34 | // Power up (start driving clock and assert clock enable). Must be asserted 35 | // before using CMD_DIRECT for start-of-day initialisation. 36 | #define SDRAM_CSR_PU_LSB 1 37 | #define SDRAM_CSR_PU_BITS 1 38 | #define SDRAM_CSR_PU_MASK 0x2 39 | 40 | /******************************************************************************* 41 | * TIME * 42 | *******************************************************************************/ 43 | 44 | // Configure SDRAM timing parameters. All times given in clock cycles. Unless 45 | // otherwise specified, the minimum timing is 1 cycle, and this is encoded by a 46 | // value of *0* in the relevant register field. Your SDRAM datasheet should 47 | // provide these timings. 48 | 49 | // Field: TIME_RC Access: RW 50 | // tRC: Row cycle time, row activate to row activate (same bank). tRFC, refresh 51 | // cycle time, is assumed to be equal to this value. If these values are 52 | // different in your datasheet, take the larger one. 53 | #define SDRAM_TIME_RC_LSB 0 54 | #define SDRAM_TIME_RC_BITS 3 55 | #define SDRAM_TIME_RC_MASK 0x7 56 | // Field: TIME_RCD Access: RW 57 | // tRCD: RAS to CAS delay (same bank). 58 | #define SDRAM_TIME_RCD_LSB 4 59 | #define SDRAM_TIME_RCD_BITS 3 60 | #define SDRAM_TIME_RCD_MASK 0x70 61 | // Field: TIME_RP Access: RW 62 | // tRP: Precharge to refresh/row activate command (same bank). 63 | #define SDRAM_TIME_RP_LSB 8 64 | #define SDRAM_TIME_RP_BITS 3 65 | #define SDRAM_TIME_RP_MASK 0x700 66 | // Field: TIME_RRD Access: RW 67 | // tRRD: Row activate to row activate delay (different banks). 68 | #define SDRAM_TIME_RRD_LSB 12 69 | #define SDRAM_TIME_RRD_BITS 3 70 | #define SDRAM_TIME_RRD_MASK 0x7000 71 | // Field: TIME_RAS Access: RW 72 | // tRAS: Row activate to precharge time (same bank). 73 | #define SDRAM_TIME_RAS_LSB 16 74 | #define SDRAM_TIME_RAS_BITS 3 75 | #define SDRAM_TIME_RAS_MASK 0x70000 76 | // Field: TIME_WR Access: RW 77 | // tWR: Write recovery time. Last Write data to Precharge (same bank) 78 | #define SDRAM_TIME_WR_LSB 20 79 | #define SDRAM_TIME_WR_BITS 3 80 | #define SDRAM_TIME_WR_MASK 0x700000 81 | // Field: TIME_CAS Access: RW 82 | // CAS latency. Should match the value programmed into SDRAM mode register. 83 | #define SDRAM_TIME_CAS_LSB 24 84 | #define SDRAM_TIME_CAS_BITS 2 85 | #define SDRAM_TIME_CAS_MASK 0x3000000 86 | 87 | /******************************************************************************* 88 | * REFRESH * 89 | *******************************************************************************/ 90 | 91 | // tREFI: Average refresh interval, in SDRAM clock cycles. 92 | 93 | // Field: REFRESH Access: RW 94 | #define SDRAM_REFRESH_LSB 0 95 | #define SDRAM_REFRESH_BITS 12 96 | #define SDRAM_REFRESH_MASK 0xfff 97 | 98 | /******************************************************************************* 99 | * CMD_DIRECT * 100 | *******************************************************************************/ 101 | 102 | // Write to assert a command directly onto SDRAM e.g. Load Mode Register. Only 103 | // to be used when bus is idle and CSR_EN is low (e.g. for start-of-day 104 | // initialisation) 105 | 106 | // Field: CMD_DIRECT_WE_N Access: WF 107 | #define SDRAM_CMD_DIRECT_WE_N_LSB 0 108 | #define SDRAM_CMD_DIRECT_WE_N_BITS 1 109 | #define SDRAM_CMD_DIRECT_WE_N_MASK 0x1 110 | // Field: CMD_DIRECT_CAS_N Access: WF 111 | #define SDRAM_CMD_DIRECT_CAS_N_LSB 1 112 | #define SDRAM_CMD_DIRECT_CAS_N_BITS 1 113 | #define SDRAM_CMD_DIRECT_CAS_N_MASK 0x2 114 | // Field: CMD_DIRECT_RAS_N Access: WF 115 | #define SDRAM_CMD_DIRECT_RAS_N_LSB 2 116 | #define SDRAM_CMD_DIRECT_RAS_N_BITS 1 117 | #define SDRAM_CMD_DIRECT_RAS_N_MASK 0x4 118 | // Field: CMD_DIRECT_ADDR Access: WF 119 | #define SDRAM_CMD_DIRECT_ADDR_LSB 3 120 | #define SDRAM_CMD_DIRECT_ADDR_BITS 13 121 | #define SDRAM_CMD_DIRECT_ADDR_MASK 0xfff8 122 | // Field: CMD_DIRECT_BA Access: WF 123 | #define SDRAM_CMD_DIRECT_BA_LSB 28 124 | #define SDRAM_CMD_DIRECT_BA_BITS 2 125 | #define SDRAM_CMD_DIRECT_BA_MASK 0x30000000 126 | 127 | #endif // _SDRAM_REGS_H_ 128 | -------------------------------------------------------------------------------- /cdc/async_fifo.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Asynchronous FIFO 19 | 20 | // wclk and rclk are two free-running clocks with arbitrary relationship. 21 | // Full/empty signals, and levels, are approximate, but conservative. 22 | // They are calculated with a sync'd version of the other clock domain's 23 | // pointer; W may see more data than is actually there (but never less) 24 | // and R may see less data (but never more), as pointers only move forward. 25 | 26 | // There are two async resets; ideally these should be the same reset, but with 27 | // rising edges synchronised to each clock domain. 28 | 29 | // This is based on Style #2 from Cummings' paper: 30 | // Simulation and Synthesis Techniques for Asynchronous FIFO Design (SNUG 2002) 31 | 32 | /* verilator lint_off PINCONNECTEMPTY */ 33 | 34 | module async_fifo #( 35 | parameter W_DATA = 16, 36 | parameter W_ADDR = 3, 37 | parameter SYNC_STAGES = 2 38 | ) ( 39 | input wire wrst_n, 40 | input wire wclk, 41 | input wire [W_DATA-1:0] wdata, 42 | input wire wpush, 43 | output wire wfull, 44 | output wire wempty, 45 | output wire [W_ADDR:0] wlevel, 46 | 47 | input wire rrst_n, 48 | input wire rclk, 49 | output reg [W_DATA-1:0] rdata, 50 | input wire rpop, 51 | output wire rfull, 52 | output wire rempty, 53 | output wire [W_ADDR:0] rlevel 54 | ); 55 | 56 | // ---------------------------------------------------------------------------- 57 | // Flags and controls (flags are mildly pessimistic) 58 | 59 | // Pointers are 1 bit oversized to distinguish empty from full state. 60 | wire [W_ADDR:0] wptr_w; // | 61 | wire [W_ADDR:0] wptr_gry_w; // | progression 62 | wire [W_ADDR:0] wptr_gry_r; // V 63 | wire [W_ADDR:0] wptr_r; 64 | 65 | wire [W_ADDR:0] rptr_r; 66 | wire [W_ADDR:0] rptr_gry_r; 67 | wire [W_ADDR:0] rptr_gry_w; 68 | wire [W_ADDR:0] rptr_w; 69 | 70 | wire [W_ADDR:0] rptr_r_next; 71 | 72 | // rptr_w and wptr_r are expensive (Gray-decoded), so avoid them for full/empty calculations 73 | // For full, due to symmetries in Gray code, we check that 2 MSBs differ and all others are equal 74 | assign wempty = wptr_gry_w == rptr_gry_w; 75 | assign wfull = wptr_gry_w == (rptr_gry_w ^ {2'b11, {W_ADDR-1{1'b0}}}); 76 | assign wlevel = wptr_w - rptr_w; 77 | 78 | assign rempty = rptr_gry_r == wptr_gry_r; 79 | assign rfull = rptr_gry_r == (wptr_gry_r ^ {2'b11, {W_ADDR-1{1'b0}}}); 80 | assign rlevel = wptr_r - rptr_r; 81 | 82 | wire push_actual = wpush && !wfull; 83 | wire pop_actual = rpop && !rempty; 84 | 85 | //synthesis translate_off 86 | always @ (posedge wclk) 87 | if (wpush && wfull) 88 | $display($time, ": WARNING %m: push on full"); 89 | always @ (posedge rclk) 90 | if (rpop && rempty) 91 | $display($time, ": WARNING %m: pop on empty"); 92 | //synthesis translate_on 93 | 94 | // ---------------------------------------------------------------------------- 95 | // Pointer counters and synchronisation 96 | 97 | gray_counter #( 98 | .W_CTR (W_ADDR + 1) 99 | ) gray_counter_w ( 100 | .clk (wclk), 101 | .rst_n (wrst_n), 102 | .en (push_actual), 103 | .clr (1'b0), 104 | .count_bin (wptr_w), 105 | .count_bin_next (/* unused */), 106 | .count_gry (wptr_gry_w) 107 | ); 108 | 109 | gray_counter #( 110 | .W_CTR (W_ADDR + 1) 111 | ) gray_counter_r ( 112 | .clk (rclk), 113 | .rst_n (rrst_n), 114 | .en (pop_actual), 115 | .clr (1'b0), 116 | .count_bin (rptr_r), 117 | .count_bin_next (rptr_r_next), 118 | .count_gry (rptr_gry_r) 119 | ); 120 | 121 | sync_1bit #( 122 | .N_STAGES (SYNC_STAGES + 1) 123 | ) sync_wptr [W_ADDR:0] ( 124 | .clk (rclk), 125 | .rst_n (rrst_n), 126 | .i (wptr_gry_w), 127 | .o (wptr_gry_r) 128 | ); 129 | 130 | sync_1bit #( 131 | .N_STAGES (SYNC_STAGES) 132 | ) sync_rptr [W_ADDR:0] ( 133 | .clk (wclk), 134 | .rst_n (wrst_n), 135 | .i (rptr_gry_r), 136 | .o (rptr_gry_w) 137 | ); 138 | 139 | gray_decode #( 140 | .N (W_ADDR + 1) 141 | ) decode_wptr ( 142 | .i (wptr_gry_r), 143 | .o (wptr_r) 144 | ); 145 | 146 | gray_decode #( 147 | .N (W_ADDR + 1) 148 | ) decode_rptr ( 149 | .i (rptr_gry_w), 150 | .o (rptr_w) 151 | ); 152 | 153 | // ---------------------------------------------------------------------------- 154 | // Memory and read/write ports 155 | 156 | localparam MEM_DEPTH = 1 << W_ADDR; 157 | reg [W_DATA-1:0] mem [0:MEM_DEPTH-1]; 158 | 159 | wire [W_ADDR-1:0] memptr_w = wptr_w[W_ADDR-1:0]; 160 | wire [W_ADDR-1:0] memptr_r = pop_actual ? rptr_r_next[W_ADDR-1:0] : rptr_r[W_ADDR-1:0]; 161 | 162 | always @ (posedge wclk) 163 | if (push_actual) 164 | mem[memptr_w] <= wdata; 165 | 166 | always @ (posedge rclk) 167 | rdata <= mem[memptr_r]; 168 | 169 | endmodule 170 | -------------------------------------------------------------------------------- /cdc/gearbox.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2020 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Clock-crossing gearbox. Pack/unpack a parallel bus n bits wide at f MHz 19 | // into a bus n / k bits wide at f * k MHz. The two clocks must derive from a 20 | // common root oscillator. 21 | // 22 | // Ideally rst_n_in and rst_n_out should be derived from the same asynchronous 23 | // reset, but each with their deassertion synchronised to the respective clock 24 | // domain. 25 | // 26 | // Some pseudocode for selecting a reasonable storage size: 27 | // 28 | // size = lowest_common_multiple(W_IN, W_OUT) 29 | // while size < W_IN * 4 or size < W_OUT * 4: 30 | // size = size * 2 31 | 32 | module gearbox #( 33 | parameter W_IN = 10, 34 | parameter W_OUT = 2, 35 | // You should set this by hand, it may be hugely pessimistic *or* optimistic: 36 | parameter STORAGE_SIZE = W_IN * W_OUT, 37 | // Reduce the granularity of capture clock enable to help PLB packing on 38 | // iCE40 (careful with your divisibility): 39 | parameter CE_GROUPING_FACTOR = 1, 40 | // Use external counters, which can be shared between gearboxes, for bigger 41 | // CE groups and better PLB packing on iCE40: 42 | parameter USE_EXTERNAL_COUNTERS = 0 43 | ) ( 44 | input wire clk_in, 45 | input wire rst_n_in, 46 | input wire [W_IN-1:0] din, 47 | 48 | input wire clk_out, 49 | input wire rst_n_out, 50 | output reg [W_OUT-1:0] dout, 51 | 52 | // Disconnect unless USE_EXTERNAL_COUNTERS is set: 53 | input wire [STORAGE_SIZE / W_IN - 1:0] external_ctr_in, 54 | input wire [STORAGE_SIZE / W_OUT - 1:0] external_ctr_out 55 | ); 56 | 57 | localparam N_IN = STORAGE_SIZE / W_IN; 58 | localparam N_OUT = STORAGE_SIZE / W_OUT; 59 | 60 | (* keep = 1'b1 *) reg [STORAGE_SIZE-1:0] launch_reg; 61 | (* keep = 1'b1 *) reg [STORAGE_SIZE-1:0] capture_reg; 62 | 63 | // ---------------------------------------------------------------------------- 64 | // Apply transitions to sections of launch register, in a circular manner, 65 | // across successive clk_in cycles 66 | 67 | reg [N_IN-1:0] wmask; 68 | 69 | generate 70 | if (USE_EXTERNAL_COUNTERS) begin: no_wctr 71 | always @ (*) wmask = external_ctr_in; 72 | end else begin: has_wctr 73 | always @ (posedge clk_in or negedge rst_n_in) begin 74 | if (!rst_n_in) begin 75 | wmask <= {{N_IN-1{1'b0}}, 1'b1}; 76 | end else begin 77 | wmask <= {wmask[N_IN-2:0], wmask[N_IN-1]}; 78 | end 79 | end 80 | end 81 | endgenerate 82 | 83 | always @ (posedge clk_in) begin: wport 84 | integer i; 85 | for (i = 0; i < N_IN; i = i + 1) begin 86 | if (wmask[i]) 87 | launch_reg[i * W_IN +: W_IN] <= din; 88 | end 89 | end 90 | 91 | // ---------------------------------------------------------------------------- 92 | // Apply enables to sections of capture register, in a circular manner, across 93 | // successive clk_out cycles (hopefully staying distant from the transitions!) 94 | 95 | reg [N_OUT-1:0] rmask; 96 | 97 | generate 98 | if (USE_EXTERNAL_COUNTERS) begin: no_rctr 99 | always @ (*) rmask = external_ctr_out; 100 | end else begin: has_rctr 101 | always @ (posedge clk_out or negedge rst_n_out) begin 102 | if (!rst_n_out) begin 103 | // Reads start as far as possible from writes 104 | rmask <= {{N_OUT-1{1'b0}}, 1'b1} << (N_OUT / 2); 105 | end else begin 106 | rmask <= {rmask[N_OUT-2:0], rmask[N_OUT-1]}; 107 | end 108 | end 109 | end 110 | endgenerate 111 | 112 | always @ (posedge clk_out) begin: capture_proc 113 | integer i; 114 | for (i = 0; i < N_OUT; i = i + 1) begin 115 | if (rmask[i / CE_GROUPING_FACTOR * CE_GROUPING_FACTOR]) 116 | capture_reg[i * W_OUT +: W_OUT] <= launch_reg[i * W_OUT +: W_OUT]; 117 | end 118 | end 119 | 120 | // ---------------------------------------------------------------------------- 121 | // CDC done, now on to the muxing 122 | 123 | wire [N_OUT-1:0] rmask_delayed = {rmask[0], rmask[N_OUT-1:1]}; 124 | reg [STORAGE_SIZE-1:0] captured_masked; 125 | 126 | always @ (posedge clk_out) begin: output_mask 127 | integer i; 128 | for (i = 0; i < STORAGE_SIZE; i = i + 1) begin 129 | captured_masked[i] <= capture_reg[i] && rmask_delayed[i / W_OUT]; 130 | end 131 | end 132 | 133 | // Do the OR reduction in one cycle. For 20 storage flops this is a 10:1 134 | // reduction, which costs 2 LUT delays. Easiest way to reduce further is to add 135 | // an empty pipe stage afterward and tell the tools to retime :) OR reductions 136 | // are very retimable. 137 | 138 | reg [W_OUT-1:0] muxed; 139 | 140 | always @ (*) begin: output_mux 141 | integer i, j; 142 | for (i = 0; i < W_OUT; i = i + 1) begin 143 | muxed[i] = 1'b0; 144 | for (j = 0; j < N_OUT; j = j + 1) begin 145 | muxed[i] = muxed[i] || captured_masked[j * W_OUT + i]; 146 | end 147 | end 148 | end 149 | 150 | always @ (posedge clk_out) begin 151 | dout <= muxed; 152 | end 153 | 154 | endmodule 155 | -------------------------------------------------------------------------------- /peris/spi_03h_xip/spi_03h_xip.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2021 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // Minimal execute-in-place for SPI NOR flash. Translates each AHB-Lite access 19 | // into a 32-bit 03h serial read command, with 24-bit address, CPHA = 0, CPOL 20 | // = 0. SCK is at half the frequency of clk. 21 | // 22 | // This is pretty slow, but if you slap a cache on top of it 23 | // (ahb_cache_readonly in this repo) you can get acceptable performance. 24 | 25 | `default_nettype none 26 | 27 | module spi_03h_xip #( 28 | parameter W_ADDR = 32, // do not modify 29 | parameter W_DATA = 32 // do not modify 30 | ) ( 31 | // Globals 32 | input wire clk, 33 | input wire rst_n, 34 | 35 | // APB slave for direct SPI access (e.g. flash erase/programming) 36 | input wire apbs_psel, 37 | input wire apbs_penable, 38 | input wire apbs_pwrite, 39 | input wire [15:0] apbs_paddr, 40 | input wire [31:0] apbs_pwdata, 41 | output wire [31:0] apbs_prdata, 42 | output wire apbs_pready, 43 | output wire apbs_pslverr, 44 | 45 | // AHB-Lite slave for XIP access 46 | output wire ahbls_hready_resp, 47 | input wire ahbls_hready, 48 | output wire ahbls_hresp, 49 | input wire [W_ADDR-1:0] ahbls_haddr, 50 | input wire ahbls_hwrite, 51 | input wire [1:0] ahbls_htrans, 52 | input wire [2:0] ahbls_hsize, 53 | input wire [2:0] ahbls_hburst, 54 | input wire [3:0] ahbls_hprot, 55 | input wire ahbls_hmastlock, 56 | input wire [W_DATA-1:0] ahbls_hwdata, 57 | output wire [W_DATA-1:0] ahbls_hrdata, 58 | 59 | // SPI interface 60 | output reg spi_cs_n, 61 | output reg spi_sck, 62 | output wire spi_mosi, 63 | input wire spi_miso 64 | ); 65 | 66 | localparam W_STATE = 2; 67 | localparam S_IDLE = 2'd0; 68 | localparam S_ADDR = 2'd1; 69 | localparam S_DATA = 2'd2; 70 | localparam S_BACKPORCH = 2'd3; 71 | 72 | localparam W_CTR = 5; 73 | 74 | reg [W_CTR-1:0] shift_ctr; 75 | reg [W_DATA-1:0] shift_reg; 76 | reg [W_STATE-1:0] shift_state; 77 | 78 | wire direct_mode; 79 | reg direct_mode_busy; 80 | wire [7:0] txdata_o; 81 | wire txdata_wen; 82 | wire [7:0] rxdata_i = shift_reg[7:0]; 83 | 84 | assign spi_mosi = shift_reg[W_DATA-1]; 85 | 86 | xip_regs regs ( 87 | .clk (clk), 88 | .rst_n (rst_n), 89 | 90 | .apbs_psel (apbs_psel), 91 | .apbs_penable (apbs_penable), 92 | .apbs_pwrite (apbs_pwrite), 93 | .apbs_paddr (apbs_paddr), 94 | .apbs_pwdata (apbs_pwdata), 95 | .apbs_prdata (apbs_prdata), 96 | .apbs_pready (apbs_pready), 97 | .apbs_pslverr (apbs_pslverr), 98 | 99 | .csr_direct_o (direct_mode), 100 | .csr_busy_i (direct_mode_busy), 101 | .txdata_o (txdata_o), 102 | .txdata_wen (txdata_wen), 103 | .rxdata_i (rxdata_i), 104 | .rxdata_ren (/* unused */) 105 | ); 106 | 107 | 108 | always @ (posedge clk or negedge rst_n) begin 109 | if (!rst_n) begin 110 | shift_reg <= {W_DATA{1'b0}}; 111 | shift_ctr <= {W_CTR{1'b0}}; 112 | shift_state <= S_IDLE; 113 | spi_cs_n <= 1'b1; 114 | spi_sck <= 1'b0; 115 | direct_mode_busy <= 1'b0; 116 | end else if (direct_mode) begin 117 | shift_state <= S_IDLE; 118 | spi_cs_n <= 1'b0; 119 | if (txdata_wen) begin 120 | direct_mode_busy <= 1'b1; 121 | shift_reg[W_DATA - 1 -: 8] <= txdata_o; 122 | shift_ctr <= 5'd7; 123 | end else if (direct_mode_busy) begin 124 | if (spi_sck) begin 125 | spi_sck <= 1'b0; 126 | shift_ctr <= shift_ctr - 1'b1; 127 | shift_reg[W_DATA-1:1] <= shift_reg[W_DATA-2:0]; 128 | if (~|shift_ctr) begin 129 | direct_mode_busy <= 1'b0; 130 | end 131 | end else begin 132 | spi_sck <= 1'b1; 133 | shift_reg[0] <= spi_miso; 134 | end 135 | end 136 | end else if (shift_state == S_IDLE) begin 137 | spi_cs_n <= 1'b1; 138 | if (ahbls_hready && ahbls_htrans[1]) begin 139 | shift_reg <= {8'h03, ahbls_haddr[23:2], 2'b00}; 140 | spi_cs_n <= 1'b0; 141 | shift_ctr <= W_DATA - 1; 142 | shift_state <= S_ADDR; 143 | end 144 | end else if (shift_state == S_ADDR) begin 145 | if (spi_sck) begin 146 | spi_sck <= 1'b0; 147 | shift_ctr <= shift_ctr - 1'b1; 148 | shift_reg <= (shift_reg << 1); 149 | if (~|shift_ctr) 150 | shift_state <= S_DATA; 151 | end else begin 152 | spi_sck <= 1'b1; 153 | end 154 | end else if (shift_state == S_DATA) begin 155 | if (spi_sck) begin 156 | spi_sck <= 1'b0; 157 | shift_ctr <= shift_ctr - 1'b1; 158 | if (~|shift_ctr) 159 | shift_state <= S_BACKPORCH; 160 | end else begin 161 | spi_sck <= 1'b1; 162 | shift_reg <= (shift_reg << 1) | spi_miso; 163 | end 164 | end else if (shift_state == S_BACKPORCH) begin 165 | spi_cs_n <= 1'b1; 166 | shift_state <= S_IDLE; 167 | end 168 | end 169 | 170 | assign ahbls_hready_resp = shift_state == S_IDLE; 171 | assign ahbls_hresp = 1'b0; 172 | assign ahbls_hrdata = shift_reg; 173 | 174 | endmodule 175 | -------------------------------------------------------------------------------- /sdram/regs/sdram_ctrl_regs.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * AUTOGENERATED BY REGBLOCK * 3 | * Do not edit manually. * 4 | * Edit the source file (or regblock utility) and regenerate. * 5 | *******************************************************************************/ 6 | 7 | // Block name : sdram 8 | // Bus type : apb 9 | // Bus data width : 32 10 | // Bus address width : 16 11 | 12 | module sdram_regs ( 13 | input wire clk, 14 | input wire rst_n, 15 | 16 | // APB Port 17 | input wire apbs_psel, 18 | input wire apbs_penable, 19 | input wire apbs_pwrite, 20 | input wire [15:0] apbs_paddr, 21 | input wire [31:0] apbs_pwdata, 22 | output wire [31:0] apbs_prdata, 23 | output wire apbs_pready, 24 | output wire apbs_pslverr, 25 | 26 | // Register interfaces 27 | output reg csr_en_o, 28 | output reg csr_pu_o, 29 | output reg [2:0] time_rc_o, 30 | output reg [2:0] time_rcd_o, 31 | output reg [2:0] time_rp_o, 32 | output reg [2:0] time_rrd_o, 33 | output reg [2:0] time_ras_o, 34 | output reg [2:0] time_wr_o, 35 | output reg [1:0] time_cas_o, 36 | output reg [11:0] refresh_o, 37 | output reg cmd_direct_we_n_o, 38 | output reg cmd_direct_we_n_wen, 39 | output reg cmd_direct_cas_n_o, 40 | output reg cmd_direct_cas_n_wen, 41 | output reg cmd_direct_ras_n_o, 42 | output reg cmd_direct_ras_n_wen, 43 | output reg [12:0] cmd_direct_addr_o, 44 | output reg cmd_direct_addr_wen, 45 | output reg [1:0] cmd_direct_ba_o, 46 | output reg cmd_direct_ba_wen 47 | ); 48 | 49 | // APB adapter 50 | wire [31:0] wdata = apbs_pwdata; 51 | reg [31:0] rdata; 52 | wire wen = apbs_psel && apbs_penable && apbs_pwrite; 53 | wire ren = apbs_psel && apbs_penable && !apbs_pwrite; 54 | wire [15:0] addr = apbs_paddr & 16'hc; 55 | assign apbs_prdata = rdata; 56 | assign apbs_pready = 1'b1; 57 | assign apbs_pslverr = 1'b0; 58 | 59 | localparam ADDR_CSR = 0; 60 | localparam ADDR_TIME = 4; 61 | localparam ADDR_REFRESH = 8; 62 | localparam ADDR_CMD_DIRECT = 12; 63 | 64 | wire __csr_wen = wen && addr == ADDR_CSR; 65 | wire __csr_ren = ren && addr == ADDR_CSR; 66 | wire __time_wen = wen && addr == ADDR_TIME; 67 | wire __time_ren = ren && addr == ADDR_TIME; 68 | wire __refresh_wen = wen && addr == ADDR_REFRESH; 69 | wire __refresh_ren = ren && addr == ADDR_REFRESH; 70 | wire __cmd_direct_wen = wen && addr == ADDR_CMD_DIRECT; 71 | wire __cmd_direct_ren = ren && addr == ADDR_CMD_DIRECT; 72 | 73 | wire csr_en_wdata = wdata[0]; 74 | wire csr_en_rdata; 75 | wire csr_pu_wdata = wdata[1]; 76 | wire csr_pu_rdata; 77 | wire [31:0] __csr_rdata = {30'h0, csr_pu_rdata, csr_en_rdata}; 78 | assign csr_en_rdata = csr_en_o; 79 | assign csr_pu_rdata = csr_pu_o; 80 | 81 | wire [2:0] time_rc_wdata = wdata[2:0]; 82 | wire [2:0] time_rc_rdata; 83 | wire [2:0] time_rcd_wdata = wdata[6:4]; 84 | wire [2:0] time_rcd_rdata; 85 | wire [2:0] time_rp_wdata = wdata[10:8]; 86 | wire [2:0] time_rp_rdata; 87 | wire [2:0] time_rrd_wdata = wdata[14:12]; 88 | wire [2:0] time_rrd_rdata; 89 | wire [2:0] time_ras_wdata = wdata[18:16]; 90 | wire [2:0] time_ras_rdata; 91 | wire [2:0] time_wr_wdata = wdata[22:20]; 92 | wire [2:0] time_wr_rdata; 93 | wire [1:0] time_cas_wdata = wdata[25:24]; 94 | wire [1:0] time_cas_rdata; 95 | wire [31:0] __time_rdata = {6'h0, time_cas_rdata, 1'h0, time_wr_rdata, 1'h0, time_ras_rdata, 1'h0, time_rrd_rdata, 1'h0, time_rp_rdata, 1'h0, time_rcd_rdata, 1'h0, time_rc_rdata}; 96 | assign time_rc_rdata = time_rc_o; 97 | assign time_rcd_rdata = time_rcd_o; 98 | assign time_rp_rdata = time_rp_o; 99 | assign time_rrd_rdata = time_rrd_o; 100 | assign time_ras_rdata = time_ras_o; 101 | assign time_wr_rdata = time_wr_o; 102 | assign time_cas_rdata = time_cas_o; 103 | 104 | wire [11:0] refresh_wdata = wdata[11:0]; 105 | wire [11:0] refresh_rdata; 106 | wire [31:0] __refresh_rdata = {20'h0, refresh_rdata}; 107 | assign refresh_rdata = refresh_o; 108 | 109 | wire cmd_direct_we_n_wdata = wdata[0]; 110 | wire cmd_direct_we_n_rdata; 111 | wire cmd_direct_cas_n_wdata = wdata[1]; 112 | wire cmd_direct_cas_n_rdata; 113 | wire cmd_direct_ras_n_wdata = wdata[2]; 114 | wire cmd_direct_ras_n_rdata; 115 | wire [12:0] cmd_direct_addr_wdata = wdata[15:3]; 116 | wire [12:0] cmd_direct_addr_rdata; 117 | wire [1:0] cmd_direct_ba_wdata = wdata[29:28]; 118 | wire [1:0] cmd_direct_ba_rdata; 119 | wire [31:0] __cmd_direct_rdata = {2'h0, cmd_direct_ba_rdata, 12'h0, cmd_direct_addr_rdata, cmd_direct_ras_n_rdata, cmd_direct_cas_n_rdata, cmd_direct_we_n_rdata}; 120 | assign cmd_direct_we_n_rdata = 1'h0; 121 | assign cmd_direct_cas_n_rdata = 1'h0; 122 | assign cmd_direct_ras_n_rdata = 1'h0; 123 | assign cmd_direct_addr_rdata = 13'h0; 124 | assign cmd_direct_ba_rdata = 2'h0; 125 | 126 | always @ (*) begin 127 | case (addr) 128 | ADDR_CSR: rdata = __csr_rdata; 129 | ADDR_TIME: rdata = __time_rdata; 130 | ADDR_REFRESH: rdata = __refresh_rdata; 131 | ADDR_CMD_DIRECT: rdata = __cmd_direct_rdata; 132 | default: rdata = 32'h0; 133 | endcase 134 | cmd_direct_we_n_wen = __cmd_direct_wen; 135 | cmd_direct_we_n_o = cmd_direct_we_n_wdata; 136 | cmd_direct_cas_n_wen = __cmd_direct_wen; 137 | cmd_direct_cas_n_o = cmd_direct_cas_n_wdata; 138 | cmd_direct_ras_n_wen = __cmd_direct_wen; 139 | cmd_direct_ras_n_o = cmd_direct_ras_n_wdata; 140 | cmd_direct_addr_wen = __cmd_direct_wen; 141 | cmd_direct_addr_o = cmd_direct_addr_wdata; 142 | cmd_direct_ba_wen = __cmd_direct_wen; 143 | cmd_direct_ba_o = cmd_direct_ba_wdata; 144 | end 145 | 146 | always @ (posedge clk or negedge rst_n) begin 147 | if (!rst_n) begin 148 | csr_en_o <= 1'h0; 149 | csr_pu_o <= 1'h0; 150 | time_rc_o <= 3'h0; 151 | time_rcd_o <= 3'h0; 152 | time_rp_o <= 3'h0; 153 | time_rrd_o <= 3'h0; 154 | time_ras_o <= 3'h0; 155 | time_wr_o <= 3'h0; 156 | time_cas_o <= 2'h0; 157 | refresh_o <= 12'h0; 158 | end else begin 159 | if (__csr_wen) 160 | csr_en_o <= csr_en_wdata; 161 | if (__csr_wen) 162 | csr_pu_o <= csr_pu_wdata; 163 | if (__time_wen) 164 | time_rc_o <= time_rc_wdata; 165 | if (__time_wen) 166 | time_rcd_o <= time_rcd_wdata; 167 | if (__time_wen) 168 | time_rp_o <= time_rp_wdata; 169 | if (__time_wen) 170 | time_rrd_o <= time_rrd_wdata; 171 | if (__time_wen) 172 | time_ras_o <= time_ras_wdata; 173 | if (__time_wen) 174 | time_wr_o <= time_wr_wdata; 175 | if (__time_wen) 176 | time_cas_o <= time_cas_wdata; 177 | if (__refresh_wen) 178 | refresh_o <= refresh_wdata; 179 | end 180 | end 181 | 182 | endmodule 183 | -------------------------------------------------------------------------------- /busfabric/ahbl_splitter.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2018 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | /* 18 | * AHB-lite 1:N splitter 19 | * If this splitter is at the top of the busfabric (i.e. its master is a true master), 20 | * tie src_hready_resp across to src_hready. 21 | * 22 | * It is up to the system implementer to *ensure that the address mapped ranges 23 | * are mutually exclusive*. 24 | */ 25 | 26 | // TODO: burst support 27 | 28 | `default_nettype none 29 | 30 | module ahbl_splitter #( 31 | parameter N_PORTS = 2, 32 | parameter W_ADDR = 32, 33 | parameter W_DATA = 32, 34 | parameter ADDR_MAP = 64'h20000000_00000000, 35 | parameter ADDR_MASK = 64'hf0000000_f0000000, 36 | parameter IGNORE_BUS_ERRORS = 0, 37 | parameter CONN_MASK = {N_PORTS{1'b1}} 38 | ) ( 39 | // Global signals 40 | input wire clk, 41 | input wire rst_n, 42 | 43 | // From master; functions as slave port 44 | input wire src_hready, 45 | output wire src_hready_resp, 46 | output wire src_hresp, 47 | output wire src_hexokay, 48 | input wire [W_ADDR-1:0] src_haddr, 49 | input wire src_hwrite, 50 | input wire [1:0] src_htrans, 51 | input wire [2:0] src_hsize, 52 | input wire [2:0] src_hburst, 53 | input wire [3:0] src_hprot, 54 | input wire [7:0] src_hmaster, 55 | input wire src_hmastlock, 56 | input wire src_hexcl, 57 | input wire [W_DATA-1:0] src_hwdata, 58 | output wire [W_DATA-1:0] src_hrdata, 59 | 60 | // To slaves; function as master ports 61 | output wire [N_PORTS-1:0] dst_hready, 62 | input wire [N_PORTS-1:0] dst_hready_resp, 63 | input wire [N_PORTS-1:0] dst_hresp, 64 | input wire [N_PORTS-1:0] dst_hexokay, 65 | output wire [N_PORTS*W_ADDR-1:0] dst_haddr, 66 | output wire [N_PORTS-1:0] dst_hwrite, 67 | output reg [N_PORTS*2-1:0] dst_htrans, 68 | output wire [N_PORTS*3-1:0] dst_hsize, 69 | output wire [N_PORTS*3-1:0] dst_hburst, 70 | output wire [N_PORTS*4-1:0] dst_hprot, 71 | output wire [N_PORTS*8-1:0] dst_hmaster, 72 | output wire [N_PORTS-1:0] dst_hmastlock, 73 | output wire [N_PORTS-1:0] dst_hexcl, 74 | output wire [N_PORTS*W_DATA-1:0] dst_hwdata, 75 | input wire [N_PORTS*W_DATA-1:0] dst_hrdata 76 | ); 77 | 78 | localparam HTRANS_IDLE = 2'b00; 79 | 80 | 81 | // Address decode 82 | 83 | reg [N_PORTS-1:0] slave_sel_a_nomask; 84 | reg [N_PORTS-1:0] slave_sel_a; 85 | reg decode_err_a; 86 | 87 | always @ (*) begin: decode 88 | integer i; 89 | if (src_htrans == HTRANS_IDLE) begin 90 | i = 0; // prevent spurious latch inference warning from yosys 91 | slave_sel_a_nomask = {N_PORTS{1'b0}}; 92 | slave_sel_a = {N_PORTS{1'b0}}; 93 | decode_err_a = 1'b0; 94 | end else begin 95 | for (i = 0; i < N_PORTS; i = i + 1) begin 96 | slave_sel_a_nomask[i] = ~|((src_haddr ^ ADDR_MAP[i * W_ADDR +: W_ADDR]) 97 | & ADDR_MASK[i * W_ADDR +: W_ADDR]); 98 | end 99 | slave_sel_a = slave_sel_a_nomask & CONN_MASK; 100 | decode_err_a = ~|slave_sel_a_nomask; 101 | end 102 | end 103 | 104 | // Address-phase passthrough 105 | // Be lazy and don't blank out signals to non-selected slaves, 106 | // except for HTRANS, which must be gated off to stop spurious transfer. 107 | // Costs transitions, but saves gates. 108 | 109 | assign dst_haddr = {N_PORTS{src_haddr}}; 110 | assign dst_hwrite = {N_PORTS{src_hwrite}}; 111 | assign dst_hsize = {N_PORTS{src_hsize}}; 112 | assign dst_hburst = {N_PORTS{src_hburst}}; 113 | assign dst_hprot = {N_PORTS{src_hprot}}; 114 | assign dst_hmaster = {N_PORTS{src_hmaster}}; 115 | assign dst_hmastlock = {N_PORTS{src_hmastlock}}; 116 | assign dst_hexcl = {N_PORTS{src_hexcl}}; 117 | 118 | always @ (*) begin: mask_htrans 119 | integer i; 120 | for (i = 0; i < N_PORTS; i = i + 1) begin 121 | dst_htrans[i * 2 +: 2] = slave_sel_a[i] ? src_htrans : HTRANS_IDLE; 122 | end 123 | end 124 | 125 | // AHB state machine 126 | 127 | reg [N_PORTS-1:0] slave_sel_d; 128 | reg decode_err_d; 129 | reg err_ph1; 130 | 131 | always @ (posedge clk or negedge rst_n) begin 132 | if (!rst_n) begin 133 | slave_sel_d <= {N_PORTS{1'b0}}; 134 | decode_err_d <= 1'b0; 135 | err_ph1 <= 1'b0; 136 | end else begin 137 | if (src_hready) begin 138 | slave_sel_d <= slave_sel_a; 139 | decode_err_d <= decode_err_a; 140 | end 141 | if (decode_err_d) begin 142 | err_ph1 <= !err_ph1; 143 | end else begin 144 | err_ph1 <= 1'b0; 145 | end 146 | end 147 | end 148 | 149 | // Data-phase passthrough 150 | 151 | assign dst_hwdata = {N_PORTS{src_hwdata}}; 152 | assign dst_hready = {N_PORTS{src_hready}}; 153 | 154 | onehot_mux #( 155 | .N_INPUTS(N_PORTS), 156 | .W_INPUT(W_DATA) 157 | ) hrdata_mux ( 158 | .in(dst_hrdata), 159 | .sel(slave_sel_d), 160 | .out(src_hrdata) 161 | ); 162 | 163 | // We want to avoid any combinatorial paths from htrans->hready 164 | // both for timing closure reasons, and to avoid loops with poorly 165 | // behaved masters. 166 | // One rule to avoid this is to *only use data-phase state for muxing* 167 | 168 | assign src_hready_resp = (~|slave_sel_d && (IGNORE_BUS_ERRORS || err_ph1 || !decode_err_d)) || 169 | |(slave_sel_d & dst_hready_resp); 170 | 171 | assign src_hresp = !IGNORE_BUS_ERRORS && (decode_err_d || |(slave_sel_d & dst_hresp)); 172 | 173 | assign src_hexokay = |(slave_sel_d & dst_hexokay); 174 | 175 | endmodule 176 | -------------------------------------------------------------------------------- /peris/spi/spi_regs.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * AUTOGENERATED BY REGBLOCK * 3 | * Do not edit manually. * 4 | * Edit the source file (or regblock utility) and regenerate. * 5 | *******************************************************************************/ 6 | 7 | // Block name : spi 8 | // Bus type : apb 9 | // Bus data width : 32 10 | // Bus address width : 16 11 | 12 | module spi_regs ( 13 | input wire clk, 14 | input wire rst_n, 15 | 16 | // APB Port 17 | input wire apbs_psel, 18 | input wire apbs_penable, 19 | input wire apbs_pwrite, 20 | input wire [15:0] apbs_paddr, 21 | input wire [31:0] apbs_pwdata, 22 | output wire [31:0] apbs_prdata, 23 | output wire apbs_pready, 24 | output wire apbs_pslverr, 25 | 26 | // Register interfaces 27 | output reg csr_csauto_o, 28 | output reg csr_cs_o, 29 | output reg csr_loopback_o, 30 | output reg csr_read_en_o, 31 | output reg csr_cpol_o, 32 | output reg csr_cpha_o, 33 | input wire csr_busy_i, 34 | output reg [5:0] div_o, 35 | input wire [7:0] fstat_txlevel_i, 36 | input wire fstat_txfull_i, 37 | input wire fstat_txempty_i, 38 | input wire fstat_txover_i, 39 | input wire [7:0] fstat_rxlevel_i, 40 | input wire fstat_rxfull_i, 41 | input wire fstat_rxempty_i, 42 | input wire fstat_rxover_i, 43 | input wire fstat_rxunder_i, 44 | output reg [7:0] tx_o, 45 | output reg tx_wen, 46 | input wire [7:0] rx_i, 47 | output reg rx_ren 48 | ); 49 | 50 | // APB adapter 51 | wire [31:0] wdata = apbs_pwdata; 52 | reg [31:0] rdata; 53 | wire wen = apbs_psel && apbs_penable && apbs_pwrite; 54 | wire ren = apbs_psel && apbs_penable && !apbs_pwrite; 55 | wire [15:0] addr = apbs_paddr & 16'h1c; 56 | assign apbs_prdata = rdata; 57 | assign apbs_pready = 1'b1; 58 | assign apbs_pslverr = 1'b0; 59 | 60 | localparam ADDR_CSR = 0; 61 | localparam ADDR_DIV = 4; 62 | localparam ADDR_FSTAT = 8; 63 | localparam ADDR_TX = 12; 64 | localparam ADDR_RX = 16; 65 | 66 | wire __csr_wen = wen && addr == ADDR_CSR; 67 | wire __csr_ren = ren && addr == ADDR_CSR; 68 | wire __div_wen = wen && addr == ADDR_DIV; 69 | wire __div_ren = ren && addr == ADDR_DIV; 70 | wire __fstat_wen = wen && addr == ADDR_FSTAT; 71 | wire __fstat_ren = ren && addr == ADDR_FSTAT; 72 | wire __tx_wen = wen && addr == ADDR_TX; 73 | wire __tx_ren = ren && addr == ADDR_TX; 74 | wire __rx_wen = wen && addr == ADDR_RX; 75 | wire __rx_ren = ren && addr == ADDR_RX; 76 | 77 | wire csr_csauto_wdata = wdata[9]; 78 | wire csr_csauto_rdata; 79 | wire csr_cs_wdata = wdata[8]; 80 | wire csr_cs_rdata; 81 | wire csr_loopback_wdata = wdata[5]; 82 | wire csr_loopback_rdata; 83 | wire csr_read_en_wdata = wdata[4]; 84 | wire csr_read_en_rdata; 85 | wire csr_cpol_wdata = wdata[3]; 86 | wire csr_cpol_rdata; 87 | wire csr_cpha_wdata = wdata[2]; 88 | wire csr_cpha_rdata; 89 | wire csr_busy_wdata = wdata[0]; 90 | wire csr_busy_rdata; 91 | wire [31:0] __csr_rdata = {22'h0, csr_csauto_rdata, csr_cs_rdata, 2'h0, csr_loopback_rdata, csr_read_en_rdata, csr_cpol_rdata, csr_cpha_rdata, 1'h0, csr_busy_rdata}; 92 | assign csr_csauto_rdata = csr_csauto_o; 93 | assign csr_cs_rdata = csr_cs_o; 94 | assign csr_loopback_rdata = csr_loopback_o; 95 | assign csr_read_en_rdata = csr_read_en_o; 96 | assign csr_cpol_rdata = csr_cpol_o; 97 | assign csr_cpha_rdata = csr_cpha_o; 98 | assign csr_busy_rdata = csr_busy_i; 99 | 100 | wire [5:0] div_wdata = wdata[5:0]; 101 | wire [5:0] div_rdata; 102 | wire [31:0] __div_rdata = {26'h0, div_rdata}; 103 | assign div_rdata = div_o; 104 | 105 | wire [7:0] fstat_txlevel_wdata = wdata[7:0]; 106 | wire [7:0] fstat_txlevel_rdata; 107 | wire fstat_txfull_wdata = wdata[8]; 108 | wire fstat_txfull_rdata; 109 | wire fstat_txempty_wdata = wdata[9]; 110 | wire fstat_txempty_rdata; 111 | wire fstat_txover_wdata = wdata[10]; 112 | wire fstat_txover_rdata; 113 | wire [7:0] fstat_rxlevel_wdata = wdata[23:16]; 114 | wire [7:0] fstat_rxlevel_rdata; 115 | wire fstat_rxfull_wdata = wdata[24]; 116 | wire fstat_rxfull_rdata; 117 | wire fstat_rxempty_wdata = wdata[25]; 118 | wire fstat_rxempty_rdata; 119 | wire fstat_rxover_wdata = wdata[26]; 120 | wire fstat_rxover_rdata; 121 | wire fstat_rxunder_wdata = wdata[27]; 122 | wire fstat_rxunder_rdata; 123 | wire [31:0] __fstat_rdata = {4'h0, fstat_rxunder_rdata, fstat_rxover_rdata, fstat_rxempty_rdata, fstat_rxfull_rdata, fstat_rxlevel_rdata, 5'h0, fstat_txover_rdata, fstat_txempty_rdata, fstat_txfull_rdata, fstat_txlevel_rdata}; 124 | assign fstat_txlevel_rdata = fstat_txlevel_i; 125 | assign fstat_txfull_rdata = fstat_txfull_i; 126 | assign fstat_txempty_rdata = fstat_txempty_i; 127 | reg fstat_txover; 128 | assign fstat_txover_rdata = fstat_txover; 129 | assign fstat_rxlevel_rdata = fstat_rxlevel_i; 130 | assign fstat_rxfull_rdata = fstat_rxfull_i; 131 | assign fstat_rxempty_rdata = fstat_rxempty_i; 132 | reg fstat_rxover; 133 | assign fstat_rxover_rdata = fstat_rxover; 134 | reg fstat_rxunder; 135 | assign fstat_rxunder_rdata = fstat_rxunder; 136 | 137 | wire [7:0] tx_wdata = wdata[7:0]; 138 | wire [7:0] tx_rdata; 139 | wire [31:0] __tx_rdata = {24'h0, tx_rdata}; 140 | assign tx_rdata = 8'h0; 141 | 142 | wire [7:0] rx_wdata = wdata[7:0]; 143 | wire [7:0] rx_rdata; 144 | wire [31:0] __rx_rdata = {24'h0, rx_rdata}; 145 | assign rx_rdata = rx_i; 146 | 147 | always @ (*) begin 148 | case (addr) 149 | ADDR_CSR: rdata = __csr_rdata; 150 | ADDR_DIV: rdata = __div_rdata; 151 | ADDR_FSTAT: rdata = __fstat_rdata; 152 | ADDR_TX: rdata = __tx_rdata; 153 | ADDR_RX: rdata = __rx_rdata; 154 | default: rdata = 32'h0; 155 | endcase 156 | tx_wen = __tx_wen; 157 | tx_o = tx_wdata; 158 | rx_ren = __rx_ren; 159 | end 160 | 161 | always @ (posedge clk or negedge rst_n) begin 162 | if (!rst_n) begin 163 | csr_csauto_o <= 1'h1; 164 | csr_cs_o <= 1'h0; 165 | csr_loopback_o <= 1'h0; 166 | csr_read_en_o <= 1'h1; 167 | csr_cpol_o <= 1'h0; 168 | csr_cpha_o <= 1'h0; 169 | div_o <= 6'h1; 170 | fstat_txover <= 1'h0; 171 | fstat_rxover <= 1'h0; 172 | fstat_rxunder <= 1'h0; 173 | end else begin 174 | if (__csr_wen) 175 | csr_csauto_o <= csr_csauto_wdata; 176 | if (__csr_wen) 177 | csr_cs_o <= csr_cs_wdata; 178 | if (__csr_wen) 179 | csr_loopback_o <= csr_loopback_wdata; 180 | if (__csr_wen) 181 | csr_read_en_o <= csr_read_en_wdata; 182 | if (__csr_wen) 183 | csr_cpol_o <= csr_cpol_wdata; 184 | if (__csr_wen) 185 | csr_cpha_o <= csr_cpha_wdata; 186 | if (__div_wen) 187 | div_o <= div_wdata; 188 | fstat_txover <= (fstat_txover && !(__fstat_wen && fstat_txover_wdata)) || fstat_txover_i; 189 | fstat_rxover <= (fstat_rxover && !(__fstat_wen && fstat_rxover_wdata)) || fstat_rxover_i; 190 | fstat_rxunder <= (fstat_rxunder && !(__fstat_wen && fstat_rxunder_wdata)) || fstat_rxunder_i; 191 | end 192 | end 193 | 194 | endmodule 195 | -------------------------------------------------------------------------------- /peris/spi/spi_mini.v: -------------------------------------------------------------------------------- 1 | module spi_mini #( 2 | parameter FIFO_DEPTH = 2 3 | ) ( 4 | input wire clk, 5 | input wire rst_n, 6 | 7 | input wire apbs_psel, 8 | input wire apbs_penable, 9 | input wire apbs_pwrite, 10 | input wire [15:0] apbs_paddr, 11 | input wire [31:0] apbs_pwdata, 12 | output wire [31:0] apbs_prdata, 13 | output wire apbs_pready, 14 | output wire apbs_pslverr, 15 | 16 | output reg sclk, 17 | output reg sdo, 18 | input wire sdi, 19 | output reg cs_n 20 | ); 21 | 22 | parameter W_FLEVEL = $clog2(FIFO_DEPTH + 1); 23 | localparam W_DIV_INT = 6; 24 | localparam W_DATA = 8; 25 | 26 | wire rst_n_sync; 27 | 28 | reset_sync #( 29 | .N_CYCLES (2) 30 | ) inst_reset_sync ( 31 | .clk (clk), 32 | .rst_n_in (rst_n), 33 | .rst_n_out (rst_n_sync) 34 | ); 35 | 36 | // ----------------------------------------------------------------------------- 37 | // Interconnects 38 | // ----------------------------------------------------------------------------- 39 | 40 | reg clk_en; 41 | 42 | wire csr_csauto; 43 | wire csr_cs; 44 | wire csr_loopback; 45 | wire csr_read_en; 46 | wire csr_cpol; 47 | wire csr_cpha; 48 | wire csr_busy; 49 | wire [W_DIV_INT-1:0] div; 50 | 51 | wire [W_DATA-1:0] txfifo_wdata; 52 | wire txfifo_wen; 53 | wire [W_DATA-1:0] txfifo_rdata; 54 | wire txfifo_ren; 55 | wire txfifo_full; 56 | wire txfifo_empty; 57 | wire [W_FLEVEL-1:0] txfifo_level; 58 | 59 | reg rxfifo_wen; 60 | wire [W_DATA-1:0] rxfifo_rdata; 61 | wire rxfifo_ren; 62 | wire rxfifo_full; 63 | wire rxfifo_empty; 64 | wire [W_FLEVEL-1:0] rxfifo_level; 65 | 66 | 67 | // ----------------------------------------------------------------------------- 68 | // SPI state machine 69 | // ----------------------------------------------------------------------------- 70 | 71 | localparam W_STATE = 4; 72 | localparam S_IDLE = 4'h0; 73 | localparam S_DATA_FIRST = 4'h1; 74 | // ... 75 | localparam S_DATA_LAST = 4'h8; 76 | localparam S_BACKPORCH = 4'h9; // Space between last SCLK pulse and CS deassertion 77 | 78 | reg [W_DATA-1:0] tx_shift; 79 | reg [W_DATA-1:0] rx_shift; 80 | reg cs_r; 81 | reg sclk_r; 82 | wire shift_in = csr_loopback ? sdo : sdi; 83 | 84 | reg [W_STATE-1:0] state; 85 | 86 | always @ (posedge clk or negedge rst_n_sync) begin 87 | if (!rst_n_sync) begin 88 | cs_r <= 1'b1; 89 | sclk_r <= 1'b0; 90 | sdo <= 1'b0; 91 | rxfifo_wen <= 1'b0; 92 | tx_shift <= {W_DATA{1'b0}}; 93 | rx_shift <= {W_DATA{1'b0}}; 94 | state <= S_IDLE; 95 | end else if (clk_en) begin 96 | rxfifo_wen <= 1'b0; 97 | case (state) 98 | S_IDLE: begin 99 | if (!txfifo_empty) begin 100 | state <= S_DATA_FIRST; 101 | cs_r <= 1'b0; 102 | tx_shift <= txfifo_rdata; 103 | if (!csr_cpha) 104 | sdo <= txfifo_rdata[W_DATA-1]; 105 | end 106 | end 107 | S_DATA_LAST: begin 108 | sclk_r <= !sclk_r; 109 | if (sclk_r) begin 110 | if (txfifo_empty) begin 111 | state <= S_BACKPORCH; 112 | end else begin 113 | state <= S_DATA_FIRST; 114 | tx_shift <= txfifo_rdata; 115 | if (!csr_cpha) 116 | sdo <= txfifo_rdata[W_DATA-1]; 117 | end 118 | rxfifo_wen <= csr_read_en; 119 | end 120 | if (csr_cpha) begin 121 | if (!sclk_r) 122 | sdo <= tx_shift[W_DATA-1]; 123 | end 124 | if (csr_cpha == sclk_r) 125 | rx_shift <= {rx_shift[W_DATA-2:0], shift_in}; 126 | end 127 | S_BACKPORCH: begin 128 | state <= S_IDLE; 129 | cs_r <= 1'b1; 130 | sdo <= 1'b0; 131 | end 132 | default: begin // Data states (except last) 133 | sclk_r <= !sclk_r; 134 | if (sclk_r) begin 135 | state <= state + 1'b1; 136 | tx_shift <= tx_shift << 1; 137 | end 138 | if (csr_cpha == sclk_r) 139 | rx_shift <= {rx_shift[W_DATA-2:0], shift_in}; 140 | else 141 | sdo <= csr_cpha ? tx_shift[W_DATA-1] : tx_shift[W_DATA-2]; 142 | end 143 | endcase 144 | end else begin 145 | rxfifo_wen <= 1'b0; 146 | end 147 | end 148 | 149 | assign csr_busy = state != S_IDLE; 150 | assign txfifo_ren = clk_en && !txfifo_empty && (state == S_IDLE || (state == S_DATA_LAST && sclk_r)); 151 | 152 | always @ (*) 153 | if (csr_csauto) 154 | cs_n = cs_r; 155 | else 156 | cs_n = csr_cs; 157 | 158 | always @ (*) 159 | sclk = sclk_r ^ csr_cpol; 160 | 161 | // ----------------------------------------------------------------------------- 162 | // FIFOs, clock divider and register block 163 | // ----------------------------------------------------------------------------- 164 | 165 | reg [W_DIV_INT-1:0] clkdiv_ctr; 166 | 167 | always @ (posedge clk or negedge rst_n_sync) begin 168 | if (!rst_n_sync) begin 169 | clk_en <= 1'b0; 170 | clkdiv_ctr <= {{W_DIV_INT-1{1'b0}}, 1'b1}; 171 | end else begin 172 | if (clkdiv_ctr == 1'b1) begin 173 | clk_en <= 1'b1; 174 | clkdiv_ctr <= div; 175 | end else begin 176 | clk_en <= 1'b0; 177 | clkdiv_ctr <= clkdiv_ctr - 1'b1; 178 | end 179 | end 180 | end 181 | 182 | sync_fifo #( 183 | .DEPTH(FIFO_DEPTH), 184 | .WIDTH(8) 185 | ) txfifo ( 186 | .clk (clk), 187 | .rst_n (rst_n_sync), 188 | .wdata (txfifo_wdata), 189 | .wen (txfifo_wen), 190 | .rdata (txfifo_rdata), 191 | .ren (txfifo_ren), 192 | .flush (1'b0), 193 | .full (txfifo_full), 194 | .empty (txfifo_empty), 195 | .level (txfifo_level) 196 | ); 197 | 198 | sync_fifo #( 199 | .DEPTH(FIFO_DEPTH), 200 | .WIDTH(8) 201 | ) rxfifo ( 202 | .clk (clk), 203 | .rst_n (rst_n_sync), 204 | .wdata (rx_shift), 205 | .wen (rxfifo_wen), 206 | .rdata (rxfifo_rdata), 207 | .ren (rxfifo_ren), 208 | .flush (1'b0), 209 | .full (rxfifo_full), 210 | .empty (rxfifo_empty), 211 | .level (rxfifo_level) 212 | ); 213 | 214 | spi_regs regs 215 | ( 216 | .clk (clk), 217 | .rst_n (rst_n_sync), 218 | 219 | .apbs_psel (apbs_psel), 220 | .apbs_penable (apbs_penable), 221 | .apbs_pwrite (apbs_pwrite), 222 | .apbs_paddr (apbs_paddr), 223 | .apbs_pwdata (apbs_pwdata), 224 | .apbs_prdata (apbs_prdata), 225 | .apbs_pready (apbs_pready), 226 | .apbs_pslverr (apbs_pslverr), 227 | 228 | .csr_csauto_o (csr_csauto), 229 | .csr_cs_o (csr_cs), 230 | .csr_loopback_o (csr_loopback), 231 | .csr_read_en_o (csr_read_en), 232 | .csr_cpol_o (csr_cpol), 233 | .csr_cpha_o (csr_cpha), 234 | .csr_busy_i (csr_busy), 235 | .div_o (div), 236 | .fstat_txlevel_i (txfifo_level | 8'h0), 237 | .fstat_txfull_i (txfifo_full), 238 | .fstat_txempty_i (txfifo_empty), 239 | .fstat_txover_i (txfifo_full && txfifo_wen), 240 | .fstat_rxlevel_i (rxfifo_level | 8'h0), 241 | .fstat_rxfull_i (rxfifo_full), 242 | .fstat_rxempty_i (rxfifo_empty), 243 | .fstat_rxover_i (rxfifo_full && rxfifo_wen), 244 | .fstat_rxunder_i (rxfifo_empty && rxfifo_ren), 245 | .tx_o (txfifo_wdata), 246 | .tx_wen (txfifo_wen), 247 | .rx_i (rxfifo_rdata), 248 | .rx_ren (rxfifo_ren) 249 | ); 250 | 251 | endmodule 252 | -------------------------------------------------------------------------------- /mem/cache_mem_directmapped.v: -------------------------------------------------------------------------------- 1 | /********************************************************************** 2 | * DO WHAT THE FUCK YOU WANT TO AND DON'T BLAME US PUBLIC LICENSE * 3 | * Version 3, April 2008 * 4 | * * 5 | * Copyright (C) 2021 Luke Wren * 6 | * * 7 | * Everyone is permitted to copy and distribute verbatim or modified * 8 | * copies of this license document and accompanying software, and * 9 | * changing either is allowed. * 10 | * * 11 | * TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION * 12 | * * 13 | * 0. You just DO WHAT THE FUCK YOU WANT TO. * 14 | * 1. We're NOT RESPONSIBLE WHEN IT DOESN'T FUCKING WORK. * 15 | * * 16 | *********************************************************************/ 17 | 18 | // This is just the memory component of a cache -- it's not useable without an 19 | // external cache control state machine and bus interfaces. This cache 20 | // captures the address input directly into the tag and data memories, and 21 | // provides both hit status and read data on the next cycle, so is suitable 22 | // for use on AHB-Lite with 0-wait-state read hits. 23 | // 24 | // The cache line size, W_LINE, must be a power of two multiple of W_DATA 25 | // (including 1 * W_DATA). For example, if: 26 | // 27 | // W_ADDR = 32 28 | // W_DATA = 32 29 | // W_LINE = 128 30 | // DEPTH = 256 31 | // 32 | // This will implement a 4 kilobyte cache (256 lines of 128 bits), with a 256 33 | // deep by 21 wide tag memory (20 tag bits plus one valid bit), and a 1024 34 | // deep by 32 wide data memory. The cache controller would fill cache lines 35 | // with four consecutive word writes, which may come from a single downstream 36 | // data burst. 37 | 38 | module cache_mem_directmapped #( 39 | parameter W_ADDR = 32, // Address bus width 40 | parameter W_DATA = 32, // Data bus width, data memory port width 41 | parameter W_LINE = W_DATA, // Amount of data associated with one tag 42 | parameter DEPTH = 256, // Capacity in bits = W_LINE * DEPTH 43 | parameter TRACK_DIRTY = 0, // 1 if used in a writeback cache, 44 | // 0 for write-thru or read-only 45 | parameter TMEM_PRELOAD = "", // Tag memory hex preload file 46 | parameter DMEM_PRELOAD = "", // Data memory hex preload file 47 | 48 | parameter W_OFFS = $clog2(W_LINE / 8), // do not modify 49 | parameter W_INDEX = $clog2(DEPTH), // do not modify 50 | parameter W_INDEX_EXTRA = $clog2(W_LINE / W_DATA) // do not modify 51 | ) ( 52 | input wire clk, 53 | input wire rst_n, 54 | 55 | // Tag memory access (note any write must follow a matching read) 56 | input wire [W_ADDR-1:0] t_addr, 57 | input wire t_ren, 58 | input wire t_wen, 59 | input wire t_wvalid, 60 | input wire t_wdirty, 61 | 62 | // Line status, valid following assertion of t_ren 63 | output wire hit, 64 | output wire dirty, 65 | output wire [W_ADDR-1:0] dirty_addr, 66 | 67 | // Data memory access 68 | input wire [W_ADDR-1:0] d_addr, 69 | input wire d_ren, 70 | input wire [W_DATA/8-1:0] d_wen, 71 | input wire [W_DATA-1:0] wdata, 72 | output wire [W_DATA-1:0] rdata 73 | ); 74 | 75 | localparam W_TAG = W_ADDR - W_INDEX - W_OFFS; 76 | localparam W_TMEM = W_TAG + 1 + TRACK_DIRTY; 77 | 78 | wire [W_TAG-1:0] t_addr_tag; 79 | wire [W_INDEX-1:0] t_addr_index; 80 | wire [W_OFFS-1:0] t_addr_offs; 81 | 82 | wire [W_TAG-1:0] d_addr_tag; 83 | wire [W_INDEX+W_INDEX_EXTRA-1:0] d_addr_index; 84 | wire [W_OFFS-W_INDEX_EXTRA-1:0] d_addr_offs; 85 | 86 | assign {t_addr_tag, t_addr_index, t_addr_offs} = t_addr; 87 | assign {d_addr_tag, d_addr_index, d_addr_offs} = d_addr; 88 | 89 | // ---------------------------------------------------------------------------- 90 | // Tag memory update 91 | 92 | wire [W_TMEM-1:0] tmem_rdata; 93 | wire [W_TMEM-1:0] tmem_wdata; 94 | wire tmem_wen = t_wen; 95 | 96 | wire [W_TAG-1:0] tmem_rdata_tag = tmem_rdata[W_TAG-1:0]; 97 | wire tmem_rdata_valid = tmem_rdata[W_TAG]; 98 | wire tmem_rdata_dirty; 99 | 100 | assign tmem_wdata[W_TAG:0] = {t_wvalid, t_addr_tag}; 101 | 102 | generate 103 | if (TRACK_DIRTY) begin: tmem_has_dirty 104 | assign tmem_rdata_dirty = tmem_rdata[W_TAG + 1]; 105 | assign tmem_wdata[W_TAG + 1] = t_wdirty; 106 | end else begin: tmem_has_no_dirty 107 | assign tmem_rdata_dirty = 1'b0; 108 | end 109 | endgenerate 110 | 111 | // ---------------------------------------------------------------------------- 112 | // Status signals 113 | 114 | reg [W_TAG-1:0] t_addr_tag_prev; 115 | always @ (posedge clk or negedge rst_n) begin 116 | if (!rst_n) begin 117 | t_addr_tag_prev <= {W_TAG{1'b0}}; 118 | end else if (t_ren) begin 119 | t_addr_tag_prev <= t_addr_tag; 120 | end 121 | end 122 | 123 | assign hit = tmem_rdata_valid && tmem_rdata_tag == t_addr_tag_prev; 124 | assign dirty = tmem_rdata_valid && tmem_rdata_dirty; 125 | 126 | generate 127 | if (TRACK_DIRTY) begin: gen_dirty_addr 128 | reg [W_INDEX-1:0] addr_index_prev; 129 | always @ (posedge clk or negedge rst_n) begin 130 | if (!rst_n) begin 131 | addr_index_prev <= {W_INDEX{1'b0}}; 132 | end else if (t_ren) begin 133 | addr_index_prev <= t_addr_index; 134 | end 135 | end 136 | assign dirty_addr = {tmem_rdata_tag, addr_index_prev, {W_OFFS{1'b0}}}; 137 | end else begin: no_dirty_addr 138 | assign dirty_addr = {W_ADDR{1'b0}}; 139 | end 140 | endgenerate 141 | 142 | // ---------------------------------------------------------------------------- 143 | // Cache memories 144 | 145 | // Important assumption is that rdata remains constant when ren is not asserted 146 | 147 | sram_sync #( 148 | .WIDTH (W_DATA), 149 | .DEPTH (DEPTH * W_LINE / W_DATA), 150 | .PRELOAD_FILE (DMEM_PRELOAD), 151 | .BYTE_ENABLE (1) 152 | ) dmem ( 153 | .clk (clk), 154 | .wen (d_wen), 155 | .ren (d_ren), 156 | .addr (d_addr_index), 157 | .wdata (wdata), 158 | .rdata (rdata) 159 | ); 160 | 161 | sram_sync #( 162 | .WIDTH (W_TMEM), 163 | .DEPTH (DEPTH), 164 | .PRELOAD_FILE (TMEM_PRELOAD), 165 | .BYTE_ENABLE (0) // would be nice to have a bit-enable, but RmW works too :) 166 | ) tmem ( 167 | .clk (clk), 168 | .wen (t_wen), 169 | .ren (t_ren), 170 | .addr (t_addr_index), 171 | .wdata (tmem_wdata), 172 | .rdata (tmem_rdata) 173 | ); 174 | 175 | `ifdef FORMAL 176 | always @ (posedge clk) if (rst_n) begin 177 | assert(!(t_wen && t_ren)); 178 | assert(!(|d_wen && d_ren)); 179 | end 180 | `endif 181 | 182 | endmodule 183 | -------------------------------------------------------------------------------- /peris/uart/uart_regs.v: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * AUTOGENERATED BY REGBLOCK * 3 | * Do not edit manually. * 4 | * Edit the source file (or regblock utility) and regenerate. * 5 | *******************************************************************************/ 6 | 7 | // Block name : uart 8 | // Bus type : apb 9 | // Bus data width : 32 10 | // Bus address width : 16 11 | 12 | module uart_regs ( 13 | input wire clk, 14 | input wire rst_n, 15 | 16 | // APB Port 17 | input wire apbs_psel, 18 | input wire apbs_penable, 19 | input wire apbs_pwrite, 20 | input wire [15:0] apbs_paddr, 21 | input wire [31:0] apbs_pwdata, 22 | output wire [31:0] apbs_prdata, 23 | output wire apbs_pready, 24 | output wire apbs_pslverr, 25 | 26 | // Register interfaces 27 | output reg csr_en_o, 28 | input wire csr_busy_i, 29 | output reg csr_txie_o, 30 | output reg csr_rxie_o, 31 | output reg csr_ctsen_o, 32 | output reg csr_loopback_o, 33 | output reg [9:0] div_int_o, 34 | output reg [3:0] div_frac_o, 35 | input wire [7:0] fstat_txlevel_i, 36 | input wire fstat_txfull_i, 37 | input wire fstat_txempty_i, 38 | input wire fstat_txover_i, 39 | output reg fstat_txover_o, 40 | input wire fstat_txunder_i, 41 | output reg fstat_txunder_o, 42 | input wire [7:0] fstat_rxlevel_i, 43 | input wire fstat_rxfull_i, 44 | input wire fstat_rxempty_i, 45 | input wire fstat_rxover_i, 46 | output reg fstat_rxover_o, 47 | input wire fstat_rxunder_i, 48 | output reg fstat_rxunder_o, 49 | output reg [7:0] tx_o, 50 | output reg tx_wen, 51 | input wire [7:0] rx_i, 52 | output reg rx_ren 53 | ); 54 | 55 | // APB adapter 56 | wire [31:0] wdata = apbs_pwdata; 57 | reg [31:0] rdata; 58 | wire wen = apbs_psel && apbs_penable && apbs_pwrite; 59 | wire ren = apbs_psel && apbs_penable && !apbs_pwrite; 60 | wire [15:0] addr = apbs_paddr & 16'h1c; 61 | assign apbs_prdata = rdata; 62 | assign apbs_pready = 1'b1; 63 | assign apbs_pslverr = 1'b0; 64 | 65 | localparam ADDR_CSR = 0; 66 | localparam ADDR_DIV = 4; 67 | localparam ADDR_FSTAT = 8; 68 | localparam ADDR_TX = 12; 69 | localparam ADDR_RX = 16; 70 | 71 | wire __csr_wen = wen && addr == ADDR_CSR; 72 | wire __csr_ren = ren && addr == ADDR_CSR; 73 | wire __div_wen = wen && addr == ADDR_DIV; 74 | wire __div_ren = ren && addr == ADDR_DIV; 75 | wire __fstat_wen = wen && addr == ADDR_FSTAT; 76 | wire __fstat_ren = ren && addr == ADDR_FSTAT; 77 | wire __tx_wen = wen && addr == ADDR_TX; 78 | wire __tx_ren = ren && addr == ADDR_TX; 79 | wire __rx_wen = wen && addr == ADDR_RX; 80 | wire __rx_ren = ren && addr == ADDR_RX; 81 | 82 | wire csr_en_wdata = wdata[0]; 83 | wire csr_en_rdata; 84 | wire csr_busy_wdata = wdata[1]; 85 | wire csr_busy_rdata; 86 | wire csr_txie_wdata = wdata[2]; 87 | wire csr_txie_rdata; 88 | wire csr_rxie_wdata = wdata[3]; 89 | wire csr_rxie_rdata; 90 | wire csr_ctsen_wdata = wdata[4]; 91 | wire csr_ctsen_rdata; 92 | wire csr_loopback_wdata = wdata[8]; 93 | wire csr_loopback_rdata; 94 | wire [31:0] __csr_rdata = {23'h0, csr_loopback_rdata, 3'h0, csr_ctsen_rdata, csr_rxie_rdata, csr_txie_rdata, csr_busy_rdata, csr_en_rdata}; 95 | assign csr_en_rdata = csr_en_o; 96 | assign csr_busy_rdata = csr_busy_i; 97 | assign csr_txie_rdata = csr_txie_o; 98 | assign csr_rxie_rdata = csr_rxie_o; 99 | assign csr_ctsen_rdata = csr_ctsen_o; 100 | assign csr_loopback_rdata = csr_loopback_o; 101 | 102 | wire [9:0] div_int_wdata = wdata[13:4]; 103 | wire [9:0] div_int_rdata; 104 | wire [3:0] div_frac_wdata = wdata[3:0]; 105 | wire [3:0] div_frac_rdata; 106 | wire [31:0] __div_rdata = {18'h0, div_int_rdata, div_frac_rdata}; 107 | assign div_int_rdata = 10'h1; 108 | assign div_frac_rdata = 4'h0; 109 | 110 | wire [7:0] fstat_txlevel_wdata = wdata[7:0]; 111 | wire [7:0] fstat_txlevel_rdata; 112 | wire fstat_txfull_wdata = wdata[8]; 113 | wire fstat_txfull_rdata; 114 | wire fstat_txempty_wdata = wdata[9]; 115 | wire fstat_txempty_rdata; 116 | wire fstat_txover_wdata = wdata[10]; 117 | wire fstat_txover_rdata; 118 | wire fstat_txunder_wdata = wdata[11]; 119 | wire fstat_txunder_rdata; 120 | wire [7:0] fstat_rxlevel_wdata = wdata[23:16]; 121 | wire [7:0] fstat_rxlevel_rdata; 122 | wire fstat_rxfull_wdata = wdata[24]; 123 | wire fstat_rxfull_rdata; 124 | wire fstat_rxempty_wdata = wdata[25]; 125 | wire fstat_rxempty_rdata; 126 | wire fstat_rxover_wdata = wdata[26]; 127 | wire fstat_rxover_rdata; 128 | wire fstat_rxunder_wdata = wdata[27]; 129 | wire fstat_rxunder_rdata; 130 | wire [31:0] __fstat_rdata = {4'h0, fstat_rxunder_rdata, fstat_rxover_rdata, fstat_rxempty_rdata, fstat_rxfull_rdata, fstat_rxlevel_rdata, 4'h0, fstat_txunder_rdata, fstat_txover_rdata, fstat_txempty_rdata, fstat_txfull_rdata, fstat_txlevel_rdata}; 131 | assign fstat_txlevel_rdata = fstat_txlevel_i; 132 | assign fstat_txfull_rdata = fstat_txfull_i; 133 | assign fstat_txempty_rdata = fstat_txempty_i; 134 | reg fstat_txover; 135 | assign fstat_txover_rdata = fstat_txover; 136 | reg fstat_txunder; 137 | assign fstat_txunder_rdata = fstat_txunder; 138 | assign fstat_rxlevel_rdata = fstat_rxlevel_i; 139 | assign fstat_rxfull_rdata = fstat_rxfull_i; 140 | assign fstat_rxempty_rdata = fstat_rxempty_i; 141 | reg fstat_rxover; 142 | assign fstat_rxover_rdata = fstat_rxover; 143 | reg fstat_rxunder; 144 | assign fstat_rxunder_rdata = fstat_rxunder; 145 | 146 | wire [7:0] tx_wdata = wdata[7:0]; 147 | wire [7:0] tx_rdata; 148 | wire [31:0] __tx_rdata = {24'h0, tx_rdata}; 149 | assign tx_rdata = 8'h0; 150 | 151 | wire [7:0] rx_wdata = wdata[7:0]; 152 | wire [7:0] rx_rdata; 153 | wire [31:0] __rx_rdata = {24'h0, rx_rdata}; 154 | assign rx_rdata = rx_i; 155 | 156 | always @ (*) begin 157 | case (addr) 158 | ADDR_CSR: rdata = __csr_rdata; 159 | ADDR_DIV: rdata = __div_rdata; 160 | ADDR_FSTAT: rdata = __fstat_rdata; 161 | ADDR_TX: rdata = __tx_rdata; 162 | ADDR_RX: rdata = __rx_rdata; 163 | default: rdata = 32'h0; 164 | endcase 165 | fstat_txover_o = fstat_txover; 166 | fstat_txunder_o = fstat_txunder; 167 | fstat_rxover_o = fstat_rxover; 168 | fstat_rxunder_o = fstat_rxunder; 169 | tx_wen = __tx_wen; 170 | tx_o = tx_wdata; 171 | rx_ren = __rx_ren; 172 | end 173 | 174 | always @ (posedge clk or negedge rst_n) begin 175 | if (!rst_n) begin 176 | csr_en_o <= 1'h0; 177 | csr_txie_o <= 1'h0; 178 | csr_rxie_o <= 1'h0; 179 | csr_ctsen_o <= 1'h0; 180 | csr_loopback_o <= 1'h0; 181 | div_int_o <= 10'h1; 182 | div_frac_o <= 4'h0; 183 | fstat_txover <= 1'h0; 184 | fstat_txunder <= 1'h0; 185 | fstat_rxover <= 1'h0; 186 | fstat_rxunder <= 1'h0; 187 | end else begin 188 | if (__csr_wen) 189 | csr_en_o <= csr_en_wdata; 190 | if (__csr_wen) 191 | csr_txie_o <= csr_txie_wdata; 192 | if (__csr_wen) 193 | csr_rxie_o <= csr_rxie_wdata; 194 | if (__csr_wen) 195 | csr_ctsen_o <= csr_ctsen_wdata; 196 | if (__csr_wen) 197 | csr_loopback_o <= csr_loopback_wdata; 198 | if (__div_wen) 199 | div_int_o <= div_int_wdata; 200 | if (__div_wen) 201 | div_frac_o <= div_frac_wdata; 202 | fstat_txover <= (fstat_txover && !(__fstat_wen && fstat_txover_wdata)) || fstat_txover_i; 203 | fstat_txunder <= (fstat_txunder && !(__fstat_wen && fstat_txunder_wdata)) || fstat_txunder_i; 204 | fstat_rxover <= (fstat_rxover && !(__fstat_wen && fstat_rxover_wdata)) || fstat_rxover_i; 205 | fstat_rxunder <= (fstat_rxunder && !(__fstat_wen && fstat_rxunder_wdata)) || fstat_rxunder_i; 206 | end 207 | end 208 | 209 | endmodule 210 | --------------------------------------------------------------------------------