├── .gitignore ├── Makefile ├── Makefile.icestorm ├── README.md ├── blink.v ├── cordic.c ├── cordic.v ├── dac.v ├── icebreaker.pcf ├── images ├── dsp-mac16.svg ├── ice40-plb.png ├── ice40-ram4k.png ├── ice40-spram.png ├── ice40-up5k.png ├── led.jpg ├── pinout.jpg └── up5k.svg ├── led_matrix.v ├── lighthouse-demo.v ├── lighthouse.v ├── oled-demo.v ├── oled.v ├── packed0.hex ├── packed1.hex ├── pulse.v ├── serial-echo.v ├── serial-hexdump.v ├── serial.v ├── spi_device.v ├── spispy.py ├── spispy.v ├── spram-demo.v ├── spram.v ├── tinyfpga-bx.pcf ├── tomu.pcf ├── uart.v ├── upduino_v2.pcf ├── usb ├── Makefile ├── edge_detect.v ├── serial-demo.v ├── strobe.v ├── usb_fs_in_arb.v ├── usb_fs_in_pe.v ├── usb_fs_out_arb.v ├── usb_fs_out_pe.v ├── usb_fs_pe.v ├── usb_fs_rx.v ├── usb_fs_tx.v ├── usb_fs_tx_mux.v ├── usb_serial.v ├── usb_serial_ctrl_ep.v ├── usb_serial_ep.v └── usb_uart.v └── util.v /.gitignore: -------------------------------------------------------------------------------- 1 | .*.swp 2 | *.bin 3 | *.blif 4 | *.asc 5 | *.timing 6 | pll_*.v 7 | *.json 8 | .*.d 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: pulse.bin 3 | all: blink.bin 4 | all: serial.bin 5 | all: serial-echo.bin 6 | all: spram-demo.bin 7 | #all: lighthouse-demo.bin 8 | 9 | 10 | include Makefile.icestorm 11 | -------------------------------------------------------------------------------- /Makefile.icestorm: -------------------------------------------------------------------------------- 1 | DEVICE-upduino ?= up5k 2 | FOOTPRINT-upduino ?= sg48 3 | PIN_SRC-upduino ?= upduino_v2.pcf 4 | 5 | DEVICE-icebreaker ?= up5k 6 | FOOTPRINT-icebreaker ?= sg48 7 | PIN_SRC-icebreaker ?= icebreaker.pcf 8 | 9 | 10 | DEVICE-tinyfpga := lp8k 11 | FOOTPRINT-tinyfpga := cm81 12 | PIN_SRC-tinyfpga := tinyfpga-bx.pcf 13 | 14 | DEVICE-tomu := up5k 15 | FOOTPRINT-tomu := uwg30 16 | PIN_SRC-tomu := tomu.pcf 17 | 18 | USB_DEV ?= 1-1:1.0 19 | BOARD ?= upduino 20 | DEVICE := $(DEVICE-$(BOARD)) 21 | FOOTPRINT := $(FOOTPRINT-$(BOARD)) 22 | PIN_SRC := $(PIN_SRC-$(BOARD)) 23 | 24 | 25 | PNR ?= $(ICEPATH)nextpnr-ice40 26 | .SECONDARY: 27 | 28 | %.flash: %.bin 29 | $(ICEPATH)iceprog -e 128 # Force a reset 30 | $(ICEPATH)iceprog $< 31 | echo $(USB_DEV) | tee /sys/bus/usb/drivers/ftdi_sio/bind 32 | 33 | %.bin: %.asc 34 | $(ICEPATH)icepack $< $@ 35 | 36 | %.json: %.v 37 | $(ICEPATH)yosys \ 38 | -q \ 39 | -p 'read_verilog $<' \ 40 | -p 'synth_ice40 -top top -json $@' \ 41 | -E .$(basename $@).d \ 42 | 43 | %.asc: $(PIN_SRC) %.json 44 | $(PNR) \ 45 | --$(DEVICE) \ 46 | --package $(FOOTPRINT) \ 47 | --asc $@ \ 48 | --pcf $(PIN_SRC) \ 49 | --json $(basename $@).json \ 50 | 51 | %.gui: %.json 52 | $(PNR) --gui --$(DEVICE) --pcf $(PIN_SRC) --json $< 53 | 54 | %.bin: %.asc 55 | $(ICEPATH)icepack $^ $@ 56 | 57 | # Generate a desired MHz pll 58 | pll_%.v: 59 | $(ICEPATH)icepll \ 60 | -i 48 \ 61 | -o $(subst pll_,,$(basename $@)) \ 62 | -m \ 63 | -n $(basename $@) \ 64 | -f $@ 65 | 66 | 67 | define make-test = 68 | $1: $1.vvp 69 | vvp $$< 70 | endef 71 | 72 | test: $(TEST-y) 73 | $(foreach t,$(TEST-y),$(eval $(call make-test,$t))) 74 | %.vvp: 75 | iverilog -o $@ -s $(basename $@) $^ 76 | 77 | clean: 78 | $(RM) *.blif *.asc *.bin *.json .*.d 79 | 80 | -include .*.d 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Upduino v2 RGB LEd](images/led.jpg) 2 | 3 | Upduino v2 examples with icestorm 4 | ==== 5 | 6 | Several demos showing how to use the `icestorm` toolchain with the 7 | Upduino (ice40 UltraPlus 5k) FPGA dev board. 8 | 9 | | Demo | Description | 10 | |------|-------------| 11 | | `blink` | Flash the RED LED in a pulse-pulse, pulse-pulse pattern | 12 | | `pulse` | Smoothly ramp the RGB LED through a color change pattern | 13 | | `serial` | Print a repeating message on the serial port at 3 Mbs | 14 | | `seral-echo` | Read from the serial port, echo it back at 3 Mbs | 15 | | `spram-demo` | Read from the serial port, buffer in SPRAM, echo it slowly | 16 | 17 | To flash them, run `sudo make blink.flash`. 18 | You will probably need to be root to flash the board and restore the 19 | `/dev/ttyUSB0` device driver after `iceprog` switches it into SIO mode. 20 | 21 | 22 | Schematics and pinout 23 | ==== 24 | 25 | Schematics for the upduino: https://github.com/gtjennings1/UPDuino_v2_0 26 | 27 | ![Upduino v2 pinout by Matt Mets](images/pinout.jpg) 28 | 29 | Note that the `upduino_v2.pcf` file disagrees with the serial port in 30 | the pinout and schematic. The pins were determined through experimentation 31 | and seem to work (and the ones in the pinout do not). 32 | 33 | UltraPlus 5K overview 34 | === 35 | 36 | ![Block diagram](images/up5k.svg) 37 | 38 | Overview: http://www.latticesemi.com/Products/FPGAandCPLD/iCE40UltraPlus 39 | 40 | Datasheet: http://www.latticesemi.com/-/media/LatticeSemi/Documents/DataSheets/iCE/iCE40-UltraPlus-Family-Data-Sheet.ashx 41 | 42 | ![DSP Block](images/dsp-mac16.svg) 43 | 44 | The eight DSP blocks can do 16x16 multiply and 32-bit accumulate operations. 45 | They can be combined to make 32x32 multipliers, etc. 46 | -------------------------------------------------------------------------------- /blink.v: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Demo the RGB LED on the upduino v2 3 | * 4 | * Note that the LED pins are inverted, so 0 is on 5 | */ 6 | 7 | module top( 8 | output led_r, 9 | output led_g, 10 | output led_b 11 | ); 12 | // turn off the green and blue (drive the lines high) 13 | assign led_g = 1; 14 | assign led_b = 1; 15 | 16 | 17 | // enable the high frequency oscillator, 18 | // which generates a 48 MHz clock 19 | wire clk_48; 20 | SB_HFOSC u_hfosc ( 21 | .CLKHFPU(1'b1), 22 | .CLKHFEN(1'b1), 23 | .CLKHF(clk_48) 24 | ); 25 | 26 | // increment the global counter at 48 MHz 27 | reg [31:0] counter; 28 | always @(posedge clk_48) 29 | counter <= counter + 1; 30 | 31 | 32 | // flash the LED in a pulse, pulse, pause, pulse, pulse pattern 33 | reg [7:0] pulse = 8'b10010000; 34 | 35 | always @(posedge counter[22]) 36 | begin 37 | led_r <= !pulse[0]; 38 | pulse <= { pulse[0], pulse[7:1] }; 39 | end 40 | 41 | endmodule 42 | -------------------------------------------------------------------------------- /cordic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(void) 5 | { 6 | const int bits = 20; 7 | const int max = (1 << bits)/2 - 1; // range is -max to +max 8 | const int shift = 5; 9 | const int shift_mask = (1 << shift) - 1; 10 | 11 | int x = max; 12 | int y = 0; 13 | 14 | const float k = 1.0; 15 | 16 | for(int i = 0 ; i < (1<<21) ; i++) 17 | { 18 | printf("%d %d\n", x, y); 19 | 20 | int xp = x + (y >> shift) - (x >> (2*shift+1)); 21 | int yp = y - (x >> shift) - (y >> (2*shift+1)); // + (xacc >> shift); 22 | 23 | 24 | #if 1 25 | if (xp > max) 26 | { 27 | x = max; 28 | y = 0; 29 | } else 30 | if (yp > max) 31 | { 32 | x = 0; 33 | y = max; 34 | } else 35 | if (yp < -max) 36 | { 37 | x = 0; 38 | y = -max; 39 | } else 40 | if (xp < -max) 41 | { 42 | x = -max; 43 | y = 0; 44 | } else 45 | #endif 46 | { 47 | x = xp; 48 | y = yp; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /cordic.v: -------------------------------------------------------------------------------- 1 | module cordic( 2 | input clk, 3 | input reset, 4 | output signed [BITS-1:0] sin, 5 | output signed [BITS-1:0] cos 6 | ); 7 | parameter BITS = 20; 8 | parameter SHIFT = 5; 9 | localparam MAX = (1 << (BITS-1)) - 1; 10 | reg signed [BITS-1:0] x; 11 | reg signed [BITS-1:0] y; 12 | //int xp = x + (y >> shift) - (x >> (2*shift+1)); 13 | //int yp = y - (x >> shift) - (y >> (2*shift+1)); // + (xacc >> shift); 14 | wire signed [BITS:0] nx = x + (y >>> SHIFT) - (x >>> (2*SHIFT+1)); 15 | wire signed [BITS:0] ny = y - (x >>> SHIFT) - (y >>> (2*SHIFT+1)); 16 | 17 | assign sin = x[BITS-1:0]; // + (1 << (BITS-1)); 18 | assign cos = y[BITS-1:0]; // + (1 << (BITS-1)); 19 | 20 | 21 | always @(posedge clk) 22 | begin 23 | if (reset) begin 24 | x <= MAX; 25 | y <= 0; 26 | end else 27 | if (nx > MAX) begin 28 | x <= MAX; 29 | y <= 0; 30 | end else 31 | if (ny > MAX) begin 32 | x <= 0; 33 | y <= MAX; 34 | end else 35 | if (nx < -MAX) begin 36 | x <= -MAX; 37 | y <= 0; 38 | end else 39 | if (ny < -MAX) begin 40 | x <= 0; 41 | y <= -MAX; 42 | end else 43 | begin 44 | x <= nx; 45 | y <= ny; 46 | end 47 | end 48 | 49 | endmodule 50 | 51 | 52 | module test_cordic; 53 | 54 | parameter BITS=20; 55 | wire signed [BITS-1:0] x; 56 | wire signed [BITS-1:0] y; 57 | reg reset = 1; 58 | reg clk = 0; 59 | 60 | cordic #(BITS,5) cord(clk, reset, x, y); 61 | 62 | 63 | always #5 clk = !clk; 64 | 65 | always begin 66 | # 50 reset <= 0; 67 | # 100000 $finish; 68 | end 69 | 70 | initial begin 71 | //$display("time,clk,x,y"); 72 | $monitor("%d %d", x, y); 73 | end 74 | 75 | endmodule 76 | -------------------------------------------------------------------------------- /dac.v: -------------------------------------------------------------------------------- 1 | module top( 2 | output led_r, 3 | output led_b, 4 | output gpio_2, // cs 5 | output gpio_46, // clk 6 | output gpio_47 // do 7 | ); 8 | wire reset = 0; 9 | wire clk_48mhz, clk = clk_48mhz; 10 | SB_HFOSC osc(1,1,clk_48mhz); 11 | 12 | reg [11:0] value_x; 13 | reg [11:0] value_y; 14 | reg axis; 15 | reg dac_strobe; 16 | wire dac_ready; 17 | 18 | mpc4922 dac( 19 | .clk(clk), 20 | .reset(reset), 21 | .cs_pin(gpio_2), 22 | .clk_pin(gpio_46), 23 | .data_pin(gpio_47), 24 | .value(axis ? value_x : value_y), 25 | .axis(axis), 26 | .strobe(dac_strobe), 27 | .ready(dac_ready) 28 | ); 29 | 30 | reg [15:0] counter; 31 | always @(posedge clk) begin 32 | counter <= counter + 1; 33 | led_r = !(counter < value_x); 34 | led_b = 1; //!dac_strobe; //!(counter < value_y); 35 | end 36 | 37 | always @(posedge clk) 38 | begin 39 | dac_strobe <= 0; 40 | 41 | if (!dac_ready || dac_strobe) 42 | begin 43 | // do nothing 44 | end else //if (counter == 0) 45 | begin 46 | if (axis) 47 | value_x <= value_x - 3; 48 | else 49 | value_y <= value_y + 7; 50 | 51 | dac_strobe <= 1; 52 | axis <= !axis; 53 | end 54 | end 55 | endmodule 56 | 57 | 58 | /* 59 | * SPI input timing: 60 | * CS is active low 61 | * CLK is rising edge 62 | */ 63 | module mpc4922( 64 | input clk, 65 | input reset, 66 | 67 | // physical interface 68 | output cs_pin, 69 | output clk_pin, 70 | output data_pin, 71 | 72 | // logical interface 73 | input [11:0] value, 74 | input axis, 75 | input strobe, 76 | output ready 77 | ); 78 | parameter GAIN = 1'b1; // Normal gain 79 | parameter BUFFERED = 1'b1; // buffered 80 | parameter SHUTDOWN = 1'b1; // not shutdown 81 | 82 | reg [15:0] cmd; 83 | reg [4:0] bits; 84 | assign ready = !reset && bits == 0; 85 | assign cs_pin = ready; // negative logic 86 | assign data_pin = cmd[15]; 87 | 88 | always @(posedge clk) 89 | begin 90 | if (reset) begin 91 | bits <= 0; 92 | clk_pin <= 0; 93 | end else 94 | if (strobe) begin 95 | cmd <= { axis, BUFFERED, GAIN, SHUTDOWN, value }; 96 | bits <= 16; 97 | clk_pin <= 0; 98 | end else 99 | if (bits != 0) begin 100 | if (clk_pin) begin 101 | // change when it is currently high 102 | cmd <= { cmd[14:0], 1'b0 }; 103 | clk_pin <= 0; 104 | bits <= bits - 1; 105 | end else begin 106 | // rising edge clocks the data 107 | clk_pin <= 1; 108 | end 109 | end else begin 110 | clk_pin <= 0; 111 | end 112 | end 113 | 114 | endmodule 115 | -------------------------------------------------------------------------------- /icebreaker.pcf: -------------------------------------------------------------------------------- 1 | # 12 MHz clock 2 | set_io -nowarn CLK 35 3 | 4 | # RS232 5 | set_io -nowarn serial_rxd 6 6 | set_io -nowarn serial_txd 9 7 | 8 | # LEDs and Button 9 | set_io -nowarn BTN_N 10 10 | set_io -nowarn led_r 11 11 | set_io -nowarn led_g 37 12 | 13 | # RGB LED Driver 14 | set_io -nowarn R 39 15 | set_io -nowarn G 40 16 | set_io -nowarn B 41 17 | 18 | # SPI Flash 19 | set_io -nowarn FLASH_SCK 15 20 | set_io -nowarn FLASH_SSB 16 21 | set_io -nowarn FLASH_IO0 14 22 | set_io -nowarn FLASH_IO1 17 23 | set_io -nowarn FLASH_IO2 12 24 | set_io -nowarn FLASH_IO3 13 25 | 26 | # PMOD 1A 27 | set_io -nowarn P1A1 4 28 | set_io -nowarn P1A2 2 29 | set_io -nowarn P1A3 47 30 | set_io -nowarn P1A4 45 31 | set_io -nowarn P1A7 3 32 | set_io -nowarn P1A8 48 33 | set_io -nowarn P1A9 46 34 | set_io -nowarn P1A10 44 35 | 36 | # PMOD 1B 37 | set_io -nowarn P1B1 43 38 | set_io -nowarn P1B2 38 39 | set_io -nowarn P1B3 34 40 | set_io -nowarn P1B4 31 41 | set_io -nowarn P1B7 42 42 | set_io -nowarn P1B8 36 43 | set_io -nowarn P1B9 32 44 | set_io -nowarn P1B10 28 45 | 46 | # PMOD 2 47 | set_io -nowarn P2_1 27 48 | set_io -nowarn P2_2 25 49 | set_io -nowarn P2_3 21 50 | set_io -nowarn P2_4 19 51 | set_io -nowarn P2_7 26 52 | set_io -nowarn P2_8 23 53 | set_io -nowarn P2_9 20 54 | set_io -nowarn P2_10 18 55 | 56 | # LEDs and Buttons (PMOD 2) 57 | set_io -nowarn LED1 27 58 | set_io -nowarn LED2 25 59 | set_io -nowarn LED3 21 60 | set_io -nowarn BTN2 19 61 | set_io -nowarn LED5 26 62 | set_io -nowarn LED4 23 63 | set_io -nowarn BTN1 20 64 | set_io -nowarn BTN3 18 65 | -------------------------------------------------------------------------------- /images/ice40-plb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osresearch/up5k/2eef12a9659b8fc4ebf68656198b8840f6da2e0d/images/ice40-plb.png -------------------------------------------------------------------------------- /images/ice40-ram4k.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osresearch/up5k/2eef12a9659b8fc4ebf68656198b8840f6da2e0d/images/ice40-ram4k.png -------------------------------------------------------------------------------- /images/ice40-spram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osresearch/up5k/2eef12a9659b8fc4ebf68656198b8840f6da2e0d/images/ice40-spram.png -------------------------------------------------------------------------------- /images/ice40-up5k.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osresearch/up5k/2eef12a9659b8fc4ebf68656198b8840f6da2e0d/images/ice40-up5k.png -------------------------------------------------------------------------------- /images/led.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osresearch/up5k/2eef12a9659b8fc4ebf68656198b8840f6da2e0d/images/led.jpg -------------------------------------------------------------------------------- /images/pinout.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osresearch/up5k/2eef12a9659b8fc4ebf68656198b8840f6da2e0d/images/pinout.jpg -------------------------------------------------------------------------------- /led_matrix.v: -------------------------------------------------------------------------------- 1 | `include "util.v" 2 | `include "uart.v" 3 | 4 | module top( 5 | output serial_txd, 6 | input serial_rxd, 7 | output spi_cs, 8 | output led_r, 9 | 10 | output gpio_26, 11 | output gpio_27, 12 | output gpio_32, 13 | output gpio_35, 14 | output gpio_31, 15 | output gpio_37, 16 | output gpio_34, 17 | output gpio_43, 18 | output gpio_36, 19 | output gpio_42, 20 | output gpio_38, 21 | output gpio_28 22 | ); 23 | assign spi_cs = 1; // it is necessary to turn off the SPI flash chip 24 | reg reset = 0; 25 | wire clk_48mhz; 26 | SB_HFOSC osc(1,1, clk_48mhz); 27 | reg [10:0] counter; 28 | always @(posedge clk_48mhz) begin 29 | counter <= counter + 1; 30 | if (~counter == 0) 31 | reset <= 0; 32 | end 33 | 34 | wire clk = clk_48mhz; // counter[0]; 35 | 36 | 37 | wire [2:0] led_addr = {gpio_36, gpio_34, gpio_43}; 38 | 39 | reg [7:0] r; 40 | reg [7:0] g; 41 | reg [7:0] b; 42 | reg [7:0] x; 43 | reg [7:0] y; 44 | reg input_strobe; 45 | 46 | 47 | led_matrix matrix( 48 | .clk(clk), 49 | .reset(reset), 50 | 51 | // pins 52 | .led_clk(gpio_38), 53 | .led_latch(gpio_42), 54 | .led_oe(gpio_28), 55 | .led_addr(led_addr), 56 | .led_r({gpio_35, gpio_27}), 57 | .led_g({gpio_31, gpio_26}), 58 | .led_b({gpio_37, gpio_32}), 59 | 60 | // 61 | .input_clk(clk), 62 | .strobe(input_strobe), 63 | .r(r), 64 | .g(g), 65 | .b(b), 66 | .x(x), 67 | .y(y) 68 | ); 69 | 70 | // generate a 3 MHz/12 MHz serial clock from the 48 MHz clock 71 | // this is the 3 Mb/s maximum supported by the FTDI chip 72 | wire clk_4; 73 | divide_by_n #(.N( 4)) div4(clk_48mhz, reset, clk_4); 74 | 75 | wire [7:0] uart_rxd; 76 | wire uart_rxd_strobe; 77 | assign serial_txd = 1; 78 | 79 | uart_rx rxd( 80 | .mclk(clk), 81 | .reset(reset), 82 | .baud_x4(clk_4), 83 | .serial(serial_rxd), 84 | .data(uart_rxd), 85 | .data_strobe(uart_rxd_strobe) 86 | ); 87 | 88 | reg [1:0] channel = 0; 89 | 90 | always @(posedge clk) 91 | begin 92 | input_strobe <= 0; 93 | led_r <= 1; 94 | 95 | if (!uart_rxd_strobe) 96 | begin 97 | // nothing 98 | end else 99 | if (channel == 0) begin 100 | if (x != 31) 101 | x <= x + 1; 102 | else begin 103 | x <= 0; 104 | if (y != 15) 105 | y <= y + 1; 106 | else 107 | y <= 0; 108 | end 109 | 110 | r <= uart_rxd; 111 | channel <= 1; 112 | //led_r <= 0; 113 | end else 114 | if (channel == 1) begin 115 | //led_r <= 0; 116 | g <= uart_rxd; 117 | channel <= 2; 118 | end else 119 | if (channel == 2) begin 120 | //led_r <= 0; 121 | b <= uart_rxd; 122 | input_strobe <= 1; 123 | channel <= 0; 124 | end else begin 125 | led_r <= 0; 126 | channel <= 0; 127 | end 128 | end 129 | 130 | endmodule 131 | 132 | 133 | 134 | /* 135 | * Max output chains: 136 | * 8 rgb sets * 8 rows per set = 64 vertical rows 137 | * 138 | * Max resolution on a up5k: 139 | * 30 * 4096 bit dual port block RAM 140 | * 64 * 64 == 4096 pixels @ 24 bits per pixel 141 | * 142 | * Using SPRAM, 4 * 256 Kb 143 | * 8192 pixels per SPRAM @ 24 bits per pixel 144 | * 1024 x 64 145 | * 146 | * Max update at 1024 == 46 K-rows / sec 147 | * 5 KHz per row (@ 8 row scan) 148 | * == 128 levels @ 45 Hz 149 | */ 150 | module led_matrix( 151 | input clk, 152 | input reset, 153 | 154 | // physical interface 155 | output reg led_clk, 156 | output reg led_latch, 157 | output reg led_oe, 158 | output reg [ADDR_WIDTH-1:0] led_addr, 159 | output reg [ROWS-1:0] led_r, 160 | output reg [ROWS-1:0] led_g, 161 | output reg [ROWS-1:0] led_b, 162 | 163 | // input from caller to update a frame buffer 164 | input input_clk, 165 | input [7:0] r, 166 | input [7:0] g, 167 | input [7:0] b, 168 | input [7:0] x, 169 | input [7:0] y, 170 | input strobe 171 | ); 172 | parameter ROWS = 2; 173 | parameter ADDR_WIDTH = 3; 174 | parameter X_RES = 32; 175 | parameter Y_SHIFT = 5; // CLOG2(X_RES) 176 | parameter Y_STRIDE = 8; //1 << ADDR_WIDTH; 177 | parameter Y_RES = ROWS * Y_STRIDE; 178 | parameter DIM = 0; 179 | 180 | reg [7:0] bright; 181 | reg [7:0] led_x; 182 | reg [7:0] led_y; 183 | reg [7:0] row; 184 | reg all_rows_done; 185 | reg all_pixels_done; 186 | 187 | reg [15:0] framebuffer_0[X_RES * Y_RES/2 - 1 : 0]; 188 | reg [15:0] framebuffer_1[X_RES * Y_RES/2 - 1 : 0]; 189 | 190 | wire [15:0] pix_0 = (led_y << Y_SHIFT) | led_x; 191 | wire [15:0] pix_1 = ((led_y+Y_STRIDE) << Y_SHIFT) | led_x; 192 | 193 | reg [7:0] pix_r0; 194 | reg [7:0] pix_g0; 195 | reg [7:0] pix_b0; 196 | 197 | reg [7:0] pix_r1; 198 | reg [7:0] pix_g1; 199 | reg [7:0] pix_b1; 200 | 201 | always @(posedge clk) begin 202 | pix_r0 <= framebuffer_0[pix_0][15:11] << 1; 203 | pix_g0 <= framebuffer_0[pix_0][10:5] << 0; 204 | pix_b0 <= framebuffer_0[pix_0][4:0] << 1; 205 | 206 | pix_r1 <= framebuffer_1[pix_1][15:11] << 1; 207 | pix_g1 <= framebuffer_1[pix_1][10:5] << 0; 208 | pix_b1 <= framebuffer_1[pix_1][4:0] << 1; 209 | end 210 | 211 | initial $readmemh("packed0.hex", framebuffer_0); 212 | initial $readmemh("packed1.hex", framebuffer_1); 213 | //initial $readmemh("blue.hex", framebuffer_b); 214 | 215 | reg stall; 216 | 217 | // output logic 218 | always @(posedge clk) 219 | begin 220 | led_clk <= 0; 221 | led_latch <= 0; 222 | 223 | if (reset) 224 | begin 225 | bright <= 0; 226 | row <= 0; 227 | led_addr <= 0; 228 | led_x <= 0; 229 | led_y <= 0; 230 | led_oe <= 1; 231 | all_rows_done <= 0; 232 | all_pixels_done <= 0; 233 | end else 234 | if (stall) begin 235 | stall <= 0; 236 | end else 237 | if (all_pixels_done) 238 | begin 239 | if (bright == 255) begin 240 | // have done all of the brightness at this 241 | // output address, switch off the output 242 | // and update the output address 243 | bright <= 0; 244 | led_oe <= 1; 245 | led_x <= 0; 246 | all_pixels_done <= 0; 247 | all_rows_done <= 0; 248 | 249 | // led_addr will wrap 250 | led_addr <= led_addr + 1; 251 | led_y <= led_addr + 1; 252 | end else begin 253 | // not yet done with this row 254 | // increase the brightness 255 | // and reset to the start of this row 256 | bright <= bright + 1; 257 | led_x <= 0; 258 | all_pixels_done <= 0; 259 | all_rows_done <= 0; 260 | stall <= 1; 261 | end 262 | end else 263 | if (all_rows_done) 264 | begin 265 | // updated all the rows, clock out this pixel 266 | // and prepare to clock out the next 267 | led_clk <= 1; 268 | led_y <= led_addr; 269 | row <= 0; 270 | all_rows_done <= 0; 271 | 272 | if (led_x == X_RES-1) begin 273 | // end of the row, latch it and enable output 274 | all_pixels_done <= 1; 275 | led_latch <= 1; 276 | led_oe <= 0; 277 | end else begin 278 | led_x <= led_x + 1; 279 | end 280 | end else begin 281 | // update the output bit for this r/g/b 282 | led_r[0] <= (pix_r0 >> DIM) > bright; 283 | led_g[0] <= (pix_g0 >> DIM) > bright; 284 | led_b[0] <= (pix_b0 >> DIM) > bright; 285 | led_r[1] <= (pix_r1 >> DIM) > bright; 286 | led_g[1] <= (pix_g1 >> DIM) > bright; 287 | led_b[1] <= (pix_b1 >> DIM) > bright; 288 | 289 | //led_r[row] <= (led_x << 2) > bright; 290 | //led_g[row] <= 0; // 291 | //led_b[row] <= 0; //bright < 200; 292 | 293 | all_rows_done <= 1; 294 | end 295 | end 296 | 297 | 298 | // input can run in a separate clock domain 299 | // this might need an input fifo to allow the framebuffer 300 | // to move into an spram 301 | wire [15:0] input_offset = (y << Y_SHIFT) | x; 302 | 303 | // 16-bit packed pixels, 5 red, 6 green, 5 blue 304 | wire [15:0] input_packed = { r[7:3], g[7:3], 1'b0, b[7:3] }; 305 | 306 | always @(posedge input_clk) 307 | begin 308 | if (strobe) begin 309 | if (y[3] == 0) 310 | framebuffer_0[input_offset] <= input_packed; 311 | else 312 | framebuffer_1[input_offset] <= input_packed; 313 | end 314 | end 315 | 316 | endmodule 317 | -------------------------------------------------------------------------------- /lighthouse-demo.v: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Print the lengths of timer pulses from the lighthouse sensors. 3 | */ 4 | `include "util.v" 5 | `include "uart.v" 6 | `include "lighthouse.v" 7 | 8 | module top( 9 | output led_r, 10 | output led_g, 11 | output led_b, 12 | output serial_txd, 13 | input serial_rxd, 14 | output spi_cs, 15 | input gpio_9, 16 | input gpio_18, 17 | input gpio_28, 18 | input gpio_38, 19 | input gpio_2, 20 | input gpio_46, 21 | input gpio_47, 22 | input gpio_45, 23 | input gpio_48, 24 | input gpio_3, 25 | input gpio_4, 26 | input gpio_44, 27 | input gpio_6, 28 | input gpio_42, 29 | input gpio_36, 30 | input gpio_34 31 | ); 32 | assign spi_cs = 1; // it is necessary to turn off the SPI flash chip 33 | 34 | // map the sensor 35 | parameter NUM_SENSORS = 16; 36 | wire [15:0] lighthouse_pin = { 37 | gpio_48, 38 | gpio_3, 39 | gpio_4, 40 | gpio_44, 41 | 42 | gpio_6, 43 | gpio_42, 44 | gpio_34, 45 | gpio_36, 46 | 47 | gpio_2, 48 | gpio_46, 49 | gpio_47, 50 | gpio_45, 51 | 52 | // really hooked up 53 | gpio_28, 54 | gpio_18, 55 | gpio_38, 56 | gpio_9 57 | }; 58 | 59 | wire clk_48; 60 | wire reset = 0; 61 | SB_HFOSC u_hfosc ( 62 | .CLKHFPU(1'b1), 63 | .CLKHFEN(1'b1), 64 | .CLKHF(clk_48) 65 | ); 66 | 67 | /* 68 | // pulse the green LED to know that we're alive 69 | reg [25:0] counter; 70 | always @(posedge clk_48) 71 | counter <= counter + 1; 72 | wire pwm_g; 73 | pwm pwm_g_driver(clk_48, 1, pwm_g); 74 | assign led_g = !(counter[25:23] == 0 && pwm_g); 75 | */ 76 | 77 | assign led_b = serial_rxd; // idles high 78 | 79 | // generate a 3 MHz/12 MHz serial clock from the 48 MHz clock 80 | // this is the 3 Mb/s maximum supported by the FTDI chip 81 | wire clk_1, clk_4; 82 | divide_by_n #(.N(16)) div1(clk_48, reset, clk_1); 83 | divide_by_n #(.N( 4)) div4(clk_48, reset, clk_4); 84 | 85 | wire [7:0] uart_rxd; 86 | wire uart_rxd_strobe; 87 | 88 | uart_rx rxd( 89 | .mclk(clk_48), 90 | .reset(reset), 91 | .baud_x4(clk_4), 92 | .serial(serial_rxd), 93 | .data(uart_rxd), 94 | .data_strobe(uart_rxd_strobe) 95 | ); 96 | 97 | assign led_r = serial_txd; 98 | 99 | reg [7:0] uart_txd; 100 | reg uart_txd_strobe = 0; 101 | 102 | uart_tx_fifo #(.NUM(256)) txd( 103 | .clk(clk_48), 104 | .reset(reset), 105 | .baud_x1(clk_1), 106 | .serial(serial_txd), 107 | .data(uart_txd), 108 | .data_strobe(uart_txd_strobe) 109 | ); 110 | 111 | // output buffer 112 | parameter FIFO_WIDTH = 28; 113 | reg [FIFO_WIDTH-1:0] fifo_write; 114 | reg fifo_write_strobe; 115 | wire fifo_available; 116 | wire [FIFO_WIDTH-1:0] fifo_read; 117 | reg fifo_read_strobe; 118 | 119 | fifo #(.WIDTH(FIFO_WIDTH),.NUM(32)) timer_fifo( 120 | .clk(clk_48), 121 | .reset(reset), 122 | .data_available(fifo_available), 123 | .write_data(fifo_write), 124 | .write_strobe(fifo_write_strobe), 125 | .read_data(fifo_read), 126 | .read_strobe(fifo_read_strobe) 127 | ); 128 | 129 | wire angle_strobe; 130 | wire lighthouse; 131 | wire axis; 132 | wire [3:0] sensor; 133 | wire [19:0] angle; 134 | 135 | wire data_strobe; 136 | wire data_out; 137 | reg data; 138 | 139 | lighthouse_sensor #(.SENSORS(NUM_SENSORS)) lh( 140 | .clk(clk_48), 141 | .reset(reset), 142 | .raw_pins(lighthouse_pin), 143 | 144 | .angle_strobe(angle_strobe), 145 | .sensor(sensor), 146 | .lighthouse(lighthouse), 147 | .axis(axis), 148 | .angle(angle), 149 | 150 | .data_strobe(data_strobe), 151 | .data(data_out) 152 | ); 153 | 154 | always @(posedge clk_48) 155 | begin 156 | fifo_write_strobe <= 0; 157 | 158 | if (data_strobe) 159 | data <= data_out; 160 | 161 | if (angle_strobe) begin 162 | fifo_write_strobe <= 1; 163 | fifo_write <= { 164 | 4'hA + sensor, 165 | 2'b0, 166 | lighthouse, 167 | axis, 168 | 3'b0, 169 | data, 170 | angle 171 | }; 172 | end 173 | end 174 | 175 | 176 | reg [FIFO_WIDTH-1:0] out; 177 | reg [5:0] out_bytes; 178 | 179 | always @(posedge clk_48) 180 | begin 181 | uart_txd_strobe <= 0; 182 | fifo_read_strobe <= 0; 183 | 184 | // convert timer deltas to hex digits 185 | if (out_bytes != 0) 186 | begin 187 | uart_txd_strobe <= 1; 188 | out_bytes <= out_bytes - 1; 189 | if (out_bytes == 1) 190 | uart_txd <= "\r"; 191 | else 192 | if (out_bytes == 2) 193 | uart_txd <= "\n"; 194 | else 195 | if (out_bytes == 3+4) 196 | uart_txd <= " "; 197 | else begin 198 | uart_txd <= hexdigit(out[FIFO_WIDTH-1:FIFO_WIDTH-4]); 199 | out <= { out[FIFO_WIDTH-5:0], 4'b0 }; 200 | end 201 | 202 | end else 203 | if (fifo_available && !fifo_write_strobe) 204 | begin 205 | out <= fifo_read; 206 | fifo_read_strobe <= 1; 207 | out_bytes <= 2 + 1 + FIFO_WIDTH/4; 208 | end 209 | end 210 | 211 | endmodule 212 | -------------------------------------------------------------------------------- /lighthouse.v: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Interface with a Vive Lighthouse v1 3 | * 4 | * Measure the raw sweep times for the sensor. 5 | * This also reports the lengths of the two sync pulses so that 6 | * the correct axis and OOTX can be assigned. 7 | 8 | Data Data Angle 9 | <-----> <-----><------------> 10 | _____ ________ ___ _____________ ___________ 11 | |_| |_____| |_____| |_| 12 | Sweep Sync0 Sync1 Sweep 13 | 14 | * Sync0 is from lighthouse A, sync1 is from lighthouse B 15 | * 16 | * at 48 MHz every sync pulse is a 512 tick window 17 | * so we only look at the top few bits, 18 | * which encode the skip/data/axis bits: 19 | * 20 | * length = 3072 + axis*512 + data*1024 + skip*2048 21 | * 22 | * This disagrees with https://github.com/nairol/LighthouseRedox/blob/master/docs/Light%20Emissions.md 23 | * but matches what I've seen on my lighthouses. 24 | */ 25 | 26 | /* 27 | * Parse an entire frame and output the angle at 20-bits of resolution 28 | * The strobe goes high when there is a valid sensor reading; axis 29 | * indicates which lighthouse sent it and which rotor on that lighthouse. 30 | * OOTX data contains both lighthouse OOTX bits 31 | */ 32 | module lighthouse_sensor( 33 | input clk, 34 | input reset, 35 | input [SENSORS-1:0] raw_pins, 36 | output angle_strobe, 37 | output [ANGLE_BITS-1:0] angle, 38 | output [SENSOR_BITS-1:0] sensor, 39 | output reg lighthouse, 40 | output reg axis, 41 | output data_strobe, 42 | output data 43 | ); 44 | parameter SENSORS = 1; 45 | parameter SENSOR_BITS = `CLOG2(SENSORS); 46 | parameter WIDTH = 20; 47 | parameter MHZ = 48; 48 | parameter MAX_COUNTER = 20'h80000; 49 | parameter ANGLE_BITS = 20; 50 | 51 | // clock shared between all of the sensors 52 | reg [WIDTH-1:0] counter; 53 | reg [WIDTH-1:0] fall_counter; 54 | reg [WIDTH-1:0] rise_counter; 55 | 56 | // the pulse length encodes information about the lighthouse 57 | // and laser being used 58 | wire skip_raw; 59 | wire data_raw; 60 | wire axis_raw; 61 | wire sync_valid; 62 | lighthouse_sync_decode #(.MHZ(MHZ)) sync_decode( 63 | counter[WIDTH-1:9], skip_raw, data_raw, axis_raw, sync_valid); 64 | 65 | // logical AND all of the raw input pins so that 66 | // any falling edge will be clocked 67 | reg all_sync; 68 | reg all_prev; 69 | wire all_rise = all_sync && !all_prev; 70 | wire all_fall = !all_sync && all_prev; 71 | 72 | // buffer all of the pins with edge capture strobes 73 | reg [SENSORS-1:0] rise_strobe; 74 | reg [SENSORS-1:0] fall_strobe; 75 | 76 | genvar x; 77 | for(x=0 ; x < SENSORS ; x = x + 1) 78 | edge_capture sensors_edge( 79 | .clk(clk), 80 | .reset(reset), 81 | .raw_pin(raw_pins[x]), 82 | .rise_strobe(rise_strobe[x]), 83 | .fall_strobe(fall_strobe[x]) 84 | ); 85 | 86 | // track the rising and falling edge of the entire input array 87 | // for detecting the sync pulses. 88 | // detects if the counter has gone too long, in which case falling 89 | // edge restarts the counter 90 | localparam WAIT_SYNC0_START = 0; 91 | localparam WAIT_SYNC0_END = 1; 92 | localparam WAIT_SYNC1_START = 2; 93 | localparam WAIT_SYNC1_END = 3; 94 | localparam WAIT_SENSORS = 4; 95 | reg [5:0] state; 96 | always @(posedge clk) 97 | begin 98 | // default is no data bit strobe 99 | data_strobe <= 0; 100 | 101 | // buffer the big AND gate 102 | all_prev <= all_sync; 103 | all_sync <= &raw_pins; 104 | 105 | // default is always increment counter 106 | counter <= counter + 1; 107 | 108 | if (reset) begin 109 | counter <= 0; 110 | state <= WAIT_SYNC0_START; 111 | end else 112 | if (counter > MAX_COUNTER) begin 113 | // if we've timed out, reset the FSM 114 | state <= WAIT_SYNC0_START; 115 | end else 116 | case (state) 117 | WAIT_SYNC0_START: if (all_fall) begin 118 | // very first sync bit, restart the counter 119 | counter <= 0; 120 | state <= WAIT_SYNC0_END; 121 | end 122 | WAIT_SYNC0_END: if (all_rise) begin 123 | // end of the first sync bit 124 | // if the length is reasonable, record it and 125 | // move to the next state 126 | if (!sync_valid) begin 127 | state <= WAIT_SYNC0_START; 128 | end else begin 129 | state <= WAIT_SYNC1_START; 130 | if (!skip_raw) begin 131 | // this is the valid output 132 | data <= data_raw; 133 | axis <= axis_raw; 134 | lighthouse <= 0; 135 | data_strobe <= 1; 136 | end 137 | end 138 | end 139 | WAIT_SYNC1_START: if (all_fall) begin 140 | // start of the second sync bit 141 | state <= WAIT_SYNC1_END; 142 | counter <= 0; 143 | end 144 | WAIT_SYNC1_END: if (all_rise) begin 145 | // end of the second sync bit 146 | if (!sync_valid) begin 147 | state <= WAIT_SYNC0_START; 148 | end else begin 149 | state <= WAIT_SENSORS; 150 | counter <= 0; 151 | 152 | if (!skip_raw) begin 153 | data <= data_raw; 154 | axis <= axis_raw; 155 | lighthouse <= 1; 156 | data_strobe <= 1; 157 | end 158 | end 159 | end 160 | WAIT_SENSORS: begin 161 | // do nothing, timeout will eventually happen 162 | end 163 | default: begin 164 | // should never happen 165 | state <= WAIT_SYNC0_START; 166 | end 167 | endcase 168 | end 169 | 170 | // select which sensor has the newest reading 171 | wire [SENSOR_BITS-1:0] sensor; 172 | wire new_sample; 173 | 174 | integer i; 175 | always @(*) 176 | begin 177 | new_sample <= 0; 178 | for(i = 0 ; i < SENSORS ; i++) 179 | begin 180 | if (fall_strobe[i]) begin 181 | sensor <= i; 182 | new_sample <= 1; 183 | end 184 | end 185 | end 186 | 187 | // find the first sensors with a low pin 188 | always @(posedge clk) 189 | begin 190 | angle_strobe <= 0; 191 | 192 | if (reset) begin 193 | // nothing to do 194 | end else 195 | if (state == WAIT_SENSORS && new_sample) begin 196 | // there has been a falling edge of a sensor 197 | angle_strobe <= 1; 198 | angle <= counter; 199 | end 200 | end 201 | endmodule 202 | 203 | module lighthouse_sync_decode( 204 | input [10:0] sync, 205 | output skip, 206 | output data, 207 | output axis, 208 | output valid 209 | ); 210 | parameter MHZ = 48; // we should do something with this 211 | 212 | assign valid = (6 <= sync) && (sync <= 13); 213 | 214 | wire [2:0] type = sync - 6; 215 | assign skip = type[2]; 216 | assign data = type[1]; 217 | assign axis = type[0]; 218 | endmodule 219 | 220 | 221 | module edge_capture( 222 | input clk, 223 | input reset, 224 | input raw_pin, 225 | output rise_strobe, 226 | output fall_strobe 227 | ); 228 | reg pin0; 229 | reg pin1; 230 | reg pin2; 231 | 232 | always @(posedge clk) 233 | begin 234 | // defaults 235 | rise_strobe <= 0; 236 | fall_strobe <= 0; 237 | 238 | // flop the raw pin the ensure stability 239 | pin0 <= raw_pin; 240 | pin1 <= pin0; 241 | pin2 <= pin1; 242 | 243 | if (reset) begin 244 | // nothing to do 245 | end else 246 | if (pin2 != pin1) begin 247 | rise_strobe <= !pin2; 248 | fall_strobe <= pin2; 249 | end 250 | end 251 | 252 | endmodule 253 | -------------------------------------------------------------------------------- /oled-demo.v: -------------------------------------------------------------------------------- 1 | `include "util.v" 2 | `include "usb_uart.v" 3 | `include "oled.v" 4 | 5 | /* 6 | * Connect a WEH001602A OLED Character 16x2 to the TinyFPGA 7 | * 8 | * 1 Gnd 9 | * 2 Vcc (3.3v) 10 | * 3 NC 11 | * 4 RS 12 | * 5 R/!W 13 | * 6 E 14 | * 7 DB0 15 | * 8 DB1 16 | * 9 DB2 17 | * 10 DB3 18 | * 11 DB4 19 | * 12 DB5 20 | * 13 DB6 21 | * 14 DB7 22 | * 15 NC (button?) 23 | * 16 NC (button?) 24 | * 25 | * Write mode timing should be fine for a 6 Mhz clock: 26 | * 27 | * Tc Enable Cycle Time (E) 1200 ns (0.8 mhz) 28 | * Tpw Enable Pulse Width (E) 140 ns (7 mhz) 29 | * Tas Address setup time RS/RW/E 0ns 30 | * Tah Address hold times RS/RW/E 10 ns (100 mhz) 31 | * Tdsw Data setup time DB0-DB8 40 ns (50 mhz) 32 | * Th Data hold time DB0-DB7 10 ns (100 mhz) 33 | */ 34 | module top( 35 | input pin_clk, 36 | output pin_led, 37 | 38 | // physical layer 39 | inout pin_usbp, 40 | inout pin_usbn, 41 | output pin_pu, 42 | 43 | output pin_1, // rs 44 | output pin_2, // r 45 | output pin_3, // e 46 | inout pin_4, // db0 47 | inout pin_5, // db1 48 | inout pin_6, // db2 49 | inout pin_7, // db3 50 | inout pin_8, // db4 51 | inout pin_9, // db5 52 | inout pin_10, // db6 53 | inout pin_11 // db7 54 | ); 55 | wire clk_48mhz, locked; 56 | wire reset; 57 | pll pll_inst(pin_clk, clk_48mhz, locked); 58 | 59 | // generate a 2 MHz clock from the 16 MHz input 60 | wire clk_24mhz, clk_12mhz, clk_6mhz, clk_3mhz, clk_1mhz; 61 | wire clk_500khz, clk_250khz, clk_100khz; 62 | always @(posedge clk_48mhz) clk_24mhz = !clk_24mhz; 63 | always @(posedge clk_24mhz) clk_12mhz = !clk_12mhz; 64 | always @(posedge clk_12mhz) clk_6mhz = !clk_6mhz; 65 | always @(posedge clk_6mhz) clk_3mhz = !clk_3mhz; 66 | always @(posedge clk_3mhz) clk_1mhz = !clk_1mhz; 67 | always @(posedge clk_1mhz) clk_500khz = !clk_500khz; 68 | always @(posedge clk_500khz) clk_250khz = !clk_250khz; 69 | always @(posedge clk_250khz) clk_100khz = !clk_100khz; 70 | wire clk = clk_24mhz; 71 | 72 | reg [15:0] reset_counter; 73 | always @(posedge clk) begin 74 | if (!locked) begin 75 | reset <= 1; 76 | reset_counter <= 0; 77 | end else 78 | if (&reset_counter) begin 79 | reset <= 0; 80 | end else 81 | reset_counter <= reset_counter + 1; 82 | end 83 | 84 | 85 | // verilog sucks 86 | parameter ROWS = 80; 87 | reg [15:0] bitmap[ROWS-1:0]; 88 | initial $readmemh("bitmap.hex", bitmap); 89 | 90 | reg [7:0] rx_offset; 91 | wire [7:0] row; 92 | 93 | // read data from the serial port into the frame buffer 94 | reg [7:0] tx_data; 95 | reg tx_strobe = 0; 96 | wire [7:0] rx_data; 97 | wire rx_strobe; 98 | 99 | usb_uart uart( 100 | .clk(clk), 101 | .clk_48mhz(clk_48mhz), 102 | .reset(reset), 103 | .pin_usbp(pin_usbp), 104 | .pin_usbn(pin_usbn), 105 | .pin_pu(pin_pu), 106 | .rx_data(rx_data), 107 | .rx_strobe(rx_strobe), 108 | .tx_data(tx_data), 109 | .tx_strobe(tx_strobe) 110 | ); 111 | 112 | always @(posedge clk) if (!reset) begin 113 | if (rx_strobe) 114 | begin 115 | pin_led <= !pin_led;; 116 | 117 | if (rx_offset[0]) 118 | bitmap[rx_offset[7:1]][7:0] <= rx_data; 119 | else 120 | bitmap[rx_offset[7:1]][15:8] <= rx_data; 121 | 122 | if (rx_offset == 2*ROWS-1) 123 | rx_offset <= 0; 124 | else 125 | rx_offset <= rx_offset + 1; 126 | end 127 | end 128 | 129 | oled_graphics #(.ROWS(ROWS)) oled( 130 | .clk(clk), 131 | .reset(reset), 132 | 133 | // physical connection 134 | .rs_pin(pin_1), 135 | .read_pin(pin_2), 136 | .enable_pin(pin_3), 137 | .db_pins({ 138 | pin_11, 139 | pin_10, 140 | pin_9, 141 | pin_8, 142 | pin_7, 143 | pin_6, 144 | pin_5, 145 | pin_4 146 | }), 147 | 148 | .row(row), 149 | .pixels(bitmap[row]), 150 | ); 151 | endmodule 152 | 153 | 154 | /** 155 | * PLL configuration 156 | * 157 | * This Verilog module was generated automatically 158 | * using the icepll tool from the IceStorm project. 159 | * Use at your own risk. 160 | * 161 | * Given input frequency: 16.000 MHz 162 | * Requested output frequency: 48.000 MHz 163 | * Achieved output frequency: 48.000 MHz 164 | */ 165 | 166 | module pll( 167 | input clock_in, 168 | output clock_out, 169 | output locked 170 | ); 171 | 172 | SB_PLL40_CORE #( 173 | .FEEDBACK_PATH("SIMPLE"), 174 | .DIVR(4'b0000), // DIVR = 0 175 | .DIVF(7'b0101111), // DIVF = 47 176 | .DIVQ(3'b100), // DIVQ = 4 177 | .FILTER_RANGE(3'b001) // FILTER_RANGE = 1 178 | ) uut ( 179 | .LOCK(locked), 180 | .RESETB(1'b1), 181 | .BYPASS(1'b0), 182 | .REFERENCECLK(clock_in), 183 | .PLLOUTCORE(clock_out) 184 | ); 185 | 186 | endmodule 187 | -------------------------------------------------------------------------------- /oled.v: -------------------------------------------------------------------------------- 1 | `ifndef oled_v 2 | `define oled_v 3 | 4 | /* 5 | * Connect a WEH001602A OLED Character 16x2 to the TinyFPGA 6 | * 7 | * 1 Gnd 8 | * 2 Vcc (3.3v) 9 | * 3 NC 10 | * 4 RS 11 | * 5 R/!W 12 | * 6 E 13 | * 7 DB0 14 | * 8 DB1 15 | * 9 DB2 16 | * 10 DB3 17 | * 11 DB4 18 | * 12 DB5 19 | * 13 DB6 20 | * 14 DB7 21 | * 15 NC (button?) 22 | * 16 NC (button?) 23 | * 24 | * Write mode timing should be fine for a 6 Mhz clock: 25 | * 26 | * Tc Enable Cycle Time (E) 1200 ns (0.8 mhz) 27 | * Tpw Enable Pulse Width (E) 140 ns (7 mhz) 28 | * Tas Address setup time RS/RW/E 0ns 29 | * Tah Address hold times RS/RW/E 10 ns (100 mhz) 30 | * Tdsw Data setup time DB0-DB8 40 ns (50 mhz) 31 | * Th Data hold time DB0-DB7 10 ns (100 mhz) 32 | */ 33 | 34 | module oled_graphics( 35 | input clk, 36 | input reset, 37 | 38 | // physical connection 39 | inout [7:0] db_pins, 40 | output read_pin, 41 | output enable_pin, 42 | output rs_pin, 43 | 44 | output [7:0] row, 45 | input [15:0] pixels 46 | ); 47 | parameter ROWS = 80; 48 | 49 | wire oled_ready; 50 | reg [8:0] oled_cmd; 51 | reg oled_strobe; 52 | reg oled_wait; 53 | 54 | oled oled_inst( 55 | .clk(clk), 56 | .reset(reset), 57 | 58 | // physical connection 59 | .rs_pin(rs_pin), 60 | .read_pin(read_pin), 61 | .enable_pin(enable_pin), 62 | .db_pins(db_pins), 63 | 64 | // commands 65 | .ready(oled_ready), 66 | .command(oled_cmd), 67 | .strobe(oled_strobe), 68 | .wait_for_busy(oled_wait) 69 | ); 70 | 71 | localparam INIT0 = 0; 72 | localparam INIT1 = 1; 73 | localparam INIT2 = 2; 74 | localparam INIT3 = 3; 75 | localparam INIT4 = 4; 76 | localparam INIT5 = 5; 77 | localparam DRAW_X = 6; 78 | localparam DRAW_Y = 7; 79 | localparam DRAW_BITS = 8; 80 | 81 | reg [3:0] state = INIT0; 82 | 83 | reg col; 84 | 85 | always @(posedge clk) 86 | begin 87 | oled_strobe <= 0; 88 | 89 | if (reset) 90 | begin 91 | state <= INIT0; 92 | col <= 0; 93 | row <= 0; 94 | end else 95 | if (oled_ready && !oled_strobe) 96 | case (state) 97 | INIT0: begin 98 | // function set 99 | oled_cmd <= { 100 | 1'b0, // rs 101 | 3'b001, 102 | 1'b1, // 8-bit data length 103 | 1'b1, // two lines 104 | 1'b0, // first font 105 | 2'b00 // font table 0 106 | }; 107 | oled_wait <= 1; 108 | oled_strobe <= 1; 109 | state <= INIT1; 110 | end 111 | INIT1: begin 112 | // display on/off control 113 | oled_cmd <= { 114 | 1'b0, // rs 115 | 5'b00001, 116 | 1'b1, // entire display on 117 | 1'b0, // no cursor 118 | 1'b0 // no blink 119 | }; 120 | oled_wait <= 1; 121 | oled_strobe <= 1; 122 | state <= INIT2; 123 | end 124 | INIT2: begin 125 | // display clear 126 | oled_cmd <= 9'b000000001; 127 | oled_wait <= 1; 128 | oled_strobe <= 1; 129 | state <= INIT3; 130 | end 131 | INIT3: begin 132 | // entry mode set 133 | oled_cmd <= { 134 | 1'b0, // rs 135 | 6'b000001, 136 | 1'b1, // increment on every write 137 | 1'b0 // no display shift 138 | }; 139 | oled_wait <= 1; 140 | oled_strobe <= 1; 141 | state <= INIT4; 142 | end 143 | INIT4: begin 144 | // power on 145 | oled_cmd <= { 146 | 1'b0, // rs 147 | 4'b0001, 148 | 1'b0, // character mode 149 | 1'b1, // power on mode 150 | 1'b1, // 151 | 1'b1 // 152 | }; 153 | oled_wait <= 1; 154 | oled_strobe <= 1; 155 | state <= INIT5; 156 | end 157 | INIT5: begin 158 | // enable graphics mode as the last thing 159 | // before drawing (otherwise it won't "stick") 160 | oled_cmd <= { 161 | 1'b0, // rs 162 | 4'b0001, 163 | 1'b1, // graphics mode 164 | 1'b1, // power on mode 165 | 1'b1, // 166 | 1'b1 // 167 | }; 168 | oled_wait <= 1; 169 | oled_strobe <= 1; 170 | state <= DRAW_Y; 171 | end 172 | DRAW_Y: begin 173 | // Y position is controlled by CGRAM 174 | oled_cmd <= { 175 | 1'b0,// register 176 | 6'b0100000, 177 | col 178 | }; 179 | oled_strobe <= 1; 180 | oled_wait <= 0; 181 | state <= DRAW_X; 182 | end 183 | DRAW_X: begin 184 | // X position is controlled by DDRAM 185 | oled_cmd <= { 186 | 1'b0, // register 187 | 1'b1, 188 | 7'b0 // go back to the first column 189 | }; 190 | oled_strobe <= 1; 191 | oled_wait <= 0; 192 | state <= DRAW_BITS; 193 | end 194 | DRAW_BITS: begin 195 | oled_wait <= 0; 196 | oled_cmd <= { 197 | 1'b1, // data 198 | col ? pixels[8:15] : pixels[0:7] 199 | }; 200 | oled_strobe <= 1; 201 | 202 | if (row == ROWS-1) begin 203 | col <= !col; 204 | row <= 0; 205 | state <= DRAW_Y; 206 | end else begin 207 | row <= row + 1; 208 | end 209 | end 210 | endcase 211 | end 212 | endmodule 213 | 214 | 215 | module oled( 216 | input clk, 217 | input reset, 218 | output debug, 219 | 220 | // physical connection 221 | inout [7:0] db_pins, 222 | output read_pin, 223 | output enable_pin, 224 | output rs_pin, 225 | 226 | // command input (rs and 8 bits of data) 227 | output ready, 228 | input wait_for_busy, 229 | input [8:0] command, 230 | input strobe 231 | ); 232 | reg read; 233 | reg enable; 234 | reg rs; 235 | 236 | assign read_pin = read; 237 | assign enable_pin = enable; 238 | assign rs_pin = rs; 239 | 240 | // only enable to output pins when we are in write mode 241 | wire [7:0] db_in; 242 | reg [7:0] db_out = 0; 243 | SB_IO #( 244 | .PIN_TYPE(6'b1010_01) // tristatable output 245 | ) db_buffer[7:0] ( 246 | .OUTPUT_ENABLE(!read), 247 | .PACKAGE_PIN(db_pins), 248 | .D_IN_0(db_in), 249 | .D_OUT_0(db_out) 250 | ); 251 | 252 | localparam IDLE = 0; 253 | localparam SEND_CMD1 = 1; 254 | localparam SEND_CMD2 = 2; 255 | localparam WAIT_BUSY = 4; 256 | localparam WAIT_BUSY1 = 5; 257 | localparam WAIT_BUSY2 = 6; 258 | localparam WAIT_BUSY3 = 7; 259 | 260 | reg [3:0] state = WAIT_BUSY; 261 | assign ready = state == IDLE; 262 | 263 | always @(posedge clk) 264 | begin 265 | if (reset) begin 266 | state <= WAIT_BUSY; 267 | end else 268 | case (state) 269 | IDLE: begin 270 | debug <= 0; 271 | rs <= 0; 272 | read <= 1; 273 | enable <= 0; 274 | 275 | if (strobe) begin 276 | // start a new write 277 | read <= 0; 278 | rs <= command[8]; 279 | db_out <= command[7:0]; 280 | state <= SEND_CMD1; 281 | end 282 | end 283 | SEND_CMD1: begin 284 | // data should be stable by now 285 | enable <= 1; 286 | state <= SEND_CMD2; 287 | end 288 | SEND_CMD2: begin 289 | // LCD clocks in data on this falling edge 290 | enable <= 0; 291 | if (wait_for_busy) 292 | state <= WAIT_BUSY; 293 | else 294 | state <= IDLE; 295 | end 296 | WAIT_BUSY: begin 297 | // reset for a status read command 298 | enable <= 0; 299 | read <= 1; 300 | rs <= 0; 301 | state <= WAIT_BUSY1; 302 | end 303 | WAIT_BUSY1: begin 304 | enable <= 1; 305 | state <= WAIT_BUSY2; 306 | end 307 | WAIT_BUSY2: begin 308 | enable <= 0; 309 | state <= WAIT_BUSY1; 310 | 311 | // if the LCD signals no longer busy, we're done 312 | if (!db_in[7]) 313 | state <= IDLE; 314 | end 315 | endcase 316 | end 317 | endmodule 318 | 319 | `endif 320 | -------------------------------------------------------------------------------- /packed0.hex: -------------------------------------------------------------------------------- 1 | 07de 2 | 0f9e 3 | 175e 4 | 1f1e 5 | 26de 6 | 2e9e 7 | 365e 8 | 3e1e 9 | 45de 10 | 4d9e 11 | 555e 12 | 5d1e 13 | 64de 14 | 6c9e 15 | 745e 16 | 7c1e 17 | 83de 18 | 8b9e 19 | 935e 20 | 9b1e 21 | a2de 22 | aa9e 23 | b25e 24 | ba1e 25 | c1de 26 | c99e 27 | d15e 28 | d91e 29 | e0de 30 | e89e 31 | f05e 32 | f81e 33 | 07dc 34 | 0f9c 35 | 175c 36 | 1f1c 37 | 26dc 38 | 2e9c 39 | 365c 40 | 3e1c 41 | 45dc 42 | 4d9c 43 | 555c 44 | 5d1c 45 | 64dc 46 | 6c9c 47 | 745c 48 | 7c1c 49 | 83dc 50 | 8b9c 51 | 935c 52 | 9b1c 53 | a2dc 54 | aa9c 55 | b25c 56 | ba1c 57 | c1dc 58 | c99c 59 | d15c 60 | d91c 61 | e0dc 62 | e89c 63 | f05c 64 | f81c 65 | 07da 66 | 0f9a 67 | 175a 68 | 1f1a 69 | 26da 70 | 2e9a 71 | 365a 72 | 3e1a 73 | 45da 74 | 4d9a 75 | 555a 76 | 5d1a 77 | 64da 78 | 6c9a 79 | 745a 80 | 7c1a 81 | 83da 82 | 8b9a 83 | 935a 84 | 9b1a 85 | a2da 86 | aa9a 87 | b25a 88 | ba1a 89 | c1da 90 | c99a 91 | d15a 92 | d91a 93 | e0da 94 | e89a 95 | f05a 96 | f81a 97 | 07d8 98 | 0f98 99 | 1758 100 | 1f18 101 | 26d8 102 | 2e98 103 | 3658 104 | 3e18 105 | 45d8 106 | 4d98 107 | 5558 108 | 5d18 109 | 64d8 110 | 6c98 111 | 7458 112 | 7c18 113 | 83d8 114 | 8b98 115 | 9358 116 | 9b18 117 | a2d8 118 | aa98 119 | b258 120 | ba18 121 | c1d8 122 | c998 123 | d158 124 | d918 125 | e0d8 126 | e898 127 | f058 128 | f818 129 | 07d6 130 | 0f96 131 | 1756 132 | 1f16 133 | 26d6 134 | 2e96 135 | 3656 136 | 3e16 137 | 45d6 138 | 4d96 139 | 5556 140 | 5d16 141 | 64d6 142 | 6c96 143 | 7456 144 | 7c16 145 | 83d6 146 | 8b96 147 | 9356 148 | 9b16 149 | a2d6 150 | aa96 151 | b256 152 | ba16 153 | c1d6 154 | c996 155 | d156 156 | d916 157 | e0d6 158 | e896 159 | f056 160 | f816 161 | 07d4 162 | 0f94 163 | 1754 164 | 1f14 165 | 26d4 166 | 2e94 167 | 3654 168 | 3e14 169 | 45d4 170 | 4d94 171 | 5554 172 | 5d14 173 | 64d4 174 | 6c94 175 | 7454 176 | 7c14 177 | 83d4 178 | 8b94 179 | 9354 180 | 9b14 181 | a2d4 182 | aa94 183 | b254 184 | ba14 185 | c1d4 186 | c994 187 | d154 188 | d914 189 | e0d4 190 | e894 191 | f054 192 | f814 193 | 07d2 194 | 0f92 195 | 1752 196 | 1f12 197 | 26d2 198 | 2e92 199 | 3652 200 | 3e12 201 | 45d2 202 | 4d92 203 | 5552 204 | 5d12 205 | 64d2 206 | 6c92 207 | 7452 208 | 7c12 209 | 83d2 210 | 8b92 211 | 9352 212 | 9b12 213 | a2d2 214 | aa92 215 | b252 216 | ba12 217 | c1d2 218 | c992 219 | d152 220 | d912 221 | e0d2 222 | e892 223 | f052 224 | f812 225 | 07d0 226 | 0f90 227 | 1750 228 | 1f10 229 | 26d0 230 | 2e90 231 | 3650 232 | 3e10 233 | 45d0 234 | 4d90 235 | 5550 236 | 5d10 237 | 64d0 238 | 6c90 239 | 7450 240 | 7c10 241 | 83d0 242 | 8b90 243 | 9350 244 | 9b10 245 | a2d0 246 | aa90 247 | b250 248 | ba10 249 | c1d0 250 | c990 251 | d150 252 | d910 253 | e0d0 254 | e890 255 | f050 256 | f810 257 | -------------------------------------------------------------------------------- /packed1.hex: -------------------------------------------------------------------------------- 1 | 07ce 2 | 0f8e 3 | 174e 4 | 1f0e 5 | 26ce 6 | 2e8e 7 | 364e 8 | 3e0e 9 | 45ce 10 | 4d8e 11 | 554e 12 | 5d0e 13 | 64ce 14 | 6c8e 15 | 744e 16 | 7c0e 17 | 83ce 18 | 8b8e 19 | 934e 20 | 9b0e 21 | a2ce 22 | aa8e 23 | b24e 24 | ba0e 25 | c1ce 26 | c98e 27 | d14e 28 | d90e 29 | e0ce 30 | e88e 31 | f04e 32 | f80e 33 | 07cc 34 | 0f8c 35 | 174c 36 | 1f0c 37 | 26cc 38 | 2e8c 39 | 364c 40 | 3e0c 41 | 45cc 42 | 4d8c 43 | 554c 44 | 5d0c 45 | 64cc 46 | 6c8c 47 | 744c 48 | 7c0c 49 | 83cc 50 | 8b8c 51 | 934c 52 | 9b0c 53 | a2cc 54 | aa8c 55 | b24c 56 | ba0c 57 | c1cc 58 | c98c 59 | d14c 60 | d90c 61 | e0cc 62 | e88c 63 | f04c 64 | f80c 65 | 07ca 66 | 0f8a 67 | 174a 68 | 1f0a 69 | 26ca 70 | 2e8a 71 | 364a 72 | 3e0a 73 | 45ca 74 | 4d8a 75 | 554a 76 | 5d0a 77 | 64ca 78 | 6c8a 79 | 744a 80 | 7c0a 81 | 83ca 82 | 8b8a 83 | 934a 84 | 9b0a 85 | a2ca 86 | aa8a 87 | b24a 88 | ba0a 89 | c1ca 90 | c98a 91 | d14a 92 | d90a 93 | e0ca 94 | e88a 95 | f04a 96 | f80a 97 | 07c8 98 | 0f88 99 | 1748 100 | 1f08 101 | 26c8 102 | 2e88 103 | 3648 104 | 3e08 105 | 45c8 106 | 4d88 107 | 5548 108 | 5d08 109 | 64c8 110 | 6c88 111 | 7448 112 | 7c08 113 | 83c8 114 | 8b88 115 | 9348 116 | 9b08 117 | a2c8 118 | aa88 119 | b248 120 | ba08 121 | c1c8 122 | c988 123 | d148 124 | d908 125 | e0c8 126 | e888 127 | f048 128 | f808 129 | 07c6 130 | 0f86 131 | 1746 132 | 1f06 133 | 26c6 134 | 2e86 135 | 3646 136 | 3e06 137 | 45c6 138 | 4d86 139 | 5546 140 | 5d06 141 | 64c6 142 | 6c86 143 | 7446 144 | 7c06 145 | 83c6 146 | 8b86 147 | 9346 148 | 9b06 149 | a2c6 150 | aa86 151 | b246 152 | ba06 153 | c1c6 154 | c986 155 | d146 156 | d906 157 | e0c6 158 | e886 159 | f046 160 | f806 161 | 07c4 162 | 0f84 163 | 1744 164 | 1f04 165 | 26c4 166 | 2e84 167 | 3644 168 | 3e04 169 | 45c4 170 | 4d84 171 | 5544 172 | 5d04 173 | 64c4 174 | 6c84 175 | 7444 176 | 7c04 177 | 83c4 178 | 8b84 179 | 9344 180 | 9b04 181 | a2c4 182 | aa84 183 | b244 184 | ba04 185 | c1c4 186 | c984 187 | d144 188 | d904 189 | e0c4 190 | e884 191 | f044 192 | f804 193 | 07c2 194 | 0f82 195 | 1742 196 | 1f02 197 | 26c2 198 | 2e82 199 | 3642 200 | 3e02 201 | 45c2 202 | 4d82 203 | 5542 204 | 5d02 205 | 64c2 206 | 6c82 207 | 7442 208 | 7c02 209 | 83c2 210 | 8b82 211 | 9342 212 | 9b02 213 | a2c2 214 | aa82 215 | b242 216 | ba02 217 | c1c2 218 | c982 219 | d142 220 | d902 221 | e0c2 222 | e882 223 | f042 224 | f802 225 | 07c0 226 | 0f80 227 | 1740 228 | 1f00 229 | 26c0 230 | 2e80 231 | 3640 232 | 3e00 233 | 45c0 234 | 4d80 235 | 5540 236 | 5d00 237 | 64c0 238 | 6c80 239 | 7440 240 | 7c00 241 | 83c0 242 | 8b80 243 | 9340 244 | 9b00 245 | a2c0 246 | aa80 247 | b240 248 | ba00 249 | c1c0 250 | c980 251 | d140 252 | d900 253 | e0c0 254 | e880 255 | f040 256 | f800 257 | -------------------------------------------------------------------------------- /pulse.v: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Demo the pulsing LED on the upduino v2 3 | * 4 | * Note that the LED pins are inverted, so 0 is on 5 | */ 6 | `include "util.v" 7 | 8 | module top( 9 | output led_r, 10 | output led_g, 11 | output led_b 12 | ); 13 | wire clk_48; 14 | SB_HFOSC u_hfosc ( 15 | .CLKHFPU(1'b1), 16 | .CLKHFEN(1'b1), 17 | .CLKHF(clk_48) 18 | ); 19 | 20 | reg [31:0] counter; 21 | 22 | always @(posedge clk_48) 23 | counter <= counter + 1; 24 | 25 | wire [7:0] bright_r; 26 | wire [7:0] bright_b; 27 | always @(*) 28 | if (counter[28]) begin 29 | bright_r = counter[27:20]; 30 | bright_b = 255 - counter[27:20]; 31 | end else begin 32 | bright_r = 255 - counter[27:20]; 33 | bright_b = counter[27:20]; 34 | end 35 | 36 | assign led_g = 1; 37 | 38 | pwm pwm_r( 39 | .clk(clk_48), 40 | .bright(bright_r), 41 | .out(led_r) 42 | ); 43 | 44 | pwm pwm_b( 45 | .clk(clk_48), 46 | .bright(bright_b), 47 | .out(led_b) 48 | ); 49 | 50 | endmodule 51 | -------------------------------------------------------------------------------- /serial-echo.v: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Test the serial input/output to the FTDI chip. 3 | * 4 | * This configures the serial port at 3 Mb/s and directly routes 5 | * the incoming data to the outbound serial port. 6 | * 7 | * The schematic disagrees with the PCF, but the PCF works... 8 | * 9 | * The SPI flash chip select *MUST* be pulled high to disable the 10 | * flash chip, otherwise they will both be driving the bus. 11 | */ 12 | `include "util.v" 13 | `include "uart.v" 14 | 15 | module top( 16 | output led_r, 17 | output led_g, 18 | output led_b, 19 | output serial_txd, 20 | input serial_rxd, 21 | output spi_cs, 22 | output gpio_2 23 | ); 24 | assign spi_cs = 1; // it is necessary to turn off the SPI flash chip 25 | wire debug0 = gpio_2; 26 | 27 | wire clk_48; 28 | wire reset = 0; 29 | SB_HFOSC u_hfosc ( 30 | .CLKHFPU(1'b1), 31 | .CLKHFEN(1'b1), 32 | .CLKHF(clk_48) 33 | ); 34 | 35 | // pulse the green LED to know that we're alive 36 | reg [31:0] counter; 37 | always @(posedge clk_48) 38 | counter <= counter + 1; 39 | wire pwm_g; 40 | pwm pwm_g_driver(clk_48, 1, pwm_g); 41 | assign led_g = !(counter[25:23] == 0 && pwm_g); 42 | 43 | assign led_b = serial_rxd; // idles high 44 | assign led_r = serial_txd; // idles high 45 | assign debug0 = serial_txd; 46 | 47 | // generate a 3 MHz/12 MHz serial clock from the 48 MHz clock 48 | // this is the 3 Mb/s maximum supported by the FTDI chip 49 | wire clk_1, clk_4; 50 | divide_by_n #(.N(16)) div1(clk_48, reset, clk_1); 51 | divide_by_n #(.N( 4)) div4(clk_48, reset, clk_4); 52 | 53 | wire [7:0] uart_rxd; 54 | wire uart_rxd_strobe; 55 | 56 | uart_tx txd( 57 | .mclk(clk_48), 58 | .reset(reset), 59 | .baud_x1(clk_1), 60 | .serial(serial_txd), 61 | .data(uart_rxd), 62 | .data_strobe(uart_rxd_strobe) 63 | ); 64 | 65 | uart_rx rxd( 66 | .mclk(clk_48), 67 | .reset(reset), 68 | .baud_x4(clk_4), 69 | .serial(serial_rxd), 70 | .data(uart_rxd), 71 | .data_strobe(uart_rxd_strobe) 72 | ); 73 | 74 | endmodule 75 | -------------------------------------------------------------------------------- /serial-hexdump.v: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Print a hexdump of the incoming serial data. 3 | * 4 | * The up5k has 1024 Kb of single ported block RAM. 5 | * This is can't read/write simultaneously, so it is necessary to 6 | * mux the read/write pins. 7 | * 8 | * This tests the 16to8 fifo, which allows us to enqueue two characters 9 | * at a time into the tx fifo, perfect for hexdumps. 10 | */ 11 | `include "util.v" 12 | `include "uart.v" 13 | `include "spram.v" 14 | 15 | module top( 16 | output led_r, 17 | output led_g, 18 | output led_b, 19 | output serial_txd, 20 | input serial_rxd, 21 | output spi_cs, 22 | output gpio_2, 23 | ); 24 | assign spi_cs = 1; // it is necessary to turn off the SPI flash chip 25 | wire debug0 = gpio_2; 26 | 27 | wire clk_48; 28 | wire reset = 0; 29 | SB_HFOSC u_hfosc ( 30 | .CLKHFPU(1'b1), 31 | .CLKHFEN(1'b1), 32 | .CLKHF(clk_48) 33 | ); 34 | 35 | reg [31:0] counter; 36 | always @(posedge clk_48) 37 | counter <= counter + 1; 38 | 39 | // pulse the green LED to know that we're alive 40 | wire pwm_g; 41 | pwm pwm_g_driver(clk_48, 1, pwm_g); 42 | assign led_g = !(counter[25:23] == 0 && pwm_g); 43 | 44 | assign led_b = serial_rxd; // idles high 45 | 46 | // generate a 3 MHz/12 MHz serial clock from the 48 MHz clock 47 | // this is the 3 Mb/s maximum supported by the FTDI chip 48 | wire clk_1, clk_4; 49 | divide_by_n #(.N(16)) div1(clk_48, reset, clk_1); 50 | divide_by_n #(.N( 4)) div4(clk_48, reset, clk_4); 51 | 52 | reg [7:0] uart_txd; 53 | reg uart_txd_strobe; 54 | wire uart_txd_ready; 55 | 56 | wire [7:0] uart_rxd; 57 | wire uart_rxd_strobe; 58 | 59 | uart_tx txd( 60 | .mclk(clk_48), 61 | .reset(reset), 62 | .baud_x1(clk_1), 63 | .serial(serial_txd), 64 | .ready(uart_txd_ready), 65 | .data(uart_txd), 66 | .data_strobe(uart_txd_strobe) 67 | ); 68 | 69 | uart_rx rxd( 70 | .mclk(clk_48), 71 | .reset(reset), 72 | .baud_x4(clk_4), 73 | .serial(serial_rxd), 74 | .data(uart_rxd), 75 | .data_strobe(uart_rxd_strobe) 76 | ); 77 | 78 | assign debug0 = serial_txd; 79 | 80 | reg fifo_read_strobe; 81 | wire fifo_available; 82 | 83 | fifo_spram_16to8 buffer( 84 | .clk(clk_48), 85 | .reset(reset), 86 | .write_data({ hexdigit(uart_rxd[7:4]), hexdigit(uart_rxd[3:0]) }), 87 | .write_strobe(uart_rxd_strobe), 88 | .data_available(fifo_available), 89 | .read_data(uart_txd), 90 | .read_strobe(fifo_read_strobe) 91 | ); 92 | 93 | always @(posedge clk_48) begin 94 | uart_txd_strobe <= 0; 95 | fifo_read_strobe <= 0; 96 | led_r <= 1; 97 | 98 | // single port fifo can't read/write the same cycle 99 | if (fifo_available 100 | && uart_txd_ready 101 | && !uart_rxd_strobe 102 | && !uart_txd_strobe 103 | ) begin 104 | fifo_read_strobe <= 1; 105 | uart_txd_strobe <= 1; 106 | led_r <= 0; 107 | end 108 | end 109 | endmodule 110 | -------------------------------------------------------------------------------- /serial.v: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Test the serial output to the FTDI cable. 3 | * 4 | * The schematic disagrees with the PCF, but the PCF works... 5 | * 6 | * The SPI flash chip select *MUST* be pulled high to disable the 7 | * flash chip, otherwise they will both be driving the bus. 8 | * 9 | * This may interfere with programming; `iceprog -e 128` should erase enough 10 | * to make it compliant for re-programming 11 | * 12 | * The USB port will have to be cycled to get the FTDI to renumerate as 13 | * /dev/ttyUSB0. Not sure what is going on with iceprog. 14 | */ 15 | `include "util.v" 16 | `include "uart.v" 17 | 18 | module top( 19 | output led_r, 20 | output led_g, 21 | output led_b, 22 | output serial_txd, 23 | input serial_rxd, 24 | output spi_cs, 25 | output gpio_2 26 | ); 27 | assign spi_cs = 1; // it is necessary to turn off the SPI flash chip 28 | wire debug0 = gpio_2; 29 | 30 | wire clk_48; 31 | wire reset = 0; 32 | SB_HFOSC u_hfosc ( 33 | .CLKHFPU(1'b1), 34 | .CLKHFEN(1'b1), 35 | .CLKHF(clk_48) 36 | ); 37 | 38 | reg [31:0] counter; 39 | 40 | always @(posedge clk_48) 41 | if (reset) 42 | counter <= 0; 43 | else 44 | counter <= counter + 1; 45 | 46 | assign led_g = 1; 47 | assign led_b = serial_rxd; // idles high 48 | 49 | // generate a 1 MHz serial clock from the 48 MHz clock 50 | wire clk_1; 51 | divide_by_n #(.N(48)) div(clk_48, reset, clk_1); 52 | 53 | reg [7:0] uart_txd; 54 | reg uart_txd_strobe; 55 | wire uart_txd_ready; 56 | 57 | uart_tx txd( 58 | .mclk(clk_48), 59 | .reset(reset), 60 | .baud_x1(clk_1), 61 | .serial(serial_txd), 62 | .ready(uart_txd_ready), 63 | .data(uart_txd), 64 | .data_strobe(uart_txd_strobe) 65 | ); 66 | 67 | assign debug0 = serial_txd; 68 | reg [3:0] byte_counter; 69 | 70 | always @(posedge clk_48) begin 71 | led_r <= 1; 72 | uart_txd_strobe <= 0; 73 | 74 | if (reset) begin 75 | // nothing 76 | byte_counter <= 0; 77 | end else 78 | if (uart_txd_ready && !uart_txd_strobe && counter[14:0] == 0) begin 79 | // ready to send a new byte 80 | uart_txd_strobe <= 1; 81 | 82 | if (byte_counter == 0) 83 | uart_txd <= "\r"; 84 | else 85 | if (byte_counter == 1) 86 | uart_txd <= "\n"; 87 | else 88 | uart_txd <= "A" + byte_counter - 2; 89 | byte_counter <= byte_counter + 1; 90 | led_r <= 0; 91 | end 92 | end 93 | endmodule 94 | -------------------------------------------------------------------------------- /spi_device.v: -------------------------------------------------------------------------------- 1 | /* 2 | * spi_device.v: Emulates a SPI device in "slave" mode 3 | * 4 | * based on scanlime's spi_mem_emu.v - Module for an SPI memory emulator. 5 | * 6 | * Portions Copyright (C) 2018 Trammell Hudson 7 | * Portions Copyright (C) 2009 Micah Dowty 8 | * 9 | * Permission is hereby granted, free of charge, to any person obtaining a copy 10 | * of this software and associated documentation files (the "Software"), to deal 11 | * in the Software without restriction, including without limitation the rights 12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | * copies of the Software, and to permit persons to whom the Software is 14 | * furnished to do so, subject to the following conditions: 15 | * 16 | * The above copyright notice and this permission notice shall be included in 17 | * all copies or substantial portions of the Software. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | * THE SOFTWARE. 26 | */ 27 | 28 | 29 | module spi_device( 30 | input mclk, 31 | input reset, 32 | input spi_cs, // active low 33 | input spi_clk, 34 | input spi_mosi, // should be inout for dual/quad 35 | input spi_miso_in, // input from the bus for monitor mode 36 | output spi_miso_out, // output to the SPI bus for driving mode 37 | output reg spi_rx_strobe, 38 | output reg [7:0] spi_rx_data, // should be 32 bits for quad 39 | input spi_tx_strobe, 40 | input [7:0] spi_tx_data, // should be 32 bits for quad 41 | output reg [7:0] spi_mon_data // if we are in monitor mode 42 | ); 43 | 44 | wire spi_clk_sync, spi_mosi_sync, spi_miso_sync, spi_cs_sync; 45 | reg spi_clk_prev; 46 | wire spi_clk_posedge = spi_clk_sync && !spi_clk_prev; 47 | wire spi_clk_negedge = !spi_clk_sync && spi_clk_prev; 48 | 49 | /* Input sync */ 50 | d_flipflop_pair spi_dff_clk(mclk, reset, spi_clk, spi_clk_sync); 51 | d_flipflop_pair spi_dff_mosi(mclk, reset, spi_mosi, spi_mosi_sync); 52 | d_flipflop_pair spi_dff_miso(mclk, reset, spi_miso_in, spi_miso_sync); 53 | d_flipflop_pair spi_dff_cs(mclk, reset, spi_cs, spi_cs_sync); 54 | 55 | /* For clock edge detection */ 56 | //d_flipflop spi_dff_clk_2(mclk, reset, spi_clk_sync, spi_clk_prev); 57 | 58 | 59 | /************************************************ 60 | * Shift register 61 | */ 62 | 63 | reg [2:0] bit_count; 64 | reg [7:0] miso_reg_in; 65 | reg [7:0] miso_reg_out; 66 | reg [7:0] mosi_reg; 67 | 68 | always @(posedge mclk) 69 | begin 70 | spi_clk_prev <= spi_clk_sync; 71 | spi_rx_strobe <= 0; 72 | 73 | /* 74 | * Master reset or chip deselect: Reset everything. 75 | */ 76 | 77 | if (reset || spi_cs) begin 78 | bit_count <= 0; 79 | spi_miso_out <= 1; 80 | end 81 | 82 | /* 83 | * Clock edges: Shift in and increment bit_count on positive 84 | * edges, shift out on negative edges. 85 | * 86 | * Our per-byte state machine begins immediately after the last 87 | * positive edge in the byte (bit_count == 7), and it must 88 | * provide a new result to mosi_reg before the next negative edge. 89 | */ 90 | else if (spi_clk_posedge) begin 91 | bit_count <= bit_count + 1; 92 | if (bit_count == 7) begin 93 | spi_rx_strobe <= 1; 94 | //spi_rx_data <= {mosi_reg[6:0], spi_mosi_sync}; 95 | spi_rx_data <= {mosi_reg[6:0], spi_mosi_sync}; 96 | spi_mon_data <= { miso_reg_in[6:0], spi_miso_sync}; 97 | end else begin 98 | mosi_reg <= {mosi_reg[6:0], spi_mosi_sync}; 99 | miso_reg_in <= { miso_reg_in[6:0], spi_miso_sync}; 100 | end 101 | end else 102 | if (spi_clk_negedge) begin 103 | // update the output pin on the falling clock edge 104 | spi_miso_out <= miso_reg_out[7]; 105 | miso_reg_out <= {miso_reg_out[6:0], 1'b1}; 106 | end else 107 | if (spi_tx_strobe) begin 108 | miso_reg_out <= spi_tx_data; 109 | end 110 | end 111 | endmodule 112 | -------------------------------------------------------------------------------- /spispy.py: -------------------------------------------------------------------------------- 1 | ctx.addClock("clk_48", 48) 2 | -------------------------------------------------------------------------------- /spispy.v: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Monitor a flash device and print the addresses read 3 | * 4 | * The up5k has 1024 Kb of single ported block RAM. 5 | * This is can't read/write simultaneously, so it is necessary to 6 | * mux the read/write pins. 7 | * 8 | */ 9 | `include "util.v" 10 | `include "uart.v" 11 | `include "spram.v" 12 | `include "spi_device.v" 13 | 14 | module top( 15 | output led_r, 16 | output led_g, 17 | output led_b, 18 | output serial_txd, 19 | input serial_rxd, 20 | output spi_cs, // to the onboard flash chip 21 | 22 | // to the 23 | input gpio_28, 24 | input gpio_38, 25 | input gpio_42, 26 | input gpio_36, 27 | output gpio_43 // copy of gpio_36, to pass through the CS 28 | ); 29 | assign spi_cs = 1; // it is necessary to turn off the SPI flash chip 30 | 31 | wire clk_48; 32 | SB_HFOSC u_hfosc ( 33 | .CLKHFPU(1'b1), 34 | .CLKHFEN(1'b1), 35 | .CLKHF(clk_48) 36 | ); 37 | 38 | wire reset = 0; 39 | 40 | /* 41 | reg [31:0] counter; 42 | always @(posedge clk_48) 43 | counter <= counter + 1; 44 | 45 | // pulse the green LED to know that we're alive 46 | wire pwm_g; 47 | pwm pwm_g_driver(clk_48, 1, pwm_g); 48 | assign led_g = !(counter[25:23] == 0 && pwm_g); 49 | */ 50 | assign led_g = 1; 51 | 52 | 53 | // generate a 3 MHz/12 MHz serial clock from the 48 MHz clock 54 | // this is the 3 Mb/s maximum supported by the FTDI chip 55 | wire clk_1, clk_4; 56 | divide_by_n #(.N(16)) div1(clk_48, reset, clk_1); 57 | divide_by_n #(.N( 4)) div4(clk_48, reset, clk_4); 58 | 59 | reg [7:0] uart_txd; 60 | reg uart_txd_strobe; 61 | wire uart_txd_ready; 62 | 63 | uart_tx txd( 64 | .mclk(clk_48), 65 | .reset(reset), 66 | .baud_x1(clk_1), 67 | .serial(serial_txd), 68 | .ready(uart_txd_ready), 69 | .data(uart_txd), 70 | .data_strobe(uart_txd_strobe) 71 | ); 72 | 73 | /* this demo doesn't use the serial port 74 | wire [7:0] uart_rxd; 75 | wire uart_rxd_strobe; 76 | 77 | uart_rx rxd( 78 | .mclk(clk_48), 79 | .reset(reset), 80 | .baud_x4(clk_4), 81 | .serial(serial_rxd), 82 | .data(uart_rxd), 83 | .data_strobe(uart_rxd_strobe) 84 | ); 85 | 86 | assign debug0 = serial_txd; 87 | */ 88 | 89 | // Emlated 256 bytes of flash ROM 90 | reg [23:0] read_addr; 91 | reg [7:0] flash_rom[0:255]; 92 | wire [7:0] flash_data = flash_rom[read_addr[7:0]]; 93 | 94 | // initialize the flash_rom 95 | initial $readmemb("flash.bin", flash_rom); 96 | 97 | // Connect the SPI port to the decoder 98 | reg spi_tx_strobe; 99 | wire spi_rx_strobe; 100 | wire [7:0] spi_rx_data; 101 | 102 | /* 35c3 cable: 103 | * 1 cs on chip 43 104 | * 2 cs on mainboard 36 105 | * 3 miso 42 106 | * 4 !wp 107 | * 5 gnd GND 108 | * 6 mosi 38 109 | * 7 sck 28 110 | * 8 !rst 111 | * 9 vcc 112 | */ 113 | 114 | wire spi_cs_in = gpio_36; 115 | 116 | // copy the incoming CS pin to the outbound CS 117 | assign gpio_43 = gpio_36; 118 | 119 | spi_device spi0( 120 | .mclk(clk_48), 121 | .reset(reset), 122 | .spi_cs(spi_cs_in), 123 | .spi_clk(gpio_28), 124 | .spi_mosi(gpio_38), 125 | .spi_miso_in(gpio_42), 126 | //.spi_miso_out(), 127 | .spi_tx_data(flash_data), 128 | .spi_tx_strobe(spi_tx_strobe), 129 | .spi_rx_strobe(spi_rx_strobe), 130 | .spi_rx_data(spi_rx_data) 131 | ); 132 | 133 | reg [12:0] bytes; 134 | reg [15:0] serial_out; 135 | reg do_serial; 136 | reg do_hex; 137 | reg spi_cs_buf; 138 | reg spi_cs_prev; 139 | reg spi_cs_sync; 140 | 141 | assign led_b = spi_cs_sync; // idles high 142 | 143 | reg read_in_progress; 144 | // watch for new commands on the SPI bus, print first x bytes 145 | always @(posedge clk_48) 146 | begin 147 | // Double buffer and latch the SPI CS to track edges 148 | spi_cs_buf <= spi_cs_in; 149 | spi_cs_prev <= spi_cs_buf; 150 | spi_cs_sync <= spi_cs_prev; 151 | 152 | // Default is no output from the SPI bus 153 | do_serial <= 0; 154 | do_hex <= 0; 155 | 156 | if (reset) begin 157 | // nothing to do 158 | end else 159 | if (!spi_cs_sync && spi_cs_prev) begin 160 | // falling edge of the CS, reset the transaction 161 | bytes <= 0; 162 | if (read_in_progress) begin 163 | serial_out = "\r\n"; 164 | do_serial <= 1; 165 | end 166 | read_in_progress <= 0; 167 | end else 168 | if (spi_cs_sync && !spi_cs_prev) begin 169 | // rising edge of the CS, send newline if we 170 | // have received a non-zero number of bytes 171 | read_in_progress <= 0; 172 | end else 173 | if (spi_rx_strobe) begin 174 | // new byte on the wire; print the first four bytes 175 | // parse the command in the first byte 176 | if (bytes == 0 && spi_rx_data == 3) begin 177 | read_in_progress <= 1; 178 | end else 179 | if (bytes <= 3 && read_in_progress) 180 | begin 181 | read_addr <= { read_addr[15:8], spi_rx_data }; 182 | do_serial <= 1; 183 | do_hex <= 1; 184 | end else 185 | if (read_in_progress) 186 | begin 187 | read_addr <= read_addr + 1; 188 | end 189 | 190 | bytes <= bytes + 1; 191 | end else begin 192 | /* 193 | if (read_addr == 24'hFFB880) begin 194 | // disable flash address overlays 195 | do_overlay <= 0; 196 | do_serial <= 1; 197 | serial_out <= "--"; 198 | end else 199 | if (read_addr == 24'hFFB800) begin 200 | // enable overlay 201 | do_overlay <= 1; 202 | do_serial <= 1; 203 | serial_out <= "++"; 204 | end 205 | */ 206 | end 207 | end 208 | 209 | 210 | reg fifo_read_strobe; 211 | wire fifo_available; 212 | 213 | fifo_spram_16to8 buffer( 214 | .clk(clk_48), 215 | .reset(reset), 216 | .write_data(do_hex 217 | ? { hexdigit(spi_rx_data[7:4]), hexdigit(spi_rx_data[3:0]) } 218 | : serial_out), 219 | .write_strobe(do_serial) , 220 | .data_available(fifo_available), 221 | .read_data(uart_txd), 222 | .read_strobe(fifo_read_strobe) 223 | ); 224 | 225 | always @(posedge clk_48) begin 226 | uart_txd_strobe <= 0; 227 | fifo_read_strobe <= 0; 228 | led_r <= 1; 229 | 230 | // single port fifo can't read/write the same cycle 231 | if (fifo_available 232 | && uart_txd_ready 233 | && !do_serial 234 | && !uart_txd_strobe 235 | ) begin 236 | fifo_read_strobe <= 1; 237 | uart_txd_strobe <= 1; 238 | led_r <= 0; 239 | end 240 | end 241 | endmodule 242 | -------------------------------------------------------------------------------- /spram-demo.v: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Demo reading / writing to the single port RAM. 3 | * 4 | * The up5k has 1024 Kb of single ported block RAM. 5 | * This is can't read/write simultaneously, so it is necessary to 6 | * mux the read/write pins. 7 | * 8 | * This is another serial demo, but the FIFO is stored in the 9 | * SPRAM and clocked out slowly to show how much the FIFO can store. 10 | * If you overflow the FIFO, bad things happen. 11 | */ 12 | `include "util.v" 13 | `include "spram.v" 14 | `include "uart.v" 15 | 16 | module top( 17 | output led_r, 18 | output led_g, 19 | output led_b, 20 | output serial_txd, 21 | input serial_rxd, 22 | output spi_cs, 23 | output gpio_2 24 | ); 25 | assign spi_cs = 1; // it is necessary to turn off the SPI flash chip 26 | wire debug0 = gpio_2; 27 | 28 | wire clk_48; 29 | wire reset = 0; 30 | SB_HFOSC u_hfosc ( 31 | .CLKHFPU(1'b1), 32 | .CLKHFEN(1'b1), 33 | .CLKHF(clk_48) 34 | ); 35 | 36 | reg [31:0] counter; 37 | always @(posedge clk_48) 38 | counter <= counter + 1; 39 | 40 | // pulse the green LED to know that we're alive 41 | wire pwm_g; 42 | pwm pwm_g_driver(clk_48, 1, pwm_g); 43 | assign led_g = !(counter[25:23] == 0 && pwm_g); 44 | 45 | assign led_b = serial_rxd; // idles high 46 | 47 | // generate a 3 MHz/12 MHz serial clock from the 48 MHz clock 48 | // this is the 3 Mb/s maximum supported by the FTDI chip 49 | wire clk_1, clk_4; 50 | divide_by_n #(.N(16)) div1(clk_48, reset, clk_1); 51 | divide_by_n #(.N( 4)) div4(clk_48, reset, clk_4); 52 | 53 | reg [7:0] uart_txd; 54 | reg uart_txd_strobe; 55 | wire uart_txd_ready; 56 | 57 | wire [7:0] uart_rxd; 58 | wire uart_rxd_strobe; 59 | 60 | uart_tx txd( 61 | .mclk(clk_48), 62 | .reset(reset), 63 | .baud_x1(clk_1), 64 | .serial(serial_txd), 65 | .ready(uart_txd_ready), 66 | .data(uart_txd), 67 | .data_strobe(uart_txd_strobe) 68 | ); 69 | 70 | uart_rx rxd( 71 | .mclk(clk_48), 72 | .reset(reset), 73 | .baud_x4(clk_4), 74 | .serial(serial_rxd), 75 | .data(uart_rxd), 76 | .data_strobe(uart_rxd_strobe) 77 | ); 78 | 79 | assign debug0 = serial_txd; 80 | 81 | reg fifo_read_strobe; 82 | wire fifo_available; 83 | 84 | fifo_spram buffer( 85 | .clk(clk_48), 86 | .reset(reset), 87 | .write_data(uart_rxd), 88 | .write_strobe(uart_rxd_strobe), 89 | .data_available(fifo_available), 90 | .read_data(uart_txd), 91 | .read_strobe(fifo_read_strobe) 92 | ); 93 | 94 | always @(posedge clk_48) begin 95 | uart_txd_strobe <= 0; 96 | fifo_read_strobe <= 0; 97 | led_r <= 1; 98 | 99 | // single port fifo can't read/write the same cycle 100 | if (fifo_available 101 | && uart_txd_ready 102 | && !uart_rxd_strobe 103 | && !uart_txd_strobe 104 | && counter[18:0] == 0 105 | ) begin 106 | fifo_read_strobe <= 1; 107 | uart_txd_strobe <= 1; 108 | led_r <= 0; 109 | end 110 | end 111 | endmodule 112 | -------------------------------------------------------------------------------- /spram.v: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Single Ported RAM wrapper. 3 | * 4 | * The up5k has 1024 Kb of single ported block RAM. 5 | * This is can't read/write simultaneously, so it is necessary to 6 | * mux the read/write pins. 7 | * 8 | * Implement an 8-bit wide SPRAM using the 16-bit wide 16K block. 9 | */ 10 | 11 | module spram_32k( 12 | input clk, 13 | input reset = 0, 14 | input cs = 1, 15 | input wren, 16 | input [14:0] addr, 17 | input [7:0] write_data, 18 | output [7:0] read_data 19 | ); 20 | wire align = addr[0]; 21 | wire [15:0] rdata_16; 22 | assign read_data = align ? rdata_16[15:8] : rdata_16[7:0]; 23 | 24 | SB_SPRAM256KA ram( 25 | // read 16 bits at a time 26 | .DATAOUT(rdata_16), 27 | 28 | // ignore the bottom bit 29 | .ADDRESS(addr[14:1]), 30 | 31 | // duplicate the write data into both bytes 32 | .DATAIN({write_data, write_data}), 33 | 34 | // select writes to either top or bottom byte 35 | .MASKWREN({align, align, !align, !align}), 36 | .WREN(wren), 37 | 38 | .CHIPSELECT(cs && !reset), 39 | .CLOCK(clk), 40 | 41 | // if we cared about power, maybe we would adjust these 42 | .STANDBY(1'b0), 43 | .SLEEP(1'b0), 44 | .POWEROFF(1'b1) 45 | ); 46 | 47 | endmodule 48 | 49 | 50 | // This works like the dual-ported FIFO, but the read_data is 51 | // only available when write_strobe is not set. 52 | module fifo_spram( 53 | input clk, 54 | input reset, 55 | output data_available, 56 | input [WIDTH-1:0] write_data, 57 | input write_strobe, 58 | output [WIDTH-1:0] read_data, 59 | input read_strobe 60 | ); 61 | parameter WIDTH = 8; 62 | parameter BITS = 15; 63 | 64 | reg [BITS-1:0] write_ptr; 65 | reg [BITS-1:0] read_ptr; 66 | 67 | spram_32k mem( 68 | .clk(clk), 69 | .reset(reset), 70 | .cs(1), 71 | .wren(write_strobe), 72 | .addr(write_strobe ? write_ptr : read_ptr), 73 | .write_data(write_data), 74 | .read_data(read_data) 75 | ); 76 | 77 | assign data_available = read_ptr != write_ptr; 78 | 79 | always @(posedge clk) 80 | begin 81 | if (reset) begin 82 | write_ptr <= 0; 83 | read_ptr <= 0; 84 | end else begin 85 | if (write_strobe) 86 | write_ptr <= write_ptr + 1; 87 | if (read_strobe) 88 | read_ptr <= read_ptr + 1; 89 | end 90 | end 91 | 92 | endmodule 93 | 94 | 95 | // This works like the dual-ported FIFO, but the read_data is 96 | // only available when write_strobe is not set. Writes 16-bits at 97 | // a time, reads 8-bits at a time for hex chars. 98 | module fifo_spram_16to8( 99 | input clk, 100 | input reset, 101 | output data_available, 102 | input [16-1:0] write_data, 103 | input write_strobe, 104 | output [8-1:0] read_data, 105 | input read_strobe 106 | ); 107 | // BITS should always be 15 since the SPRAM can't be 108 | // partially allocated. 109 | parameter BITS = 15; 110 | 111 | reg [BITS-1:0] write_ptr; 112 | reg [BITS-1:0] read_ptr; 113 | 114 | // reads from the SPRAM are 16-bits at a time, 115 | // so we have to pick which byte of the word should be extracted 116 | wire [15:0] rdata_16; 117 | assign read_data = (!read_ptr[0]) ? rdata_16[15:8] : rdata_16[7:0]; 118 | 119 | SB_SPRAM256KA ram( 120 | // read 16 bits at a time 121 | .DATAOUT(rdata_16), 122 | 123 | // ignore the bottom bit of the address 124 | .ADDRESS(write_strobe 125 | ? write_ptr[BITS-1:1] 126 | : read_ptr[BITS-1:1] 127 | ), 128 | 129 | .DATAIN(write_data), 130 | 131 | // always write to both bytes 132 | .MASKWREN(4'b1111), 133 | .WREN(write_strobe), 134 | 135 | .CHIPSELECT(!reset), 136 | .CLOCK(clk), 137 | 138 | // if we cared about power, maybe we would adjust these 139 | .STANDBY(1'b0), 140 | .SLEEP(1'b0), 141 | .POWEROFF(1'b1) 142 | ); 143 | 144 | assign data_available = read_ptr != write_ptr; 145 | 146 | always @(posedge clk) 147 | begin 148 | if (reset) begin 149 | write_ptr <= 0; 150 | read_ptr <= 0; 151 | end else begin 152 | if (write_strobe) 153 | write_ptr <= write_ptr + 2; 154 | if (read_strobe) 155 | read_ptr <= read_ptr + 1; 156 | end 157 | end 158 | 159 | endmodule 160 | -------------------------------------------------------------------------------- /tinyfpga-bx.pcf: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Family & Device: iCE40LP8K 3 | # Package: CM81 4 | ############################################################################### 5 | 6 | set_io -nowarn pin_1 A2 7 | set_io -nowarn pin_2 A1 8 | set_io -nowarn pin_3 B1 9 | set_io -nowarn pin_4 C2 10 | set_io -nowarn pin_5 C1 11 | set_io -nowarn pin_6 D2 12 | set_io -nowarn pin_7 D1 13 | set_io -nowarn pin_8 E2 14 | set_io -nowarn pin_9 E1 15 | set_io -nowarn pin_10 G2 16 | set_io -nowarn pin_11 H1 17 | set_io -nowarn pin_12 J1 18 | set_io -nowarn pin_13 H2 19 | set_io -nowarn pin_14 H9 20 | set_io -nowarn pin_15 D9 21 | set_io -nowarn pin_16 D8 22 | set_io -nowarn pin_17 C9 23 | set_io -nowarn pin_18 A9 24 | set_io -nowarn pin_19 B8 25 | set_io -nowarn pin_20 A8 26 | set_io -nowarn pin_21 B7 27 | set_io -nowarn pin_22 A7 28 | set_io -nowarn pin_23 B6 29 | set_io -nowarn pin_24 A6 30 | set_io -nowarn pin_25 G1 31 | set_io -nowarn pin_26 J3 32 | set_io -nowarn pin_27 J4 33 | set_io -nowarn pin_28 H4 34 | set_io -nowarn pin_29_miso H7 35 | set_io -nowarn pin_30_cs F7 36 | set_io -nowarn pin_31_mosi G6 37 | set_io -nowarn pin_32_sck G7 38 | set_io -nowarn pin_33 J8 39 | set_io -nowarn pin_34 G9 40 | set_io -nowarn pin_35 J9 41 | set_io -nowarn pin_36 E8 42 | set_io -nowarn pin_37 J2 43 | set_io -nowarn pin_led B3 44 | set_io -nowarn pin_usbp B4 45 | set_io -nowarn pin_usbn A4 46 | set_io -nowarn pin_pu A3 47 | set_io -nowarn pin_clk B2 48 | 49 | -------------------------------------------------------------------------------- /tomu.pcf: -------------------------------------------------------------------------------- 1 | # 2 | # Pinmap for the Fomu hacker version 0.0 3 | # 4 | set_io -nowarn pin_clk F5 # IOB_3b 5 | set_io -nowarn BTN_N F4 # IOB_11b / pin1 6 | set_io -nowarn pin_8 C5 # Red 7 | set_io -nowarn pin_led B5 # Green 8 | set_io -nowarn pin_9 A5 # Blue 9 | 10 | set_io -nowarn flash_sck D1 # IOB_35a 11 | set_io -nowarn flash_cs C1 # IOB_35b 12 | set_io -nowarn flash_mosi F1 # IOB_32a 13 | set_io -nowarn flash_miso E1 # IOB_33b 14 | 15 | set_io -nowarn pin_usbp A4 # IOT_47a 16 | set_io -nowarn pin_usbn A2 # IOT_37a 17 | set_io -nowarn pin_pu D5 # IOT_2a ? 18 | -------------------------------------------------------------------------------- /uart.v: -------------------------------------------------------------------------------- 1 | /* 2 | * uart.v - High-speed serial support. Includes a baud generator, UART, 3 | * and a simple RFC1662-inspired packet framing protocol. 4 | * 5 | * This module is designed a 3 Mbaud serial port. 6 | * This is the highest data rate supported by 7 | * the popular FT232 USB-to-serial chip. 8 | * 9 | * Copyright (C) 2009 Micah Dowty 10 | * (C) 2018 Trammell Hudson 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | */ 30 | 31 | 32 | /* 33 | * Byte transmitter, RS-232 8-N-1 34 | * 35 | * Transmits on 'serial'. When 'ready' goes high, we can accept another byte. 36 | * It should be supplied on 'data' with a pulse on 'data_strobe'. 37 | */ 38 | 39 | module uart_tx( 40 | input mclk, 41 | input reset, 42 | input baud_x1, 43 | output serial, 44 | output reg ready, 45 | input [7:0] data, 46 | input data_strobe 47 | ); 48 | 49 | /* 50 | * Left-to-right shift register. 51 | * Loaded with data, start bit, and stop bit. 52 | * 53 | * The stop bit doubles as a flag to tell us whether data has been 54 | * loaded; we initialize the whole shift register to zero on reset, 55 | * and when the register goes zero again, it's ready for more data. 56 | */ 57 | reg [7+1+1:0] shiftreg; 58 | 59 | /* 60 | * Serial output register. This is like an extension of the 61 | * shift register, but we never load it separately. This gives 62 | * us one bit period of latency to prepare the next byte. 63 | * 64 | * This register is inverted, so we can give it a reset value 65 | * of zero and still keep the 'serial' output high when idle. 66 | */ 67 | reg serial_r; 68 | assign serial = !serial_r; 69 | 70 | //assign ready = (shiftreg == 0); 71 | 72 | /* 73 | * State machine 74 | */ 75 | 76 | always @(posedge mclk) 77 | if (reset) begin 78 | shiftreg <= 0; 79 | serial_r <= 0; 80 | end 81 | else if (data_strobe) begin 82 | shiftreg <= { 83 | 1'b1, // stop bit 84 | data, 85 | 1'b0 // start bit (inverted) 86 | }; 87 | ready <= 0; 88 | end 89 | else if (baud_x1) begin 90 | if (shiftreg == 0) 91 | begin 92 | /* Idle state is idle high, serial_r is inverted */ 93 | serial_r <= 0; 94 | ready <= 1; 95 | end else 96 | serial_r <= !shiftreg[0]; 97 | // shift the output register down 98 | shiftreg <= {1'b0, shiftreg[7+1+1:1]}; 99 | end else 100 | ready <= (shiftreg == 0); 101 | 102 | endmodule 103 | 104 | 105 | /* 106 | * Byte receiver, RS-232 8-N-1 107 | * 108 | * Receives on 'serial'. When a properly framed byte is 109 | * received, 'data_strobe' pulses while the byte is on 'data'. 110 | * 111 | * Error bytes are ignored. 112 | */ 113 | 114 | module uart_rx(mclk, reset, baud_x4, 115 | serial, data, data_strobe); 116 | 117 | input mclk, reset, baud_x4, serial; 118 | output [7:0] data; 119 | output data_strobe; 120 | 121 | /* 122 | * Synchronize the serial input to this clock domain 123 | */ 124 | wire serial_sync; 125 | d_flipflop_pair input_dff(mclk, reset, serial, serial_sync); 126 | 127 | /* 128 | * State machine: Four clocks per bit, 10 total bits. 129 | */ 130 | reg [8:0] shiftreg; 131 | reg [5:0] state; 132 | reg data_strobe; 133 | wire [3:0] bit_count = state[5:2]; 134 | wire [1:0] bit_phase = state[1:0]; 135 | 136 | wire sampling_phase = (bit_phase == 1); 137 | wire start_bit = (bit_count == 0 && sampling_phase); 138 | wire stop_bit = (bit_count == 9 && sampling_phase); 139 | 140 | wire waiting_for_start = (state == 0 && serial_sync == 1); 141 | 142 | wire error = ( (start_bit && serial_sync == 1) || 143 | (stop_bit && serial_sync == 0) ); 144 | 145 | assign data = shiftreg[7:0]; 146 | 147 | always @(posedge mclk or posedge reset) 148 | if (reset) begin 149 | state <= 0; 150 | data_strobe <= 0; 151 | end 152 | else if (baud_x4) begin 153 | 154 | if (waiting_for_start || error || stop_bit) 155 | state <= 0; 156 | else 157 | state <= state + 1; 158 | 159 | if (bit_phase == 1) 160 | shiftreg <= { serial_sync, shiftreg[8:1] }; 161 | 162 | data_strobe <= stop_bit && !error; 163 | 164 | end 165 | else begin 166 | data_strobe <= 0; 167 | end 168 | 169 | endmodule 170 | 171 | 172 | /* 173 | * Output UART with a block RAM FIFO queue. 174 | * 175 | * Add bytes to the queue and they will be printed when the line is idle. 176 | */ 177 | module uart_tx_fifo( 178 | input clk, 179 | input reset, 180 | input baud_x1, 181 | input [7:0] data, 182 | input data_strobe, 183 | output serial 184 | ); 185 | parameter NUM = 32; 186 | 187 | wire uart_txd_ready; // high the UART is ready to take a new byte 188 | reg uart_txd_strobe; // pulse when we have a new byte to transmit 189 | reg [7:0] uart_txd; 190 | 191 | uart_tx txd( 192 | .mclk(clk), 193 | .reset(reset), 194 | .baud_x1(baud_x1), 195 | .serial(serial), 196 | .ready(uart_txd_ready), 197 | .data(uart_txd), 198 | .data_strobe(uart_txd_strobe) 199 | ); 200 | 201 | wire fifo_available; 202 | wire fifo_read_strobe; 203 | 204 | fifo #(.NUM(NUM), .WIDTH(8)) buffer( 205 | .clk(clk), 206 | .reset(reset), 207 | .write_data(data), 208 | .write_strobe(data_strobe), 209 | .data_available(fifo_available), 210 | .read_data(uart_txd), 211 | .read_strobe(fifo_read_strobe) 212 | ); 213 | 214 | // drain the fifo into the serial port 215 | always @(posedge clk) 216 | begin 217 | uart_txd_strobe <= 0; 218 | fifo_read_strobe <= 0; 219 | 220 | if (fifo_available 221 | && uart_txd_ready 222 | && !data_strobe // avoid dual port RAM if possible 223 | && !uart_txd_strobe // don't TX twice on one byte 224 | ) begin 225 | fifo_read_strobe <= 1; 226 | uart_txd_strobe <= 1; 227 | end 228 | end 229 | endmodule 230 | -------------------------------------------------------------------------------- /upduino_v2.pcf: -------------------------------------------------------------------------------- 1 | # The LED pins are using the current controlled outputs 2 | # and are negative logic (write a 0 to turn on). 3 | set_io -nowarn led_r 41 4 | set_io -nowarn led_g 39 5 | set_io -nowarn led_b 40 6 | 7 | # FTDI chip, which sort of works 8 | set_io -nowarn serial_txd 14 # FPGA transmit to USB 9 | set_io -nowarn serial_rxd 15 # FPGA receive from USB 10 | set_io -nowarn spi_cs 16 # Drive high to ensure that the SPI flash is disabled 11 | # set_io serial_rts_n 14 # no? 12 | # set_io serial_dtr_n 16 # no? 13 | 14 | # Normal GPIO pins, left side 15 | set_io -nowarn gpio_23 23 16 | set_io -nowarn gpio_25 25 17 | set_io -nowarn gpio_26 26 18 | set_io -nowarn gpio_27 27 19 | set_io -nowarn gpio_32 32 20 | set_io -nowarn gpio_35 35 21 | set_io -nowarn gpio_31 31 22 | set_io -nowarn gpio_37 37 23 | set_io -nowarn gpio_34 34 24 | set_io -nowarn gpio_43 43 25 | set_io -nowarn gpio_36 36 26 | set_io -nowarn gpio_42 42 27 | set_io -nowarn gpio_38 38 28 | set_io -nowarn gpio_28 28 29 | 30 | # Normal GPIO pins, right side 31 | set_io -nowarn gpio_12 12 32 | set_io -nowarn gpio_21 21 33 | set_io -nowarn gpio_13 13 34 | set_io -nowarn gpio_19 19 35 | set_io -nowarn gpio_18 18 36 | set_io -nowarn gpio_11 11 37 | set_io -nowarn gpio_9 9 38 | set_io -nowarn gpio_6 6 39 | set_io -nowarn gpio_44 44 40 | set_io -nowarn gpio_4 4 41 | set_io -nowarn gpio_3 3 42 | set_io -nowarn gpio_48 48 43 | set_io -nowarn gpio_45 45 44 | set_io -nowarn gpio_47 47 45 | set_io -nowarn gpio_46 46 46 | set_io -nowarn gpio_2 2 47 | -------------------------------------------------------------------------------- /usb/Makefile: -------------------------------------------------------------------------------- 1 | all: top.bin 2 | 3 | DEVICE-tinyfpga := lp8k 4 | FOOTPRINT-tinyfpga := cm81 5 | PIN_SRC-tinyfpga := ../tinyfpga-bx.pcf 6 | 7 | DEVICE-tomu := up5k 8 | FOOTPRINT-tomu := uwg30 9 | PIN_SRC-tomu := ../tomu.pcf 10 | 11 | DEVICE := $(DEVICE-$(BOARD)) 12 | FOOTPRINT := $(FOOTPRINT-$(BOARD)) 13 | PIN_SRC := $(PIN_SRC-$(BOARD)) 14 | 15 | include ../Makefile.icestorm 16 | -------------------------------------------------------------------------------- /usb/edge_detect.v: -------------------------------------------------------------------------------- 1 | `ifndef edge_detect_v 2 | `define edge_detect_v 3 | 4 | module rising_edge_detector ( 5 | input clk, 6 | input in, 7 | output out 8 | ); 9 | reg in_q; 10 | 11 | always @(posedge clk) begin 12 | in_q <= in; 13 | end 14 | 15 | assign out = !in_q && in; 16 | endmodule 17 | 18 | module falling_edge_detector ( 19 | input clk, 20 | input in, 21 | output out 22 | ); 23 | reg in_q; 24 | 25 | always @(posedge clk) begin 26 | in_q <= in; 27 | end 28 | 29 | assign out = in_q && !in; 30 | endmodule 31 | 32 | `endif 33 | -------------------------------------------------------------------------------- /usb/serial-demo.v: -------------------------------------------------------------------------------- 1 | `include "usb_serial.v" 2 | `include "../uart.v" 3 | `include "../util.v" 4 | 5 | module top ( 6 | input pin_clk, 7 | 8 | inout pin_usbp, 9 | inout pin_usbn, 10 | output pin_pu, 11 | 12 | output pin_led, 13 | output pin_8, 14 | output pin_9 15 | ); 16 | wire serial_tx = pin_8; 17 | 18 | wire clk_48mhz; 19 | wire lock; 20 | wire reset = !lock; 21 | 22 | `ifdef TINYFPGA 23 | SB_PLL40_CORE #( 24 | .DIVR(4'b0000), 25 | .DIVF(7'b0101111), 26 | .DIVQ(3'b100), 27 | .FILTER_RANGE(3'b001), 28 | .FEEDBACK_PATH("SIMPLE"), 29 | .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), 30 | .FDA_FEEDBACK(4'b0000), 31 | .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), 32 | .FDA_RELATIVE(4'b0000), 33 | .SHIFTREG_DIV_MODE(2'b00), 34 | .PLLOUT_SELECT("GENCLK"), 35 | .ENABLE_ICEGATE(1'b0) 36 | ) usb_pll_inst ( 37 | .REFERENCECLK(pin_clk), 38 | .PLLOUTCORE(clk_48mhz), 39 | .PLLOUTGLOBAL(), 40 | .EXTFEEDBACK(), 41 | .DYNAMICDELAY(), 42 | .RESETB(1'b1), 43 | .BYPASS(1'b0), 44 | .LATCHINPUTVALUE(), 45 | .LOCK(lock), 46 | .SDI(), 47 | .SDO(), 48 | .SCLK() 49 | `define TOMU 50 | ); 51 | `endif 52 | 53 | `define TOMU 54 | `ifdef TOMU 55 | assign lock = 1; 56 | SB_HFOSC u_hfosc ( 57 | .CLKHFPU(1'b1), 58 | .CLKHFEN(1'b1), 59 | .CLKHF(clk_48mhz) 60 | ); 61 | `endif 62 | 63 | reg clk_24mhz; 64 | reg clk_12mhz; 65 | reg clk_6mhz; 66 | reg clk_3mhz; 67 | always @(posedge clk_48mhz) clk_24mhz = !clk_24mhz; 68 | always @(posedge clk_24mhz) clk_12mhz = !clk_12mhz; 69 | always @(posedge clk_12mhz) clk_6mhz = !clk_6mhz; 70 | always @(posedge clk_6mhz) clk_3mhz = !clk_3mhz; 71 | 72 | wire clk = clk_12mhz; 73 | 74 | wire uart_ready; 75 | reg [7:0] uart_data; 76 | reg uart_strobe; 77 | wire clk_1; 78 | divide_by_n #(.N(16)) div1(clk_48mhz, reset, clk_1); 79 | uart_tx uart( 80 | .mclk(clk), 81 | .reset(reset), 82 | .baud_x1(clk_1), 83 | .serial(serial_tx), 84 | .ready(uart_ready), 85 | .data(uart_data), 86 | .data_strobe(uart_strobe) 87 | ); 88 | 89 | wire usb_p_tx; 90 | wire usb_n_tx; 91 | wire usb_p_rx; 92 | wire usb_n_rx; 93 | wire usb_tx_en; 94 | 95 | wire uart_tx_ready; 96 | reg [7:0] uart_tx_data; 97 | reg uart_tx_strobe; 98 | 99 | wire uart_rx_strobe; 100 | wire [7:0] uart_rx_data; 101 | 102 | reg [21:0] counter = 1; 103 | initial pin_led <= 0; 104 | reg [4:0] out; 105 | wire host_presence; 106 | 107 | reg [23:0] init; 108 | reg active; 109 | always @(posedge clk) begin 110 | if (reset) begin 111 | init <= 0; 112 | active <= 0; 113 | end else 114 | if (&init == 1) begin 115 | active <= 1; 116 | end else begin 117 | init <= init + 1; 118 | end 119 | end 120 | 121 | wire fifo_data_available; 122 | reg [7:0] fifo_tx_data; 123 | reg fifo_tx_strobe; 124 | wire [7:0] fifo_rx_data; 125 | reg fifo_rx_strobe; 126 | 127 | fifo tx_buffer( 128 | .clk(clk), 129 | .reset(reset), 130 | .data_available(fifo_data_available), 131 | .write_data(fifo_tx_data), 132 | .write_strobe(fifo_tx_strobe), 133 | .read_data(fifo_rx_data), 134 | .read_strobe(fifo_rx_strobe) 135 | ); 136 | 137 | always @(posedge clk) if (!reset) begin 138 | if (uart_tx_ready 139 | && fifo_data_available 140 | && !uart_tx_strobe 141 | ) begin 142 | uart_tx_data <= fifo_rx_data; 143 | uart_tx_strobe <= 1; 144 | fifo_rx_strobe <= 1; 145 | end else begin 146 | uart_tx_strobe <= 0; 147 | fifo_rx_strobe <= 0; 148 | end 149 | end 150 | 151 | always @(posedge clk) if (active) begin 152 | fifo_tx_strobe <= 0; 153 | uart_strobe <= 0; 154 | 155 | counter <= counter + 1; 156 | pin_9 <= counter[21]; 157 | 158 | if (uart_tx_ready 159 | && !uart_tx_strobe 160 | && counter == 0 161 | ) begin 162 | uart_data <= "A" + out[4:0]; 163 | fifo_tx_data <= "A" + out[4:0]; 164 | fifo_tx_strobe <= 1; 165 | out <= out + 1; 166 | pin_led <= !pin_led; 167 | 168 | uart_strobe <= 1; 169 | end 170 | 171 | if (uart_rx_strobe) begin 172 | pin_led <= 1; 173 | uart_data <= uart_rx_data; 174 | fifo_tx_data <= uart_rx_data; 175 | fifo_tx_strobe <= 1; 176 | 177 | if (!uart_strobe) 178 | uart_strobe <= 1; 179 | end 180 | end 181 | 182 | 183 | 184 | usb_serial serial( 185 | .clk_48mhz(clk_48mhz), 186 | .clk(clk), 187 | .reset(reset), 188 | .host_presence(host_presence), 189 | .uart_tx_ready(uart_tx_ready), 190 | .uart_tx_strobe(uart_tx_strobe), 191 | .uart_tx_data(uart_tx_data), 192 | .uart_rx_strobe(uart_rx_strobe), 193 | .uart_rx_data(uart_rx_data), 194 | .usb_p_tx(usb_p_tx), 195 | .usb_n_tx(usb_n_tx), 196 | .usb_p_rx(usb_p_rx), 197 | .usb_n_rx(usb_n_rx), 198 | .usb_tx_en(usb_tx_en) 199 | ); 200 | 201 | assign pin_pu = 1'b1; 202 | 203 | wire usb_p_rx_io; 204 | wire usb_n_rx_io; 205 | assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_rx_io; 206 | assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_rx_io; 207 | 208 | tristate usbn_buffer( 209 | .pin(pin_usbn), 210 | .enable(usb_tx_en), 211 | .data_in(usb_n_rx_io), 212 | .data_out(usb_n_tx) 213 | ); 214 | 215 | tristate usbp_buffer( 216 | .pin(pin_usbp), 217 | .enable(usb_tx_en), 218 | .data_in(usb_p_rx_io), 219 | .data_out(usb_p_tx) 220 | ); 221 | endmodule 222 | 223 | module tristate( 224 | inout pin, 225 | input enable, 226 | input data_out, 227 | output data_in 228 | ); 229 | SB_IO #( 230 | .PIN_TYPE(6'b1010_01) // tristatable output 231 | ) buffer( 232 | .PACKAGE_PIN(pin), 233 | .OUTPUT_ENABLE(enable), 234 | .D_IN_0(data_in), 235 | .D_OUT_0(data_out) 236 | ); 237 | endmodule 238 | -------------------------------------------------------------------------------- /usb/strobe.v: -------------------------------------------------------------------------------- 1 | `ifndef strobe_v 2 | `define strobe_v 3 | 4 | module strobe( 5 | input clk_in, 6 | input clk_out, 7 | input strobe_in, 8 | output strobe_out, 9 | input [WIDTH-1:0] data_in, 10 | output [WIDTH-1:0] data_out 11 | ); 12 | parameter WIDTH = 1; 13 | parameter DELAY = 2; // 2 for metastability, larger for testing 14 | 15 | `define CLOCK_CROSS 16 | `ifdef CLOCK_CROSS 17 | reg flag; 18 | reg prev_strobe; 19 | reg [DELAY:0] sync; 20 | reg [WIDTH-1:0] data; 21 | 22 | // flip the flag and clock in the data when strobe is high 23 | always @(posedge clk_in) begin 24 | //if ((strobe_in && !prev_strobe) 25 | //|| (!strobe_in && prev_strobe)) 26 | flag <= flag ^ strobe_in; 27 | 28 | if (strobe_in) 29 | data <= data_in; 30 | 31 | prev_strobe <= strobe_in; 32 | end 33 | 34 | // shift through a chain of flipflop to ensure stability 35 | always @(posedge clk_out) 36 | sync <= { sync[DELAY-1:0], flag }; 37 | 38 | assign strobe_out = sync[DELAY] ^ sync[DELAY-1]; 39 | assign data_out = data; 40 | `else 41 | assign strobe_out = strobe_in; 42 | assign data_out = data_in; 43 | `endif 44 | endmodule 45 | 46 | 47 | module dflip( 48 | input clk, 49 | input in, 50 | output out 51 | ); 52 | reg [2:0] d; 53 | always @(posedge clk) 54 | d <= { d[1:0], in }; 55 | assign out = d[2]; 56 | endmodule 57 | 58 | 59 | module delay( 60 | input clk, 61 | input in, 62 | output out 63 | ); 64 | parameter DELAY = 1; 65 | 66 | generate 67 | if (DELAY == 0) begin 68 | assign out = in; 69 | end else 70 | if (DELAY == 1) begin 71 | reg buffer; 72 | always @(posedge clk) 73 | buffer <= in; 74 | assign out = buffer; 75 | end else begin 76 | reg [DELAY-1:0] buffer; 77 | always @(posedge clk) 78 | buffer <= { buffer[DELAY-2:0], in }; 79 | assign out = buffer[DELAY-1]; 80 | end 81 | endgenerate 82 | endmodule 83 | 84 | `endif 85 | 86 | -------------------------------------------------------------------------------- /usb/usb_fs_in_arb.v: -------------------------------------------------------------------------------- 1 | module usb_fs_in_arb #( 2 | parameter NUM_IN_EPS = 1 3 | ) ( 4 | //////////////////// 5 | // endpoint interface 6 | //////////////////// 7 | input [NUM_IN_EPS-1:0] in_ep_req, 8 | output reg [NUM_IN_EPS-1:0] in_ep_grant, 9 | input [(NUM_IN_EPS*8)-1:0] in_ep_data, 10 | 11 | 12 | //////////////////// 13 | // protocol engine interface 14 | //////////////////// 15 | output reg [7:0] arb_in_ep_data 16 | ); 17 | integer i; 18 | reg grant; 19 | 20 | always @* begin 21 | grant = 0; 22 | 23 | arb_in_ep_data <= 0; 24 | 25 | for (i = 0; i < NUM_IN_EPS; i = i + 1) begin 26 | in_ep_grant[i] <= 0; 27 | 28 | if (in_ep_req[i] && !grant) begin 29 | in_ep_grant[i] <= 1; 30 | arb_in_ep_data <= in_ep_data[i * 8 +: 8]; 31 | grant = 1; 32 | end 33 | end 34 | end 35 | endmodule 36 | -------------------------------------------------------------------------------- /usb/usb_fs_in_pe.v: -------------------------------------------------------------------------------- 1 | // The IN Protocol Engine sends data to the host. 2 | module usb_fs_in_pe #( 3 | parameter NUM_IN_EPS = 11, 4 | parameter MAX_IN_PACKET_SIZE = 32 5 | ) ( 6 | input clk, 7 | input reset, 8 | input [NUM_IN_EPS-1:0] reset_ep, 9 | input [6:0] dev_addr, 10 | 11 | 12 | //////////////////// 13 | // endpoint interface 14 | //////////////////// 15 | output reg [NUM_IN_EPS-1:0] in_ep_data_free = 0, 16 | input [NUM_IN_EPS-1:0] in_ep_data_put, 17 | input [7:0] in_ep_data, 18 | input [NUM_IN_EPS-1:0] in_ep_data_done, 19 | input [NUM_IN_EPS-1:0] in_ep_stall, 20 | output reg [NUM_IN_EPS-1:0] in_ep_acked = 0, 21 | 22 | 23 | //////////////////// 24 | // rx path 25 | //////////////////// 26 | 27 | // Strobed on reception of packet. 28 | input rx_pkt_start, 29 | input rx_pkt_end, 30 | input rx_pkt_valid, 31 | 32 | // Most recent packet received. 33 | input [3:0] rx_pid, 34 | input [6:0] rx_addr, 35 | input [3:0] rx_endp, 36 | input [10:0] rx_frame_num, 37 | 38 | 39 | //////////////////// 40 | // tx path 41 | //////////////////// 42 | 43 | // Strobe to send new packet. 44 | output reg tx_pkt_start, 45 | input tx_pkt_end, 46 | 47 | 48 | // Packet type to send 49 | output reg [3:0] tx_pid, 50 | 51 | // Data payload to send if any 52 | output tx_data_avail, 53 | input tx_data_get, 54 | output reg [7:0] tx_data 55 | ); 56 | 57 | //////////////////////////////////////////////////////////////////////////////// 58 | // endpoint state machine 59 | //////////////////////////////////////////////////////////////////////////////// 60 | reg [1:0] ep_state [NUM_IN_EPS - 1:0]; 61 | reg [1:0] ep_state_next [NUM_IN_EPS - 1:0]; 62 | 63 | // latched on valid IN token 64 | reg [3:0] current_endp = 0; 65 | 66 | wire [1:0] current_ep_state = ep_state[current_endp][1:0]; 67 | 68 | localparam READY_FOR_PKT = 0; 69 | localparam PUTTING_PKT = 1; 70 | localparam GETTING_PKT = 2; 71 | localparam STALL = 3; 72 | 73 | 74 | 75 | 76 | //////////////////////////////////////////////////////////////////////////////// 77 | // in transfer state machine 78 | //////////////////////////////////////////////////////////////////////////////// 79 | localparam IDLE = 0; 80 | localparam RCVD_IN = 1; 81 | localparam SEND_DATA = 2; 82 | localparam WAIT_ACK = 3; 83 | 84 | reg [1:0] in_xfr_state = IDLE; 85 | reg [1:0] in_xfr_state_next; 86 | 87 | 88 | reg in_xfr_start = 0; 89 | reg in_xfr_end = 0; 90 | 91 | 92 | // data toggle state 93 | reg [NUM_IN_EPS - 1:0] data_toggle = 0; 94 | 95 | // endpoint data buffer 96 | reg [7:0] in_data_buffer [(MAX_IN_PACKET_SIZE * NUM_IN_EPS) - 1:0]; 97 | reg [5:0] ep_put_addr [NUM_IN_EPS - 1:0]; 98 | reg [5:0] ep_get_addr [NUM_IN_EPS - 1:0]; 99 | 100 | integer i = 0; 101 | initial begin 102 | for (i = 0; i < NUM_IN_EPS; i = i + 1) begin 103 | ep_put_addr[i] <= 0; 104 | ep_get_addr[i] <= 0; 105 | ep_state[i] <= 0; 106 | end 107 | end 108 | 109 | reg [3:0] in_ep_num; 110 | 111 | wire [8:0] buffer_put_addr = {in_ep_num[3:0], ep_put_addr[in_ep_num][4:0]}; 112 | wire [8:0] buffer_get_addr = {current_endp[3:0], ep_get_addr[current_endp][4:0]}; 113 | 114 | // endpoint data packet buffer has a data packet ready to send 115 | reg [NUM_IN_EPS - 1:0] endp_ready_to_send = 0; 116 | 117 | // endpoint has some space free in its buffer 118 | reg [NUM_IN_EPS - 1:0] endp_free = 0; 119 | 120 | 121 | wire token_received = 122 | rx_pkt_end && 123 | rx_pkt_valid && 124 | rx_pid[1:0] == 2'b01 && 125 | rx_addr == dev_addr && 126 | rx_endp < NUM_IN_EPS; 127 | 128 | wire setup_token_received = 129 | token_received && 130 | rx_pid[3:2] == 2'b11; 131 | 132 | wire in_token_received = 133 | token_received && 134 | rx_pid[3:2] == 2'b10; 135 | 136 | wire ack_received = 137 | rx_pkt_end && 138 | rx_pkt_valid && 139 | rx_pid == 4'b0010; 140 | 141 | wire more_data_to_send = 142 | ep_get_addr[current_endp][5:0] < ep_put_addr[current_endp][5:0]; 143 | 144 | wire [5:0] current_ep_get_addr = ep_get_addr[current_endp][5:0]; 145 | wire [5:0] current_ep_put_addr = ep_put_addr[current_endp][5:0]; 146 | 147 | 148 | 149 | 150 | wire tx_data_avail_i = 151 | in_xfr_state == SEND_DATA && 152 | more_data_to_send; 153 | 154 | assign tx_data_avail = tx_data_avail_i; 155 | 156 | 157 | 158 | //////////////////////////////////////////////////////////////////////////////// 159 | // endpoint state machine 160 | //////////////////////////////////////////////////////////////////////////////// 161 | 162 | 163 | genvar ep_num; 164 | generate 165 | for (ep_num = 0; ep_num < NUM_IN_EPS; ep_num = ep_num + 1) begin 166 | always @* begin 167 | in_ep_acked[ep_num] <= 0; 168 | 169 | ep_state_next[ep_num] <= ep_state[ep_num]; 170 | 171 | if (in_ep_stall[ep_num]) begin 172 | ep_state_next[ep_num] <= STALL; 173 | 174 | end else begin 175 | case (ep_state[ep_num]) 176 | READY_FOR_PKT : begin 177 | ep_state_next[ep_num] <= PUTTING_PKT; 178 | end 179 | 180 | PUTTING_PKT : begin 181 | if ( 182 | ( 183 | in_ep_data_done[ep_num] 184 | ) || ( 185 | ep_put_addr[ep_num][5] 186 | ) 187 | ) begin 188 | ep_state_next[ep_num] <= GETTING_PKT; 189 | 190 | end else begin 191 | ep_state_next[ep_num] <= PUTTING_PKT; 192 | end 193 | end 194 | 195 | GETTING_PKT : begin 196 | if (in_xfr_end && current_endp == ep_num) begin 197 | ep_state_next[ep_num] <= READY_FOR_PKT; 198 | in_ep_acked[ep_num] <= 1; 199 | 200 | end else begin 201 | ep_state_next[ep_num] <= GETTING_PKT; 202 | end 203 | end 204 | 205 | STALL : begin 206 | if (setup_token_received && rx_endp == ep_num) begin 207 | ep_state_next[ep_num] <= READY_FOR_PKT; 208 | 209 | end else begin 210 | ep_state_next[ep_num] <= STALL; 211 | end 212 | end 213 | 214 | default begin 215 | ep_state_next[ep_num] <= READY_FOR_PKT; 216 | end 217 | endcase 218 | end 219 | 220 | endp_free[ep_num] = !ep_put_addr[ep_num][5]; 221 | in_ep_data_free[ep_num] = endp_free[ep_num] && ep_state[ep_num] == PUTTING_PKT; 222 | end 223 | 224 | always @(posedge clk) begin 225 | if (reset || reset_ep[ep_num]) begin 226 | ep_state[ep_num] <= READY_FOR_PKT; 227 | 228 | end else begin 229 | ep_state[ep_num] <= ep_state_next[ep_num]; 230 | 231 | case (ep_state[ep_num]) 232 | READY_FOR_PKT : begin 233 | ep_put_addr[ep_num][5:0] <= 0; 234 | end 235 | 236 | PUTTING_PKT : begin 237 | if (in_ep_data_put[ep_num]) begin 238 | ep_put_addr[ep_num][5:0] <= ep_put_addr[ep_num][5:0] + 1; 239 | end 240 | end 241 | 242 | GETTING_PKT : begin 243 | end 244 | 245 | STALL : begin 246 | end 247 | endcase 248 | end 249 | end 250 | end 251 | endgenerate 252 | 253 | integer ep_num_decoder; 254 | always @* begin 255 | in_ep_num <= 0; 256 | 257 | for (ep_num_decoder = 0; ep_num_decoder < NUM_IN_EPS; ep_num_decoder = ep_num_decoder + 1) begin 258 | if (in_ep_data_put[ep_num_decoder]) begin 259 | in_ep_num <= ep_num_decoder; 260 | end 261 | end 262 | end 263 | 264 | always @(posedge clk) begin 265 | case (ep_state[in_ep_num]) 266 | PUTTING_PKT : begin 267 | if (in_ep_data_put[in_ep_num] && !ep_put_addr[in_ep_num][5]) begin 268 | in_data_buffer[buffer_put_addr] <= in_ep_data; 269 | end 270 | end 271 | endcase 272 | end 273 | 274 | 275 | //////////////////////////////////////////////////////////////////////////////// 276 | // in transfer state machine 277 | //////////////////////////////////////////////////////////////////////////////// 278 | 279 | reg rollback_in_xfr; 280 | 281 | always @* begin 282 | in_xfr_state_next <= in_xfr_state; 283 | in_xfr_start <= 0; 284 | in_xfr_end <= 0; 285 | tx_pkt_start <= 0; 286 | tx_pid <= 4'b0000; 287 | rollback_in_xfr <= 0; 288 | 289 | case (in_xfr_state) 290 | IDLE : begin 291 | rollback_in_xfr <= 1; 292 | 293 | if (in_token_received) begin 294 | in_xfr_state_next <= RCVD_IN; 295 | 296 | end else begin 297 | in_xfr_state_next <= IDLE; 298 | end 299 | end 300 | 301 | 302 | RCVD_IN : begin 303 | tx_pkt_start <= 1; 304 | 305 | if (ep_state[current_endp] == STALL) begin 306 | in_xfr_state_next <= IDLE; 307 | tx_pid <= 4'b1110; // STALL 308 | 309 | end else if (ep_state[current_endp] == GETTING_PKT) begin 310 | in_xfr_state_next <= SEND_DATA; 311 | tx_pid <= {data_toggle[current_endp], 3'b011}; // DATA0/1 312 | in_xfr_start <= 1; 313 | 314 | end else begin 315 | in_xfr_state_next <= IDLE; 316 | tx_pid <= 4'b1010; // NAK 317 | end 318 | end 319 | 320 | 321 | SEND_DATA : begin 322 | if (!more_data_to_send) begin 323 | in_xfr_state_next <= WAIT_ACK; 324 | 325 | end else begin 326 | in_xfr_state_next <= SEND_DATA; 327 | end 328 | end 329 | 330 | WAIT_ACK : begin 331 | // FIXME: need to handle smash/timeout 332 | if (ack_received) begin 333 | in_xfr_state_next <= IDLE; 334 | in_xfr_end <= 1; 335 | 336 | end else if (in_token_received) begin 337 | in_xfr_state_next <= RCVD_IN; 338 | rollback_in_xfr <= 1; 339 | 340 | end else if (rx_pkt_end) begin 341 | in_xfr_state_next <= IDLE; 342 | rollback_in_xfr <= 1; 343 | 344 | end else begin 345 | in_xfr_state_next <= WAIT_ACK; 346 | end 347 | end 348 | endcase 349 | end 350 | 351 | always @(posedge clk) 352 | tx_data <= in_data_buffer[buffer_get_addr]; 353 | 354 | integer j; 355 | always @(posedge clk) begin 356 | if (reset) begin 357 | in_xfr_state <= IDLE; 358 | 359 | end else begin 360 | in_xfr_state <= in_xfr_state_next; 361 | 362 | if (setup_token_received) begin 363 | data_toggle[rx_endp] <= 1; 364 | end 365 | 366 | if (in_token_received) begin 367 | current_endp <= rx_endp; 368 | end 369 | 370 | if (rollback_in_xfr) begin 371 | ep_get_addr[current_endp][5:0] <= 0; 372 | end 373 | 374 | case (in_xfr_state) 375 | IDLE : begin 376 | end 377 | 378 | RCVD_IN : begin 379 | end 380 | 381 | SEND_DATA : begin 382 | if (tx_data_get && tx_data_avail_i) begin 383 | ep_get_addr[current_endp][5:0] <= ep_get_addr[current_endp][5:0] + 1; 384 | end 385 | end 386 | 387 | WAIT_ACK : begin 388 | if (ack_received) begin 389 | data_toggle[current_endp] <= !data_toggle[current_endp]; 390 | end 391 | end 392 | endcase 393 | end 394 | 395 | for (j = 0; j < NUM_IN_EPS; j = j + 1) begin 396 | if (reset || reset_ep[j]) begin 397 | data_toggle[j] <= 0; 398 | ep_get_addr[j][5:0] <= 0; 399 | end 400 | end 401 | end 402 | 403 | endmodule 404 | -------------------------------------------------------------------------------- /usb/usb_fs_out_arb.v: -------------------------------------------------------------------------------- 1 | module usb_fs_out_arb #( 2 | parameter NUM_OUT_EPS = 1 3 | ) ( 4 | //////////////////// 5 | // endpoint interface 6 | //////////////////// 7 | input [NUM_OUT_EPS-1:0] out_ep_req, 8 | output reg [NUM_OUT_EPS-1:0] out_ep_grant 9 | ); 10 | integer i; 11 | reg grant; 12 | 13 | always @* begin 14 | grant = 0; 15 | 16 | for (i = 0; i < NUM_OUT_EPS; i = i + 1) begin 17 | out_ep_grant[i] <= 0; 18 | 19 | if (out_ep_req[i] && !grant) begin 20 | out_ep_grant[i] <= 1; 21 | grant = 1; 22 | end 23 | end 24 | end 25 | endmodule 26 | -------------------------------------------------------------------------------- /usb/usb_fs_out_pe.v: -------------------------------------------------------------------------------- 1 | // The OUT Protocol Engine receives data from the host. 2 | module usb_fs_out_pe #( 3 | parameter NUM_OUT_EPS = 1, 4 | parameter MAX_OUT_PACKET_SIZE = 32 5 | ) ( 6 | input clk, 7 | input reset, 8 | input [NUM_OUT_EPS-1:0] reset_ep, 9 | input [6:0] dev_addr, 10 | 11 | //////////////////// 12 | // endpoint interface 13 | //////////////////// 14 | output [NUM_OUT_EPS-1:0] out_ep_data_avail, 15 | output reg [NUM_OUT_EPS-1:0] out_ep_setup, 16 | input [NUM_OUT_EPS-1:0] out_ep_data_get, 17 | output reg [7:0] out_ep_data, 18 | input [NUM_OUT_EPS-1:0] out_ep_stall, 19 | output reg [NUM_OUT_EPS-1:0] out_ep_acked = 0, 20 | 21 | 22 | //////////////////// 23 | // rx path 24 | //////////////////// 25 | 26 | // Strobed on reception of packet. 27 | input rx_pkt_start, 28 | input rx_pkt_end, 29 | input rx_pkt_valid, 30 | 31 | // Most recent packet received. 32 | input [3:0] rx_pid, 33 | input [6:0] rx_addr, 34 | input [3:0] rx_endp, 35 | input [10:0] rx_frame_num, 36 | 37 | // rx_data is pushed into endpoint controller. 38 | input rx_data_put, 39 | input [7:0] rx_data, 40 | 41 | 42 | //////////////////// 43 | // tx path 44 | //////////////////// 45 | 46 | // Strobe to send new packet. 47 | output reg tx_pkt_start, 48 | input tx_pkt_end, 49 | output reg [3:0] tx_pid 50 | ); 51 | //////////////////////////////////////////////////////////////////////////////// 52 | // endpoint state machine 53 | //////////////////////////////////////////////////////////////////////////////// 54 | localparam READY_FOR_PKT = 0; 55 | localparam PUTTING_PKT = 1; 56 | localparam GETTING_PKT = 2; 57 | localparam STALL = 3; 58 | 59 | reg [1:0] ep_state [NUM_OUT_EPS - 1:0]; 60 | reg [1:0] ep_state_next [NUM_OUT_EPS - 1:0]; 61 | 62 | 63 | //////////////////////////////////////////////////////////////////////////////// 64 | // out transfer state machine 65 | //////////////////////////////////////////////////////////////////////////////// 66 | localparam IDLE = 0; 67 | localparam RCVD_OUT = 1; 68 | localparam RCVD_DATA_START = 2; 69 | localparam RCVD_DATA_END = 3; 70 | 71 | reg [1:0] out_xfr_state = IDLE; 72 | reg [1:0] out_xfr_state_next; 73 | 74 | reg out_xfr_start; 75 | reg new_pkt_end = 0; 76 | reg rollback_data = 0; 77 | 78 | 79 | reg [3:0] out_ep_num; 80 | 81 | 82 | reg [NUM_OUT_EPS - 1:0] out_ep_data_avail_i = 0; 83 | reg [NUM_OUT_EPS - 1:0] out_ep_data_avail_j = 0; 84 | 85 | // set when the endpoint buffer is unable to receive the out transfer 86 | reg nak_out_transfer = 0; 87 | 88 | // data toggle state 89 | reg [NUM_OUT_EPS - 1:0] data_toggle = 0; 90 | 91 | // latched on valid OUT/SETUP token 92 | reg [3:0] current_endp = 0; 93 | wire [1:0] current_ep_state = ep_state[current_endp]; 94 | 95 | // endpoint data buffer 96 | reg [7:0] out_data_buffer [(MAX_OUT_PACKET_SIZE * NUM_OUT_EPS) - 1:0]; 97 | 98 | // current get_addr when outputting a packet from the buffer 99 | reg [5:0] ep_get_addr [NUM_OUT_EPS - 1:0]; 100 | reg [5:0] ep_get_addr_next [NUM_OUT_EPS - 1:0]; 101 | 102 | 103 | // endpoint put_addrs when inputting a packet into the buffer 104 | reg [5:0] ep_put_addr [NUM_OUT_EPS - 1:0]; 105 | 106 | // total buffer put addr, uses endpoint number and that endpoints current 107 | // put address 108 | wire [8:0] buffer_put_addr = {current_endp[3:0], ep_put_addr[current_endp][4:0]}; 109 | wire [8:0] buffer_get_addr = {out_ep_num[3:0], ep_get_addr[out_ep_num][4:0]}; 110 | 111 | wire token_received = 112 | rx_pkt_end && 113 | rx_pkt_valid && 114 | rx_pid[1:0] == 2'b01 && 115 | rx_addr == dev_addr && 116 | rx_endp < NUM_OUT_EPS; 117 | 118 | wire out_token_received = 119 | token_received && 120 | rx_pid[3:2] == 2'b00; 121 | 122 | wire setup_token_received = 123 | token_received && 124 | rx_pid[3:2] == 2'b11; 125 | 126 | wire invalid_packet_received = 127 | rx_pkt_end && 128 | !rx_pkt_valid; 129 | 130 | wire data_packet_received = 131 | rx_pkt_end && 132 | rx_pkt_valid && 133 | rx_pid[2:0] == 3'b011; 134 | 135 | wire non_data_packet_received = 136 | rx_pkt_end && 137 | rx_pkt_valid && 138 | rx_pid[2:0] != 3'b011; 139 | 140 | //reg last_data_toggle = 0; 141 | 142 | wire bad_data_toggle = 143 | data_packet_received && 144 | rx_pid[3] != data_toggle[rx_endp]; 145 | 146 | //last_data_toggle == data_toggle[current_endp]; 147 | 148 | //////////////////////////////////////////////////////////////////////////////// 149 | // endpoint state machine 150 | //////////////////////////////////////////////////////////////////////////////// 151 | 152 | genvar ep_num; 153 | generate 154 | for (ep_num = 0; ep_num < NUM_OUT_EPS; ep_num = ep_num + 1) begin 155 | always @* begin 156 | 157 | ep_state_next[ep_num] <= ep_state[ep_num]; 158 | 159 | if (out_ep_stall[ep_num]) begin 160 | ep_state_next[ep_num] <= STALL; 161 | 162 | end else begin 163 | case (ep_state[ep_num]) 164 | READY_FOR_PKT : begin 165 | if (out_xfr_start && rx_endp == ep_num) begin 166 | ep_state_next[ep_num] <= PUTTING_PKT; 167 | 168 | end else begin 169 | ep_state_next[ep_num] <= READY_FOR_PKT; 170 | end 171 | end 172 | 173 | PUTTING_PKT : begin 174 | if (new_pkt_end && current_endp == ep_num) begin 175 | ep_state_next[ep_num] <= GETTING_PKT; 176 | 177 | end else if (rollback_data && current_endp == ep_num) begin 178 | ep_state_next[ep_num] <= READY_FOR_PKT; 179 | 180 | end else begin 181 | ep_state_next[ep_num] <= PUTTING_PKT; 182 | end 183 | end 184 | 185 | GETTING_PKT : begin 186 | 187 | if (ep_get_addr[ep_num][5:0] >= (ep_put_addr[ep_num][5:0] - 2)) begin 188 | ep_state_next[ep_num] <= READY_FOR_PKT; 189 | 190 | end else begin 191 | ep_state_next[ep_num] <= GETTING_PKT; 192 | end 193 | end 194 | 195 | STALL : begin 196 | if (setup_token_received && rx_endp == ep_num) begin 197 | ep_state_next[ep_num] <= READY_FOR_PKT; 198 | 199 | end else begin 200 | ep_state_next[ep_num] <= STALL; 201 | end 202 | end 203 | 204 | default begin 205 | ep_state_next[ep_num] <= READY_FOR_PKT; 206 | end 207 | endcase 208 | end 209 | 210 | if (ep_state_next[ep_num][1:0] == READY_FOR_PKT) begin 211 | ep_get_addr_next[ep_num][5:0] <= 0; 212 | end else if (ep_state_next[ep_num][1:0] == GETTING_PKT && out_ep_data_get[ep_num]) begin 213 | ep_get_addr_next[ep_num][5:0] <= ep_get_addr[ep_num][5:0] + 1; 214 | end else begin 215 | ep_get_addr_next[ep_num][5:0] <= ep_get_addr[ep_num][5:0]; 216 | end 217 | end 218 | 219 | always @(posedge clk) begin 220 | if (reset || reset_ep[ep_num]) begin 221 | ep_state[ep_num] <= READY_FOR_PKT; 222 | end else begin 223 | ep_state[ep_num] <= ep_state_next[ep_num]; 224 | end 225 | 226 | ep_get_addr[ep_num][5:0] <= ep_get_addr_next[ep_num][5:0]; 227 | end 228 | 229 | 230 | assign out_ep_data_avail[ep_num] = 231 | (ep_get_addr[ep_num][5:0] < (ep_put_addr[ep_num][5:0] - 2)) && 232 | (ep_state[ep_num][1:0] == GETTING_PKT); 233 | 234 | 235 | 236 | end 237 | endgenerate 238 | 239 | integer i; 240 | always @(posedge clk) begin 241 | if (reset) begin 242 | out_ep_setup <= 0; 243 | 244 | end else begin 245 | if (setup_token_received) begin 246 | out_ep_setup[rx_endp] <= 1; 247 | end else if (out_token_received) begin 248 | out_ep_setup[rx_endp] <= 0; 249 | end 250 | end 251 | 252 | for (i = 0; i < NUM_OUT_EPS; i = i + 1) begin 253 | if (reset_ep[i]) begin 254 | out_ep_setup[i] <= 0; 255 | end 256 | end 257 | end 258 | 259 | always @(posedge clk) out_ep_data <= out_data_buffer[buffer_get_addr][7:0]; 260 | 261 | integer ep_num_decoder; 262 | always @* begin 263 | out_ep_num <= 0; 264 | 265 | for (ep_num_decoder = 0; ep_num_decoder < NUM_OUT_EPS; ep_num_decoder = ep_num_decoder + 1) begin 266 | if (out_ep_data_get[ep_num_decoder]) begin 267 | out_ep_num <= ep_num_decoder; 268 | end 269 | end 270 | end 271 | 272 | //////////////////////////////////////////////////////////////////////////////// 273 | // out transfer state machine 274 | //////////////////////////////////////////////////////////////////////////////// 275 | 276 | always @* begin 277 | out_ep_acked <= 0; 278 | out_xfr_start <= 0; 279 | out_xfr_state_next <= out_xfr_state; 280 | tx_pkt_start <= 0; 281 | tx_pid <= 0; 282 | new_pkt_end <= 0; 283 | rollback_data <= 0; 284 | 285 | case (out_xfr_state) 286 | IDLE : begin 287 | if (out_token_received || setup_token_received) begin 288 | out_xfr_state_next <= RCVD_OUT; 289 | out_xfr_start <= 1; 290 | end else begin 291 | out_xfr_state_next <= IDLE; 292 | end 293 | end 294 | 295 | RCVD_OUT : begin 296 | if (rx_pkt_start) begin 297 | out_xfr_state_next <= RCVD_DATA_START; 298 | end else begin 299 | out_xfr_state_next <= RCVD_OUT; 300 | end 301 | end 302 | 303 | RCVD_DATA_START : begin 304 | if (bad_data_toggle) begin 305 | out_xfr_state_next <= IDLE; 306 | rollback_data <= 1; 307 | tx_pkt_start <= 1; 308 | tx_pid <= 4'b0010; // ACK 309 | 310 | end else if (invalid_packet_received || non_data_packet_received) begin 311 | out_xfr_state_next <= IDLE; 312 | rollback_data <= 1; 313 | 314 | end else if (data_packet_received) begin 315 | out_xfr_state_next <= RCVD_DATA_END; 316 | 317 | end else begin 318 | out_xfr_state_next <= RCVD_DATA_START; 319 | end 320 | end 321 | 322 | RCVD_DATA_END : begin 323 | out_xfr_state_next <= IDLE; 324 | tx_pkt_start <= 1; 325 | 326 | if (ep_state[current_endp] == STALL) begin 327 | tx_pid <= 4'b1110; // STALL 328 | 329 | end else if (nak_out_transfer) begin 330 | tx_pid <= 4'b1010; // NAK 331 | rollback_data <= 1; 332 | 333 | end else begin 334 | tx_pid <= 4'b0010; // ACK 335 | new_pkt_end <= 1; 336 | out_ep_acked[current_endp] <= 1; 337 | 338 | //end else begin 339 | // tx_pid <= 4'b0010; // ACK 340 | // rollback_data <= 1; 341 | end 342 | end 343 | 344 | default begin 345 | out_xfr_state_next <= IDLE; 346 | end 347 | endcase 348 | end 349 | 350 | wire current_ep_busy = 351 | (ep_state[current_endp] == GETTING_PKT) || 352 | (ep_state[current_endp] == READY_FOR_PKT); 353 | 354 | integer j; 355 | always @(posedge clk) begin 356 | if (reset) begin 357 | out_xfr_state <= IDLE; 358 | end else begin 359 | out_xfr_state <= out_xfr_state_next; 360 | 361 | if (out_xfr_start) begin 362 | current_endp <= rx_endp; 363 | //last_data_toggle <= setup_token_received ? 0 : data_toggle[rx_endp]; 364 | end 365 | 366 | if (new_pkt_end) begin 367 | data_toggle[current_endp] <= !data_toggle[current_endp]; 368 | end 369 | 370 | if (setup_token_received) begin 371 | data_toggle[rx_endp] <= 0; 372 | end 373 | 374 | case (out_xfr_state) 375 | IDLE : begin 376 | end 377 | 378 | RCVD_OUT : begin 379 | if (current_ep_busy) begin 380 | nak_out_transfer <= 1; 381 | end else begin 382 | nak_out_transfer <= 0; 383 | ep_put_addr[current_endp][5:0] <= 0; 384 | end 385 | end 386 | 387 | RCVD_DATA_START : begin 388 | if (!nak_out_transfer && rx_data_put && !ep_put_addr[current_endp][5]) begin 389 | out_data_buffer[buffer_put_addr][7:0] <= rx_data; 390 | end 391 | 392 | if (!nak_out_transfer && rx_data_put) begin 393 | ep_put_addr[current_endp][5:0] <= ep_put_addr[current_endp][5:0] + 1; 394 | 395 | end 396 | end 397 | 398 | RCVD_DATA_END : begin 399 | end 400 | endcase 401 | end 402 | 403 | for (j = 0; j < NUM_OUT_EPS; j = j + 1) begin 404 | if (reset || reset_ep[j]) begin 405 | data_toggle[j] <= 0; 406 | ep_put_addr[j][5:0] <= 0; 407 | end 408 | end 409 | end 410 | 411 | endmodule 412 | -------------------------------------------------------------------------------- /usb/usb_fs_pe.v: -------------------------------------------------------------------------------- 1 | `include "usb_fs_in_arb.v" 2 | `include "usb_fs_in_pe.v" 3 | `include "usb_fs_out_arb.v" 4 | `include "usb_fs_out_pe.v" 5 | `include "usb_fs_tx.v" 6 | `include "usb_fs_tx_mux.v" 7 | `include "usb_fs_rx.v" 8 | 9 | module usb_fs_pe #( 10 | parameter [4:0] NUM_OUT_EPS = 1, 11 | parameter [4:0] NUM_IN_EPS = 1 12 | ) ( 13 | input clk_48mhz, 14 | input clk, 15 | input [6:0] dev_addr, 16 | 17 | //////////////////////////////////////////////////////////////////////////////// 18 | //////////////////////////////////////////////////////////////////////////////// 19 | /// USB Endpoint Interface 20 | //////////////////////////////////////////////////////////////////////////////// 21 | //////////////////////////////////////////////////////////////////////////////// 22 | 23 | //////////////////// 24 | // global endpoint interface 25 | //////////////////// 26 | input reset, 27 | 28 | 29 | //////////////////// 30 | // out endpoint interfaces 31 | //////////////////// 32 | input [NUM_OUT_EPS-1:0] out_ep_req, 33 | output [NUM_OUT_EPS-1:0] out_ep_grant, 34 | output [NUM_OUT_EPS-1:0] out_ep_data_avail, 35 | output [NUM_OUT_EPS-1:0] out_ep_setup, 36 | input [NUM_OUT_EPS-1:0] out_ep_data_get, 37 | output [7:0] out_ep_data, 38 | input [NUM_OUT_EPS-1:0] out_ep_stall, 39 | output [NUM_OUT_EPS-1:0] out_ep_acked, 40 | 41 | 42 | //////////////////// 43 | // in endpoint interfaces 44 | //////////////////// 45 | input [NUM_IN_EPS-1:0] in_ep_req, 46 | output [NUM_IN_EPS-1:0] in_ep_grant, 47 | output [NUM_IN_EPS-1:0] in_ep_data_free, 48 | input [NUM_IN_EPS-1:0] in_ep_data_put, 49 | input [(NUM_IN_EPS*8)-1:0] in_ep_data, 50 | input [NUM_IN_EPS-1:0] in_ep_data_done, 51 | input [NUM_IN_EPS-1:0] in_ep_stall, 52 | output [NUM_IN_EPS-1:0] in_ep_acked, 53 | 54 | 55 | //////////////////// 56 | // sof interface 57 | //////////////////// 58 | output sof_valid, 59 | output [10:0] frame_index, 60 | 61 | 62 | 63 | //////////////////////////////////////////////////////////////////////////////// 64 | //////////////////////////////////////////////////////////////////////////////// 65 | /// USB TX/RX Interface 66 | //////////////////////////////////////////////////////////////////////////////// 67 | //////////////////////////////////////////////////////////////////////////////// 68 | output usb_p_tx, 69 | output usb_n_tx, 70 | 71 | input usb_p_rx, 72 | input usb_n_rx, 73 | 74 | output usb_tx_en 75 | ); 76 | // in pe interface 77 | wire [7:0] arb_in_ep_data; 78 | 79 | // rx interface 80 | wire bit_strobe; 81 | wire rx_pkt_start; 82 | wire rx_pkt_end; 83 | wire [3:0] rx_pid; 84 | wire [6:0] rx_addr; 85 | wire [3:0] rx_endp; 86 | wire [10:0] rx_frame_num; 87 | wire rx_data_put; 88 | wire [7:0] rx_data; 89 | wire rx_pkt_valid; 90 | 91 | // tx mux 92 | wire in_tx_pkt_start; 93 | wire [3:0] in_tx_pid; 94 | wire out_tx_pkt_start; 95 | wire [3:0] out_tx_pid; 96 | 97 | // tx interface 98 | wire tx_pkt_start; 99 | wire tx_pkt_end; 100 | wire [3:0] tx_pid; 101 | wire tx_data_avail; 102 | wire tx_data_get; 103 | wire [7:0] tx_data; 104 | 105 | // sof interface 106 | assign sof_valid = rx_pkt_end && rx_pkt_valid && rx_pid == 4'b0101; 107 | assign frame_index = rx_frame_num; 108 | 109 | 110 | usb_fs_in_arb #( 111 | .NUM_IN_EPS(NUM_IN_EPS) 112 | ) usb_fs_in_arb_inst ( 113 | // endpoint interface 114 | .in_ep_req(in_ep_req), 115 | .in_ep_grant(in_ep_grant), 116 | .in_ep_data(in_ep_data), 117 | 118 | // protocol engine interface 119 | .arb_in_ep_data(arb_in_ep_data) 120 | ); 121 | 122 | usb_fs_out_arb #( 123 | .NUM_OUT_EPS(NUM_OUT_EPS) 124 | ) usb_fs_out_arb_inst ( 125 | // endpoint interface 126 | .out_ep_req(out_ep_req), 127 | .out_ep_grant(out_ep_grant) 128 | ); 129 | 130 | usb_fs_in_pe #( 131 | .NUM_IN_EPS(NUM_IN_EPS) 132 | ) usb_fs_in_pe_inst ( 133 | .clk(clk), 134 | .reset(reset), 135 | .reset_ep({NUM_IN_EPS{1'b0}}), 136 | .dev_addr(dev_addr), 137 | 138 | // endpoint interface 139 | .in_ep_data_free(in_ep_data_free), 140 | .in_ep_data_put(in_ep_data_put), 141 | .in_ep_data(arb_in_ep_data), 142 | .in_ep_data_done(in_ep_data_done), 143 | .in_ep_stall(in_ep_stall), 144 | .in_ep_acked(in_ep_acked), 145 | 146 | // rx path 147 | .rx_pkt_start(rx_pkt_start), 148 | .rx_pkt_end(rx_pkt_end), 149 | .rx_pkt_valid(rx_pkt_valid), 150 | .rx_pid(rx_pid), 151 | .rx_addr(rx_addr), 152 | .rx_endp(rx_endp), 153 | .rx_frame_num(rx_frame_num), 154 | 155 | // tx path 156 | .tx_pkt_start(in_tx_pkt_start), 157 | .tx_pkt_end(tx_pkt_end), 158 | .tx_pid(in_tx_pid), 159 | .tx_data_avail(tx_data_avail), 160 | .tx_data_get(tx_data_get), 161 | .tx_data(tx_data) 162 | ); 163 | 164 | usb_fs_out_pe #( 165 | .NUM_OUT_EPS(NUM_OUT_EPS) 166 | ) usb_fs_out_pe_inst ( 167 | .clk(clk), 168 | .reset(reset), 169 | .reset_ep({NUM_OUT_EPS{1'b0}}), 170 | .dev_addr(dev_addr), 171 | 172 | // endpoint interface 173 | .out_ep_data_avail(out_ep_data_avail), 174 | .out_ep_data_get(out_ep_data_get), 175 | .out_ep_data(out_ep_data), 176 | .out_ep_setup(out_ep_setup), 177 | .out_ep_stall(out_ep_stall), 178 | .out_ep_acked(out_ep_acked), 179 | 180 | // rx path 181 | .rx_pkt_start(rx_pkt_start), 182 | .rx_pkt_end(rx_pkt_end), 183 | .rx_pkt_valid(rx_pkt_valid), 184 | .rx_pid(rx_pid), 185 | .rx_addr(rx_addr), 186 | .rx_endp(rx_endp), 187 | .rx_frame_num(rx_frame_num), 188 | .rx_data_put(rx_data_put), 189 | .rx_data(rx_data), 190 | 191 | // tx path 192 | .tx_pkt_start(out_tx_pkt_start), 193 | .tx_pkt_end(tx_pkt_end), 194 | .tx_pid(out_tx_pid) 195 | ); 196 | 197 | usb_fs_rx usb_fs_rx_inst ( 198 | .clk_48mhz(clk_48mhz), 199 | .clk(clk), 200 | .reset(reset), 201 | .dp(usb_p_rx), 202 | .dn(usb_n_rx), 203 | .bit_strobe(bit_strobe), 204 | .pkt_start(rx_pkt_start), 205 | .pkt_end(rx_pkt_end), 206 | .pid(rx_pid), 207 | .addr(rx_addr), 208 | .endp(rx_endp), 209 | .frame_num(rx_frame_num), 210 | .rx_data_put(rx_data_put), 211 | .rx_data(rx_data), 212 | .valid_packet(rx_pkt_valid) 213 | ); 214 | 215 | usb_fs_tx_mux usb_fs_tx_mux_inst ( 216 | // interface to IN Protocol Engine 217 | .in_tx_pkt_start(in_tx_pkt_start), 218 | .in_tx_pid(in_tx_pid), 219 | 220 | // interface to OUT Protocol Engine 221 | .out_tx_pkt_start(out_tx_pkt_start), 222 | .out_tx_pid(out_tx_pid), 223 | 224 | // interface to tx module 225 | .tx_pkt_start(tx_pkt_start), 226 | .tx_pid(tx_pid) 227 | ); 228 | 229 | usb_fs_tx usb_fs_tx_inst ( 230 | .clk_48mhz(clk_48mhz), 231 | .clk(clk), 232 | .reset(reset), 233 | .bit_strobe(bit_strobe), 234 | .oe(usb_tx_en), 235 | .dp(usb_p_tx), 236 | .dn(usb_n_tx), 237 | .pkt_start(tx_pkt_start), 238 | .pkt_end(tx_pkt_end), 239 | .pid(tx_pid), 240 | .tx_data_avail(tx_data_avail), 241 | .tx_data_get(tx_data_get), 242 | .tx_data(tx_data) 243 | ); 244 | endmodule 245 | -------------------------------------------------------------------------------- /usb/usb_fs_rx.v: -------------------------------------------------------------------------------- 1 | `include "strobe.v" 2 | 3 | module usb_fs_rx ( 4 | // A 48MHz clock is required to recover the clock from the incoming data. 5 | input clk_48mhz, 6 | input clk, 7 | input reset, 8 | 9 | // USB data+ and data- lines (clk_48mhz domain) 10 | input dp, 11 | input dn, 12 | 13 | // pulse on every bit transition (clk_48mhz domain) 14 | output bit_strobe, 15 | 16 | // Pulse on beginning of new packet (clk domain) 17 | output pkt_start, 18 | 19 | // Pulse on end of current packet (clk domain) 20 | output pkt_end, 21 | 22 | // Most recent packet decoded (clk domain) 23 | output [3:0] pid, 24 | output [6:0] addr, 25 | output [3:0] endp, 26 | output [10:0] frame_num, 27 | 28 | // Pulse on valid data on rx_data (clk domain) 29 | output rx_data_put, 30 | output [7:0] rx_data, 31 | 32 | // Most recent packet passes PID and CRC checks (clk domain) 33 | output valid_packet 34 | ); 35 | wire [3:0] pid_48; 36 | reg [6:0] addr_48; 37 | reg [3:0] endp_48; 38 | reg [10:0] frame_num_48; 39 | //////////////////////////////////////////////////////////////////////////////// 40 | //////////////////////////////////////////////////////////////////////////////// 41 | //////// 42 | //////// usb receive path 43 | //////// 44 | //////////////////////////////////////////////////////////////////////////////// 45 | //////////////////////////////////////////////////////////////////////////////// 46 | 47 | 48 | //////////////////////////////////////////////////////////////////////////////// 49 | // double flop for metastability 50 | /* 51 | all asynchronous inputs into the RTL need to be double-flopped to protect 52 | against metastable scenarios. if the RTL clock samples an asynchronous signal 53 | at the same time the signal is transitioning the result is undefined. flopping 54 | the signal twice ensures it will be either 1 or 0 and nothing in between. 55 | */ 56 | 57 | reg [3:0] dpair_q = 0; 58 | 59 | always @(posedge clk_48mhz) begin 60 | dpair_q[3:0] <= {dpair_q[1:0], dp, dn}; 61 | end 62 | 63 | 64 | //////////////////////////////////////////////////////////////////////////////// 65 | // line state recovery state machine 66 | /* 67 | the recieve path doesn't currently use a differential reciever. because of 68 | this there is a chance that one of the differential pairs will appear to have 69 | changed to the new state while the other is still in the old state. the 70 | following state machine detects transitions and waits an extra sampling clock 71 | before decoding the state on the differential pair. this transition period 72 | will only ever last for one clock as long as there is no noise on the line. 73 | if there is enough noise on the line then the data may be corrupted and the 74 | packet will fail the data integrity checks. 75 | */ 76 | 77 | reg [2:0] line_state = 0; 78 | localparam DT = 3'b100; 79 | localparam DJ = 3'b010; 80 | localparam DK = 3'b001; 81 | localparam SE0 = 3'b000; 82 | localparam SE1 = 3'b011; 83 | 84 | wire [1:0] dpair = dpair_q[3:2]; 85 | 86 | always @(posedge clk_48mhz) begin 87 | case (line_state) 88 | // if we are in a transition state, then we can sample the pair and 89 | // move to the next corresponding line state 90 | DT : begin 91 | case (dpair) 92 | 2'b10 : line_state <= DJ; 93 | 2'b01 : line_state <= DK; 94 | 2'b00 : line_state <= SE0; 95 | 2'b11 : line_state <= SE1; 96 | endcase 97 | end 98 | 99 | // if we are in a valid line state and the value of the pair changes, 100 | // then we need to move to the transition state 101 | DJ : if (dpair != 2'b10) line_state <= DT; 102 | DK : if (dpair != 2'b01) line_state <= DT; 103 | SE0 : if (dpair != 2'b00) line_state <= DT; 104 | SE1 : if (dpair != 2'b11) line_state <= DT; 105 | 106 | // if we are in an invalid state we should move to the transition state 107 | default : line_state <= DT; 108 | endcase 109 | end 110 | 111 | 112 | //////////////////////////////////////////////////////////////////////////////// 113 | // clock recovery 114 | /* 115 | the DT state from the line state recovery state machine is used to align to 116 | transmit clock. the line state is sampled in the middle of the bit time. 117 | 118 | example of signal relationships 119 | ------------------------------- 120 | line_state DT DJ DJ DJ DT DK DK DK DK DK DK DT DJ DJ DJ 121 | line_state_valid ________----____________----____________----________----____ 122 | bit_phase 0 0 1 2 3 0 1 2 3 0 1 2 0 1 2 123 | */ 124 | 125 | reg [1:0] bit_phase = 0; 126 | 127 | wire line_state_valid = (bit_phase == 1); 128 | assign bit_strobe = (bit_phase == 2); 129 | 130 | always @(posedge clk_48mhz) begin 131 | // keep track of phase within each bit 132 | if (line_state == DT) begin 133 | bit_phase <= 0; 134 | 135 | end else begin 136 | bit_phase <= bit_phase + 1; 137 | end 138 | end 139 | 140 | 141 | //////////////////////////////////////////////////////////////////////////////// 142 | // packet detection 143 | /* 144 | usb uses a sync to denote the beginning of a packet and two single-ended-0 to 145 | denote the end of a packet. this state machine recognizes the beginning and 146 | end of packets for subsequent layers to process. 147 | */ 148 | reg [5:0] line_history = 0; 149 | reg packet_valid = 0; 150 | reg next_packet_valid; 151 | wire packet_start = next_packet_valid && !packet_valid; 152 | wire packet_end = !next_packet_valid && packet_valid; 153 | 154 | always @* begin 155 | if (line_state_valid) begin 156 | // check for packet start: KJKJKK 157 | if (!packet_valid && line_history[5:0] == 6'b100101) begin 158 | next_packet_valid <= 1; 159 | end 160 | 161 | // check for packet end: SE0 SE0 162 | else if (packet_valid && line_history[3:0] == 4'b0000) begin 163 | next_packet_valid <= 0; 164 | 165 | end else begin 166 | next_packet_valid <= packet_valid; 167 | end 168 | end else begin 169 | next_packet_valid <= packet_valid; 170 | end 171 | end 172 | 173 | always @(posedge clk_48mhz) begin 174 | if (reset) begin 175 | line_history <= 6'b101010; 176 | packet_valid <= 0; 177 | end else begin 178 | // keep a history of the last two states on the line 179 | if (line_state_valid) begin 180 | line_history[5:0] <= {line_history[3:0], line_state[1:0]}; 181 | end 182 | end 183 | packet_valid <= next_packet_valid; 184 | end 185 | 186 | 187 | //////////////////////////////////////////////////////////////////////////////// 188 | // NRZI decode 189 | /* 190 | in order to ensure there are enough bit transitions for a receiver to recover 191 | the clock usb uses NRZI encoding. 192 | 193 | https://en.wikipedia.org/wiki/Non-return-to-zero 194 | */ 195 | reg dvalid_raw; 196 | reg din; 197 | 198 | always @* begin 199 | case (line_history[3:0]) 200 | 4'b0101 : din <= 1; 201 | 4'b0110 : din <= 0; 202 | 4'b1001 : din <= 0; 203 | 4'b1010 : din <= 1; 204 | default : din <= 0; 205 | endcase 206 | 207 | if (packet_valid && line_state_valid) begin 208 | case (line_history[3:0]) 209 | 4'b0101 : dvalid_raw <= 1; 210 | 4'b0110 : dvalid_raw <= 1; 211 | 4'b1001 : dvalid_raw <= 1; 212 | 4'b1010 : dvalid_raw <= 1; 213 | default : dvalid_raw <= 0; 214 | endcase 215 | end else begin 216 | dvalid_raw <= 0; 217 | end 218 | end 219 | 220 | reg [5:0] bitstuff_history = 0; 221 | 222 | always @(posedge clk_48mhz) begin 223 | if (reset || packet_end) begin 224 | bitstuff_history <= 6'b000000; 225 | end else begin 226 | if (dvalid_raw) begin 227 | bitstuff_history <= {bitstuff_history[4:0], din}; 228 | end 229 | end 230 | end 231 | 232 | wire dvalid = dvalid_raw && !(bitstuff_history == 6'b111111); 233 | 234 | 235 | //////////////////////////////////////////////////////////////////////////////// 236 | // save and check pid 237 | /* 238 | shift in the entire 8-bit pid with an additional 9th bit used as a sentinal. 239 | */ 240 | 241 | reg [8:0] full_pid = 0; 242 | wire pid_valid = full_pid[4:1] == ~full_pid[8:5]; 243 | wire pid_complete = full_pid[0]; 244 | 245 | always @(posedge clk_48mhz) begin 246 | if (packet_start) begin 247 | full_pid <= 9'b100000000; 248 | end 249 | 250 | if (dvalid && !pid_complete) begin 251 | full_pid <= {din, full_pid[8:1]}; 252 | end 253 | end 254 | 255 | 256 | //////////////////////////////////////////////////////////////////////////////// 257 | // check crc5 258 | reg [4:0] crc5 = 0; 259 | wire crc5_valid = crc5 == 5'b01100; 260 | wire crc5_invert = din ^ crc5[4]; 261 | always @(posedge clk_48mhz) begin 262 | if (packet_start) begin 263 | crc5 <= 5'b11111; 264 | end 265 | 266 | if (dvalid && pid_complete) begin 267 | crc5[4] <= crc5[3]; 268 | crc5[3] <= crc5[2]; 269 | crc5[2] <= crc5[1] ^ crc5_invert; 270 | crc5[1] <= crc5[0]; 271 | crc5[0] <= crc5_invert; 272 | end 273 | end 274 | 275 | 276 | //////////////////////////////////////////////////////////////////////////////// 277 | // check crc16 278 | reg [15:0] crc16 = 0; 279 | wire crc16_valid = crc16 == 16'b1000000000001101; 280 | wire crc16_invert = din ^ crc16[15]; 281 | 282 | always @(posedge clk_48mhz) begin 283 | if (packet_start) begin 284 | crc16 <= 16'b1111111111111111; 285 | end 286 | 287 | if (dvalid && pid_complete) begin 288 | crc16[15] <= crc16[14] ^ crc16_invert; 289 | crc16[14] <= crc16[13]; 290 | crc16[13] <= crc16[12]; 291 | crc16[12] <= crc16[11]; 292 | crc16[11] <= crc16[10]; 293 | crc16[10] <= crc16[9]; 294 | crc16[9] <= crc16[8]; 295 | crc16[8] <= crc16[7]; 296 | crc16[7] <= crc16[6]; 297 | crc16[6] <= crc16[5]; 298 | crc16[5] <= crc16[4]; 299 | crc16[4] <= crc16[3]; 300 | crc16[3] <= crc16[2]; 301 | crc16[2] <= crc16[1] ^ crc16_invert; 302 | crc16[1] <= crc16[0]; 303 | crc16[0] <= crc16_invert; 304 | end 305 | end 306 | 307 | 308 | //////////////////////////////////////////////////////////////////////////////// 309 | // output control signals 310 | wire pkt_is_token = full_pid[2:1] == 2'b01; 311 | wire pkt_is_data = full_pid[2:1] == 2'b11; 312 | wire pkt_is_handshake = full_pid[2:1] == 2'b10; 313 | 314 | 315 | // TODO: need to check for data packet babble 316 | // TODO: do i need to check for bitstuff error? 317 | wire valid_packet_48 = pid_valid && ( 318 | (pkt_is_handshake) || 319 | (pkt_is_data && crc16_valid) || 320 | (pkt_is_token && crc5_valid) 321 | ); 322 | 323 | // valid is level, not a strobe 324 | dflip valid_buffer(clk, valid_packet_48, valid_packet); 325 | 326 | reg [11:0] token_payload = 0; 327 | wire token_payload_done = token_payload[0]; 328 | 329 | always @(posedge clk_48mhz) begin 330 | if (packet_start) begin 331 | token_payload <= 12'b100000000000; 332 | end 333 | 334 | if (dvalid && pid_complete && pkt_is_token && !token_payload_done) begin 335 | token_payload <= {din, token_payload[11:1]}; 336 | end 337 | end 338 | 339 | always @(posedge clk_48mhz) begin 340 | if (token_payload_done && pkt_is_token) begin 341 | addr_48 <= token_payload[7:1]; 342 | endp_48 <= token_payload[11:8]; 343 | frame_num_48 <= token_payload[11:1]; 344 | end 345 | end 346 | 347 | // cross the packet start signal to the endpoint clk domain 348 | strobe pkt_start_strobe( 349 | .clk_in(clk_48mhz), 350 | .clk_out(clk), 351 | .strobe_in(packet_start), 352 | .strobe_out(pkt_start) 353 | ); 354 | 355 | // at the end of the packet, capture the parameters to the clk domain 356 | strobe #(.WIDTH(26)) pkt_end_strobe( 357 | clk_48mhz, clk, 358 | packet_end, pkt_end, 359 | { pid_48, addr_48, endp_48, frame_num_48 }, 360 | { pid, addr, endp, frame_num } 361 | ); 362 | assign pid_48 = full_pid[4:1]; 363 | 364 | //assign addr = token_payload[7:1]; 365 | //assign endp = token_payload[11:8]; 366 | //assign frame_num = token_payload[11:1]; 367 | 368 | 369 | //////////////////////////////////////////////////////////////////////////////// 370 | // deserialize and output data 371 | //assign rx_data_put = dvalid && pid_complete && pkt_is_data; 372 | reg [8:0] rx_data_buffer = 0; 373 | wire rx_data_buffer_full = rx_data_buffer[0]; 374 | 375 | // convert the rx_data_put to clk domain 376 | strobe #(.WIDTH(8)) rx_data_strobe( 377 | clk_48mhz, clk, 378 | rx_data_buffer_full, rx_data_put, 379 | rx_data_buffer[8:1], rx_data 380 | ); 381 | 382 | always @(posedge clk_48mhz) begin 383 | if (packet_start || rx_data_buffer_full) begin 384 | rx_data_buffer <= 9'b100000000; 385 | end 386 | 387 | if (dvalid && pid_complete && pkt_is_data) begin 388 | rx_data_buffer <= {din, rx_data_buffer[8:1]}; 389 | end 390 | end 391 | 392 | endmodule // usb_fs_rx 393 | -------------------------------------------------------------------------------- /usb/usb_fs_tx.v: -------------------------------------------------------------------------------- 1 | `include "strobe.v" 2 | 3 | module usb_fs_tx ( 4 | // A 48MHz clock is required to receive USB data at 12MHz 5 | // it's simpler to juse use 48MHz everywhere 6 | input clk_48mhz, 7 | input clk, 8 | input reset, 9 | 10 | // bit strobe from rx to align with senders clock (in clk_48mhz domain) 11 | input bit_strobe, 12 | 13 | // output enable to take ownership of bus and data out 14 | output reg oe = 0, 15 | output reg dp = 0, 16 | output reg dn = 0, 17 | 18 | // pulse to initiate new packet transmission (clk domain) 19 | input pkt_start, 20 | 21 | // pulse to indicate end of packet transmission (clk domain) 22 | output pkt_end, 23 | 24 | // pid to send (clk domain) 25 | input [3:0] pid, 26 | 27 | // tx logic pulls data until there is nothing available 28 | input tx_data_avail, 29 | output tx_data_get, 30 | input [7:0] tx_data 31 | ); 32 | // convert pkt_start to clk_48mhz domain 33 | // save packet parameters at pkt_start 34 | wire pkt_start_48; 35 | wire [3:0] pidq; 36 | strobe #(.WIDTH(4)) pkt_start_strobe( 37 | clk, clk_48mhz, 38 | pkt_start, pkt_start_48, 39 | pid, pidq 40 | ); 41 | 42 | wire tx_data_avail_48; 43 | dflip tx_data_avail_buffer(clk_48mhz, tx_data_avail, tx_data_avail_48); 44 | //wire tx_data_avail_48 = tx_data_avail; 45 | 46 | // convert tx_data_get from 48 to clk 47 | //wire tx_data_get_48 = tx_data_get; 48 | reg tx_data_get_48; 49 | strobe tx_data_get_strobe( 50 | .clk_in(clk_48mhz), 51 | .clk_out(clk), 52 | .strobe_in(tx_data_get_48), 53 | .strobe_out(tx_data_get) 54 | ); 55 | 56 | reg [7:0] data_shift_reg = 0; 57 | reg [7:0] oe_shift_reg = 0; 58 | reg [7:0] se0_shift_reg = 0; 59 | 60 | 61 | wire serial_tx_data = data_shift_reg[0]; 62 | wire serial_tx_oe = oe_shift_reg[0]; 63 | wire serial_tx_se0 = se0_shift_reg[0]; 64 | 65 | 66 | // serialize sync, pid, data payload, and crc16 67 | reg byte_strobe = 0; 68 | reg [2:0] bit_count = 0; 69 | 70 | reg [4:0] bit_history_q = 0; 71 | wire [5:0] bit_history = {serial_tx_data, bit_history_q}; 72 | wire bitstuff = bit_history == 6'b111111; 73 | reg bitstuff_q = 0; 74 | reg bitstuff_qq = 0; 75 | reg bitstuff_qqq = 0; 76 | reg bitstuff_qqqq = 0; 77 | 78 | 79 | always @(posedge clk_48mhz) begin 80 | bitstuff_q <= bitstuff; 81 | bitstuff_qq <= bitstuff_q; 82 | bitstuff_qqq <= bitstuff_qq; 83 | bitstuff_qqqq <= bitstuff_qqq; 84 | end 85 | 86 | wire pkt_end_48 = bit_strobe && se0_shift_reg[1:0] == 2'b01; 87 | strobe pkt_end_strobe( 88 | .clk_in(clk_48mhz), 89 | .clk_out(clk), 90 | .strobe_in(pkt_end_48), 91 | .strobe_out(pkt_end) 92 | ); 93 | 94 | reg data_payload = 0; 95 | 96 | reg [31:0] pkt_state = 0; 97 | localparam IDLE = 0; 98 | localparam SYNC = 1; 99 | localparam PID = 2; 100 | localparam DATA_OR_CRC16_0 = 3; 101 | localparam CRC16_1 = 4; 102 | localparam EOP = 5; 103 | 104 | reg [15:0] crc16 = 0; 105 | 106 | always @(posedge clk_48mhz) begin 107 | case (pkt_state) 108 | IDLE : begin 109 | if (pkt_start_48) begin 110 | pkt_state <= SYNC; 111 | end 112 | end 113 | 114 | SYNC : begin 115 | if (byte_strobe) begin 116 | pkt_state <= PID; 117 | data_shift_reg <= 8'b10000000; 118 | oe_shift_reg <= 8'b11111111; 119 | se0_shift_reg <= 8'b00000000; 120 | end 121 | end 122 | 123 | PID : begin 124 | if (byte_strobe) begin 125 | if (pidq[1:0] == 2'b11) begin 126 | pkt_state <= DATA_OR_CRC16_0; 127 | end else begin 128 | pkt_state <= EOP; 129 | end 130 | 131 | data_shift_reg <= {~pidq, pidq}; 132 | oe_shift_reg <= 8'b11111111; 133 | se0_shift_reg <= 8'b00000000; 134 | end 135 | end 136 | 137 | DATA_OR_CRC16_0 : begin 138 | if (byte_strobe) begin 139 | if (tx_data_avail_48) begin 140 | pkt_state <= DATA_OR_CRC16_0; 141 | data_payload <= 1; 142 | tx_data_get_48 <= 1; 143 | data_shift_reg <= tx_data; 144 | oe_shift_reg <= 8'b11111111; 145 | se0_shift_reg <= 8'b00000000; 146 | end else begin 147 | pkt_state <= CRC16_1; 148 | data_payload <= 0; 149 | tx_data_get_48 <= 0; 150 | data_shift_reg <= ~{crc16[8], crc16[9], crc16[10], crc16[11], crc16[12], crc16[13], crc16[14], crc16[15]}; 151 | oe_shift_reg <= 8'b11111111; 152 | se0_shift_reg <= 8'b00000000; 153 | end 154 | end else begin 155 | tx_data_get_48 <= 0; 156 | end 157 | end 158 | 159 | CRC16_1 : begin 160 | if (byte_strobe) begin 161 | pkt_state <= EOP; 162 | data_shift_reg <= ~{crc16[0], crc16[1], crc16[2], crc16[3], crc16[4], crc16[5], crc16[6], crc16[7]}; 163 | oe_shift_reg <= 8'b11111111; 164 | se0_shift_reg <= 8'b00000000; 165 | end 166 | end 167 | 168 | EOP : begin 169 | if (byte_strobe) begin 170 | pkt_state <= IDLE; 171 | oe_shift_reg <= 8'b00000111; 172 | se0_shift_reg <= 8'b00000111; 173 | end 174 | end 175 | endcase 176 | 177 | if (bit_strobe && !bitstuff) begin 178 | byte_strobe <= (bit_count == 3'b000); 179 | end else begin 180 | byte_strobe <= 0; 181 | end 182 | 183 | if (pkt_start_48) begin 184 | bit_count <= 1; 185 | bit_history_q <= 0; 186 | 187 | end else if (bit_strobe) begin 188 | // bitstuff 189 | if (bitstuff /* && !serial_tx_se0*/) begin 190 | bit_history_q <= bit_history[5:1]; 191 | data_shift_reg[0] <= 0; 192 | 193 | // normal deserialize 194 | end else begin 195 | bit_count <= bit_count + 1; 196 | 197 | data_shift_reg <= (data_shift_reg >> 1); 198 | oe_shift_reg <= (oe_shift_reg >> 1); 199 | se0_shift_reg <= (se0_shift_reg >> 1); 200 | 201 | bit_history_q <= bit_history[5:1]; 202 | end 203 | end 204 | end 205 | 206 | 207 | 208 | // calculate crc16 209 | wire crc16_invert = serial_tx_data ^ crc16[15]; 210 | 211 | always @(posedge clk_48mhz) begin 212 | if (pkt_start_48) begin 213 | crc16 <= 16'b1111111111111111; 214 | end 215 | 216 | if (bit_strobe && data_payload && !bitstuff_qqqq && !pkt_start_48) begin 217 | crc16[15] <= crc16[14] ^ crc16_invert; 218 | crc16[14] <= crc16[13]; 219 | crc16[13] <= crc16[12]; 220 | crc16[12] <= crc16[11]; 221 | crc16[11] <= crc16[10]; 222 | crc16[10] <= crc16[9]; 223 | crc16[9] <= crc16[8]; 224 | crc16[8] <= crc16[7]; 225 | crc16[7] <= crc16[6]; 226 | crc16[6] <= crc16[5]; 227 | crc16[5] <= crc16[4]; 228 | crc16[4] <= crc16[3]; 229 | crc16[3] <= crc16[2]; 230 | crc16[2] <= crc16[1] ^ crc16_invert; 231 | crc16[1] <= crc16[0]; 232 | crc16[0] <= crc16_invert; 233 | end 234 | end 235 | 236 | reg [2:0] dp_eop = 0; 237 | 238 | 239 | // nrzi and differential driving 240 | always @(posedge clk_48mhz) begin 241 | if (pkt_start_48) begin 242 | // J 243 | dp <= 1; 244 | dn <= 0; 245 | 246 | dp_eop <= 3'b100; 247 | 248 | end else if (bit_strobe) begin 249 | oe <= serial_tx_oe; 250 | 251 | if (serial_tx_se0) begin 252 | dp <= dp_eop[0]; 253 | dn <= 0; 254 | 255 | dp_eop <= dp_eop >> 1; 256 | 257 | end else if (serial_tx_data) begin 258 | // value should stay the same, do nothing 259 | 260 | end else begin 261 | dp <= !dp; 262 | dn <= !dn; 263 | end 264 | end 265 | end 266 | 267 | endmodule 268 | -------------------------------------------------------------------------------- /usb/usb_fs_tx_mux.v: -------------------------------------------------------------------------------- 1 | module usb_fs_tx_mux ( 2 | // interface to IN Protocol Engine 3 | input in_tx_pkt_start, 4 | input [3:0] in_tx_pid, 5 | 6 | // interface to OUT Protocol Engine 7 | input out_tx_pkt_start, 8 | input [3:0] out_tx_pid, 9 | 10 | // interface to tx module 11 | output tx_pkt_start, 12 | output [3:0] tx_pid 13 | ); 14 | assign tx_pkt_start = in_tx_pkt_start | out_tx_pkt_start; 15 | assign tx_pid = out_tx_pkt_start ? out_tx_pid : in_tx_pid; 16 | endmodule 17 | -------------------------------------------------------------------------------- /usb/usb_serial.v: -------------------------------------------------------------------------------- 1 | `include "usb_fs_pe.v" 2 | `include "usb_serial_ctrl_ep.v" 3 | `include "usb_serial_ep.v" 4 | 5 | module usb_serial ( 6 | input clk_48mhz, 7 | input clk, 8 | input reset, 9 | 10 | // USB lines in clk_48mhz domain. 11 | // Split into input vs. output and oe control signal to maintain 12 | // highest level of compatibility with synthesis tools. 13 | output usb_p_tx, 14 | output usb_n_tx, 15 | 16 | input usb_p_rx, 17 | input usb_n_rx, 18 | 19 | output usb_tx_en, 20 | 21 | // serial uart interface, runs at clk domain 22 | output uart_tx_ready, 23 | input [7:0] uart_tx_data, 24 | input uart_tx_strobe, 25 | 26 | output [7:0] uart_rx_data, 27 | output uart_rx_strobe, 28 | 29 | output host_presence // need to figure this out 30 | ); 31 | wire [6:0] dev_addr; 32 | wire [7:0] out_ep_data; 33 | 34 | wire ctrl_out_ep_req; 35 | wire ctrl_out_ep_grant; 36 | wire ctrl_out_ep_data_avail; 37 | wire ctrl_out_ep_setup; 38 | wire ctrl_out_ep_data_get; 39 | wire ctrl_out_ep_stall; 40 | wire ctrl_out_ep_acked; 41 | 42 | wire ctrl_in_ep_req; 43 | wire ctrl_in_ep_grant; 44 | wire ctrl_in_ep_data_free; 45 | wire ctrl_in_ep_data_put; 46 | wire [7:0] ctrl_in_ep_data; 47 | wire ctrl_in_ep_data_done; 48 | wire ctrl_in_ep_stall; 49 | wire ctrl_in_ep_acked; 50 | 51 | wire serial_out_ep_req; 52 | wire serial_out_ep_grant; 53 | wire serial_out_ep_data_avail; 54 | wire serial_out_ep_setup; 55 | wire serial_out_ep_data_get; 56 | wire serial_out_ep_stall; 57 | wire serial_out_ep_acked; 58 | 59 | wire serial_in_ep_req; 60 | wire serial_in_ep_grant; 61 | wire serial_in_ep_data_free; 62 | wire serial_in_ep_data_put; 63 | wire [7:0] serial_in_ep_data; 64 | wire serial_in_ep_data_done; 65 | wire serial_in_ep_stall; 66 | wire serial_in_ep_acked; 67 | 68 | wire sof_valid; 69 | wire [10:0] frame_index; 70 | 71 | `undef SERIAL 72 | `ifdef SERIAL 73 | // signal if we have data available 74 | // note that the "in" and "out" are from the HOST perspective, 75 | // while "rx" and "tx" are from the FPGA perspective 76 | 77 | // the grant and data available go high one clock cycle before 78 | // the data is actually available. this works for receiving data 79 | wire rx_ready = serial_out_ep_grant && serial_out_ep_data_avail; 80 | delay #(.DELAY(1)) rx_ready_delay(clk, rx_ready, uart_rx_ready); 81 | 82 | assign serial_out_ep_req = serial_out_ep_data_avail; 83 | assign serial_out_ep_data_get = serial_out_ep_grant && uart_rx_strobe; 84 | assign uart_rx_data = out_ep_data; 85 | assign serial_out_ep_stall = 0; 86 | 87 | // buffer up to 512 bytes of outgoing data (one BRAM) 88 | reg [7:0] tx_fifo[511:0]; 89 | reg [8:0] tx_read_ptr; 90 | reg [8:0] tx_write_ptr; 91 | wire tx_data_available = tx_write_ptr != tx_read_ptr; 92 | assign uart_tx_ready = (tx_write_ptr+1) != tx_read_ptr; 93 | assign serial_in_ep_stall = 0; 94 | 95 | delay #(.DELAY(0)) in_req_delay(clk, tx_data_available, serial_in_ep_req); 96 | 97 | wire data_done = !serial_in_ep_data_free || !tx_data_available; 98 | //delay #(.DELAY(2)) data_done_delay(clk, data_done, serial_in_ep_data_done); 99 | assign serial_in_ep_data_done = data_done; 100 | wire in_ready_i = serial_in_ep_data_free && serial_in_ep_grant; 101 | reg in_ready; 102 | delay #(.DELAY(0)) in_ready_delay(clk, in_ready_i, in_ready); 103 | 104 | reg data_put; 105 | //reg serial_in_ep_data_put; 106 | delay #(.DELAY(0)) data_put_delay(clk, data_put, serial_in_ep_data_put); 107 | //assign serial_in_ep_data_put = data_put; 108 | 109 | always @(posedge clk) if (!reset) 110 | begin 111 | data_put <= 0; 112 | 113 | if (uart_tx_strobe && uart_tx_ready) 114 | begin 115 | tx_fifo[tx_write_ptr] <= uart_tx_data; 116 | tx_write_ptr <= tx_write_ptr + 1; 117 | end 118 | 119 | if (tx_data_available) 120 | begin 121 | data_put <= 1; 122 | serial_in_ep_data <= tx_fifo[tx_read_ptr]; 123 | if (in_ready) 124 | tx_read_ptr <= tx_read_ptr + 1; 125 | end 126 | end 127 | `else 128 | 129 | usb_serial_ep usb_serial_ep_inst ( 130 | .clk(clk), 131 | .reset(reset), 132 | 133 | // out endpoint interface 134 | .out_ep_req(serial_out_ep_req), 135 | .out_ep_grant(serial_out_ep_grant), 136 | .out_ep_data_avail(serial_out_ep_data_avail), 137 | .out_ep_setup(serial_out_ep_setup), 138 | .out_ep_data_get(serial_out_ep_data_get), 139 | .out_ep_data(out_ep_data), 140 | .out_ep_stall(serial_out_ep_stall), 141 | .out_ep_acked(serial_out_ep_acked), 142 | 143 | // in endpoint interface 144 | .in_ep_req(serial_in_ep_req), 145 | .in_ep_grant(serial_in_ep_grant), 146 | .in_ep_data_free(serial_in_ep_data_free), 147 | .in_ep_data_put(serial_in_ep_data_put), 148 | .in_ep_data(serial_in_ep_data), 149 | .in_ep_data_done(serial_in_ep_data_done), 150 | .in_ep_stall(serial_in_ep_stall), 151 | .in_ep_acked(serial_in_ep_acked), 152 | 153 | // uart interface 154 | .uart_tx_ready(uart_tx_ready), 155 | .uart_tx_data(uart_tx_data), 156 | .uart_tx_strobe(uart_tx_strobe), 157 | .uart_rx_data(uart_rx_data), 158 | .uart_rx_strobe(uart_rx_strobe) 159 | ); 160 | `endif 161 | 162 | usb_serial_ctrl_ep ctrl_ep_inst ( 163 | .clk(clk), 164 | .reset(reset), 165 | .dev_addr(dev_addr), 166 | 167 | // out endpoint interface 168 | .out_ep_req(ctrl_out_ep_req), 169 | .out_ep_grant(ctrl_out_ep_grant), 170 | .out_ep_data_avail(ctrl_out_ep_data_avail), 171 | .out_ep_setup(ctrl_out_ep_setup), 172 | .out_ep_data_get(ctrl_out_ep_data_get), 173 | .out_ep_data(out_ep_data), 174 | .out_ep_stall(ctrl_out_ep_stall), 175 | .out_ep_acked(ctrl_out_ep_acked), 176 | 177 | // in endpoint interface 178 | .in_ep_req(ctrl_in_ep_req), 179 | .in_ep_grant(ctrl_in_ep_grant), 180 | .in_ep_data_free(ctrl_in_ep_data_free), 181 | .in_ep_data_put(ctrl_in_ep_data_put), 182 | .in_ep_data(ctrl_in_ep_data), 183 | .in_ep_data_done(ctrl_in_ep_data_done), 184 | .in_ep_stall(ctrl_in_ep_stall), 185 | .in_ep_acked(ctrl_in_ep_acked) 186 | ); 187 | 188 | wire nak_in_ep_grant; 189 | wire nak_in_ep_data_free; 190 | wire nak_in_ep_acked; 191 | 192 | usb_fs_pe #( 193 | .NUM_OUT_EPS(5'd2), 194 | .NUM_IN_EPS(5'd3) 195 | ) usb_fs_pe_inst ( 196 | .clk_48mhz(clk_48mhz), 197 | .clk(clk), 198 | .reset(reset), 199 | 200 | .usb_p_tx(usb_p_tx), 201 | .usb_n_tx(usb_n_tx), 202 | .usb_p_rx(usb_p_rx), 203 | .usb_n_rx(usb_n_rx), 204 | .usb_tx_en(usb_tx_en), 205 | 206 | .dev_addr(dev_addr), 207 | 208 | // out endpoint interfaces 209 | .out_ep_req({serial_out_ep_req, ctrl_out_ep_req}), 210 | .out_ep_grant({serial_out_ep_grant, ctrl_out_ep_grant}), 211 | .out_ep_data_avail({serial_out_ep_data_avail, ctrl_out_ep_data_avail}), 212 | .out_ep_setup({serial_out_ep_setup, ctrl_out_ep_setup}), 213 | .out_ep_data_get({serial_out_ep_data_get, ctrl_out_ep_data_get}), 214 | .out_ep_data(out_ep_data), 215 | .out_ep_stall({serial_out_ep_stall, ctrl_out_ep_stall}), 216 | .out_ep_acked({serial_out_ep_acked, ctrl_out_ep_acked}), 217 | 218 | // in endpoint interfaces 219 | .in_ep_req({1'b0, serial_in_ep_req, ctrl_in_ep_req}), 220 | .in_ep_grant({nak_in_ep_grant, serial_in_ep_grant, ctrl_in_ep_grant}), 221 | .in_ep_data_free({nak_in_ep_data_free, serial_in_ep_data_free, ctrl_in_ep_data_free}), 222 | .in_ep_data_put({1'b0, serial_in_ep_data_put, ctrl_in_ep_data_put}), 223 | .in_ep_data({8'b0, serial_in_ep_data[7:0], ctrl_in_ep_data[7:0]}), 224 | .in_ep_data_done({1'b0, serial_in_ep_data_done, ctrl_in_ep_data_done}), 225 | .in_ep_stall({1'b0, serial_in_ep_stall, ctrl_in_ep_stall}), 226 | .in_ep_acked({nak_in_ep_acked, serial_in_ep_acked, ctrl_in_ep_acked}), 227 | 228 | // sof interface 229 | .sof_valid(sof_valid), 230 | .frame_index(frame_index) 231 | ); 232 | 233 | endmodule 234 | -------------------------------------------------------------------------------- /usb/usb_serial_ctrl_ep.v: -------------------------------------------------------------------------------- 1 | `include "edge_detect.v" 2 | 3 | module usb_serial_ctrl_ep ( 4 | input clk, 5 | input reset, 6 | output [6:0] dev_addr, 7 | 8 | //////////////////// 9 | // out endpoint interface 10 | //////////////////// 11 | output out_ep_req, 12 | input out_ep_grant, 13 | input out_ep_data_avail, 14 | input out_ep_setup, 15 | output out_ep_data_get, 16 | input [7:0] out_ep_data, 17 | output out_ep_stall, 18 | input out_ep_acked, 19 | 20 | 21 | //////////////////// 22 | // in endpoint interface 23 | //////////////////// 24 | output in_ep_req, 25 | input in_ep_grant, 26 | input in_ep_data_free, 27 | output in_ep_data_put, 28 | output [7:0] in_ep_data, 29 | output in_ep_data_done, 30 | output reg in_ep_stall, 31 | input in_ep_acked 32 | ); 33 | 34 | 35 | localparam IDLE = 0; 36 | localparam SETUP = 1; 37 | localparam DATA_IN = 2; 38 | localparam DATA_OUT = 3; 39 | localparam STATUS_IN = 4; 40 | localparam STATUS_OUT = 5; 41 | 42 | reg [5:0] ctrl_xfr_state = IDLE; 43 | reg [5:0] ctrl_xfr_state_next; 44 | 45 | 46 | 47 | reg setup_stage_end; 48 | reg data_stage_end; 49 | reg status_stage_end; 50 | reg send_zero_length_data_pkt; 51 | 52 | 53 | 54 | // the default control endpoint gets assigned the device address 55 | reg [6:0] dev_addr_i = 0; 56 | assign dev_addr = dev_addr_i; 57 | 58 | assign out_ep_req = out_ep_data_avail; 59 | assign out_ep_data_get = out_ep_data_avail; 60 | reg out_ep_data_valid = 0; 61 | always @(posedge clk) out_ep_data_valid <= out_ep_data_avail && out_ep_grant; 62 | 63 | // need to record the setup data 64 | reg [3:0] setup_data_addr; 65 | reg [9:0] raw_setup_data [7:0]; 66 | 67 | wire [7:0] bmRequestType = raw_setup_data[0]; 68 | wire [7:0] bRequest = raw_setup_data[1]; 69 | wire [15:0] wValue = {raw_setup_data[3][7:0], raw_setup_data[2][7:0]}; 70 | wire [15:0] wIndex = {raw_setup_data[5][7:0], raw_setup_data[4][7:0]}; 71 | wire [15:0] wLength = {raw_setup_data[7][7:0], raw_setup_data[6][7:0]}; 72 | 73 | // keep track of new out data start and end 74 | wire pkt_start; 75 | wire pkt_end; 76 | 77 | rising_edge_detector detect_pkt_start ( 78 | .clk(clk), 79 | .in(out_ep_data_avail), 80 | .out(pkt_start) 81 | ); 82 | 83 | falling_edge_detector detect_pkt_end ( 84 | .clk(clk), 85 | .in(out_ep_data_avail), 86 | .out(pkt_end) 87 | ); 88 | 89 | assign out_ep_stall = 1'b0; 90 | 91 | wire setup_pkt_start = pkt_start && out_ep_setup; 92 | 93 | wire has_data_stage = wLength != 16'b0000000000000000; 94 | 95 | wire out_data_stage; 96 | assign out_data_stage = has_data_stage && !bmRequestType[7]; 97 | 98 | wire in_data_stage; 99 | assign in_data_stage = has_data_stage && bmRequestType[7]; 100 | 101 | reg [7:0] bytes_sent = 0; 102 | reg [6:0] rom_length = 0; 103 | 104 | wire all_data_sent = 105 | (bytes_sent >= rom_length) || 106 | (bytes_sent >= wLength); 107 | 108 | wire more_data_to_send = 109 | !all_data_sent; 110 | 111 | wire in_data_transfer_done; 112 | 113 | rising_edge_detector detect_in_data_transfer_done ( 114 | .clk(clk), 115 | .in(all_data_sent), 116 | .out(in_data_transfer_done) 117 | ); 118 | 119 | assign in_ep_data_done = (in_data_transfer_done && ctrl_xfr_state == DATA_IN) || send_zero_length_data_pkt; 120 | 121 | assign in_ep_req = ctrl_xfr_state == DATA_IN && more_data_to_send; 122 | assign in_ep_data_put = ctrl_xfr_state == DATA_IN && more_data_to_send && in_ep_data_free; 123 | 124 | 125 | reg [6:0] rom_addr = 0; 126 | 127 | reg save_dev_addr = 0; 128 | reg [6:0] new_dev_addr = 0; 129 | 130 | //////////////////////////////////////////////////////////////////////////////// 131 | // control transfer state machine 132 | //////////////////////////////////////////////////////////////////////////////// 133 | 134 | 135 | always @* begin 136 | setup_stage_end <= 0; 137 | data_stage_end <= 0; 138 | status_stage_end <= 0; 139 | send_zero_length_data_pkt <= 0; 140 | 141 | case (ctrl_xfr_state) 142 | IDLE : begin 143 | if (setup_pkt_start) begin 144 | ctrl_xfr_state_next <= SETUP; 145 | end else begin 146 | ctrl_xfr_state_next <= IDLE; 147 | end 148 | end 149 | 150 | SETUP : begin 151 | if (pkt_end) begin 152 | setup_stage_end <= 1; 153 | 154 | if (in_data_stage) begin 155 | ctrl_xfr_state_next <= DATA_IN; 156 | 157 | end else if (out_data_stage) begin 158 | ctrl_xfr_state_next <= DATA_OUT; 159 | 160 | end else begin 161 | ctrl_xfr_state_next <= STATUS_IN; 162 | send_zero_length_data_pkt <= 1; 163 | end 164 | 165 | end else begin 166 | ctrl_xfr_state_next <= SETUP; 167 | end 168 | end 169 | 170 | DATA_IN : begin 171 | if (in_ep_stall) begin 172 | ctrl_xfr_state_next <= IDLE; 173 | data_stage_end <= 1; 174 | status_stage_end <= 1; 175 | 176 | end else if (in_ep_acked && all_data_sent) begin 177 | ctrl_xfr_state_next <= STATUS_OUT; 178 | data_stage_end <= 1; 179 | 180 | end else begin 181 | ctrl_xfr_state_next <= DATA_IN; 182 | end 183 | end 184 | 185 | DATA_OUT : begin 186 | if (out_ep_acked) begin 187 | ctrl_xfr_state_next <= STATUS_IN; 188 | send_zero_length_data_pkt <= 1; 189 | data_stage_end <= 1; 190 | 191 | end else begin 192 | ctrl_xfr_state_next <= DATA_OUT; 193 | end 194 | end 195 | 196 | STATUS_IN : begin 197 | if (in_ep_acked) begin 198 | ctrl_xfr_state_next <= IDLE; 199 | status_stage_end <= 1; 200 | 201 | end else begin 202 | ctrl_xfr_state_next <= STATUS_IN; 203 | end 204 | end 205 | 206 | STATUS_OUT: begin 207 | if (out_ep_acked) begin 208 | ctrl_xfr_state_next <= IDLE; 209 | status_stage_end <= 1; 210 | 211 | end else begin 212 | ctrl_xfr_state_next <= STATUS_OUT; 213 | end 214 | end 215 | 216 | default begin 217 | ctrl_xfr_state_next <= IDLE; 218 | end 219 | endcase 220 | end 221 | 222 | always @(posedge clk) begin 223 | if (reset) begin 224 | ctrl_xfr_state <= IDLE; 225 | end else begin 226 | ctrl_xfr_state <= ctrl_xfr_state_next; 227 | end 228 | end 229 | 230 | always @(posedge clk) begin 231 | in_ep_stall <= 0; 232 | 233 | if (out_ep_setup && out_ep_data_valid) begin 234 | raw_setup_data[setup_data_addr] <= out_ep_data; 235 | setup_data_addr <= setup_data_addr + 1; 236 | end 237 | 238 | if (setup_stage_end) begin 239 | case (bRequest) 240 | 'h06 : begin 241 | // GET_DESCRIPTOR 242 | case (wValue[15:8]) 243 | 1 : begin 244 | // DEVICE 245 | rom_addr <= 'h00; 246 | rom_length <= 'h12; 247 | end 248 | 249 | 2 : begin 250 | // CONFIGURATION 251 | rom_addr <= 'h12; 252 | rom_length <= 'h43; 253 | end 254 | 255 | 6 : begin 256 | // DEVICE_QUALIFIER 257 | in_ep_stall <= 1; 258 | rom_addr <= 'h00; 259 | rom_length <= 'h00; 260 | end 261 | 262 | endcase 263 | end 264 | 265 | 'h05 : begin 266 | // SET_ADDRESS 267 | rom_addr <= 'h00; 268 | rom_length <= 'h00; 269 | 270 | // we need to save the address after the status stage ends 271 | // this is because the status stage token will still be using 272 | // the old device address 273 | save_dev_addr <= 1; 274 | new_dev_addr <= wValue[6:0]; 275 | end 276 | 277 | 'h09 : begin 278 | // SET_CONFIGURATION 279 | rom_addr <= 'h00; 280 | rom_length <= 'h00; 281 | end 282 | 283 | 'h20 : begin 284 | // SET_LINE_CODING 285 | rom_addr <= 'h00; 286 | rom_length <= 'h00; 287 | end 288 | 289 | 'h21 : begin 290 | // GET_LINE_CODING 291 | rom_addr <= 'h55; 292 | rom_length <= 'h07; 293 | end 294 | 295 | 'h22 : begin 296 | // SET_CONTROL_LINE_STATE 297 | rom_addr <= 'h00; 298 | rom_length <= 'h00; 299 | end 300 | 301 | 'h23 : begin 302 | // SEND_BREAK 303 | rom_addr <= 'h00; 304 | rom_length <= 'h00; 305 | end 306 | 307 | default begin 308 | rom_addr <= 'h00; 309 | rom_length <= 'h00; 310 | end 311 | endcase 312 | end 313 | 314 | if (ctrl_xfr_state == DATA_IN && more_data_to_send && in_ep_grant && in_ep_data_free) begin 315 | rom_addr <= rom_addr + 1; 316 | bytes_sent <= bytes_sent + 1; 317 | end 318 | 319 | if (status_stage_end) begin 320 | setup_data_addr <= 0; 321 | bytes_sent <= 0; 322 | rom_addr <= 0; 323 | rom_length <= 0; 324 | 325 | if (save_dev_addr) begin 326 | save_dev_addr <= 0; 327 | dev_addr_i <= new_dev_addr; 328 | end 329 | end 330 | 331 | if (reset) begin 332 | dev_addr_i <= 0; 333 | setup_data_addr <= 0; 334 | save_dev_addr <= 0; 335 | end 336 | end 337 | 338 | 339 | `define CDC_ACM_ENDPOINT 2 340 | `define CDC_RX_ENDPOINT 1 341 | `define CDC_TX_ENDPOINT 1 342 | 343 | reg [7:0] ep_rom[255:0]; 344 | assign in_ep_data = ep_rom[rom_addr]; 345 | 346 | initial begin 347 | // device descriptor 348 | ep_rom['h000] <= 18; // bLength 349 | ep_rom['h001] <= 1; // bDescriptorType 350 | ep_rom['h002] <= 'h00; // bcdUSB[0] 351 | ep_rom['h003] <= 'h02; // bcdUSB[1] 352 | ep_rom['h004] <= 'h02; // bDeviceClass (Communications Device Class) 353 | ep_rom['h005] <= 'h00; // bDeviceSubClass (Abstract Control Model) 354 | ep_rom['h006] <= 'h00; // bDeviceProtocol (No class specific protocol required) 355 | ep_rom['h007] <= 32; // bMaxPacketSize0 356 | 357 | ep_rom['h008] <= 'h50; // idVendor[0] http://wiki.openmoko.org/wiki/USB_Product_IDs 358 | ep_rom['h009] <= 'h1d; // idVendor[1] 359 | ep_rom['h00A] <= 'h30; // idProduct[0] 360 | ep_rom['h00B] <= 'h61; // idProduct[1] 361 | 362 | ep_rom['h00C] <= 0; // bcdDevice[0] 363 | ep_rom['h00D] <= 0; // bcdDevice[1] 364 | ep_rom['h00E] <= 0; // iManufacturer 365 | ep_rom['h00F] <= 0; // iProduct 366 | ep_rom['h010] <= 0; // iSerialNumber 367 | ep_rom['h011] <= 1; // bNumConfigurations 368 | 369 | // configuration descriptor 370 | ep_rom['h012] <= 9; // bLength 371 | ep_rom['h013] <= 2; // bDescriptorType 372 | ep_rom['h014] <= (9+9+5+5+4+5+7+9+7+7); // wTotalLength[0] 373 | ep_rom['h015] <= 0; // wTotalLength[1] 374 | ep_rom['h016] <= 2; // bNumInterfaces 375 | ep_rom['h017] <= 1; // bConfigurationValue 376 | ep_rom['h018] <= 0; // iConfiguration 377 | ep_rom['h019] <= 'hC0; // bmAttributes 378 | ep_rom['h01A] <= 50; // bMaxPower 379 | 380 | // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 381 | ep_rom['h01B] <= 9; // bLength 382 | ep_rom['h01C] <= 4; // bDescriptorType 383 | ep_rom['h01D] <= 0; // bInterfaceNumber 384 | ep_rom['h01E] <= 0; // bAlternateSetting 385 | ep_rom['h01F] <= 1; // bNumEndpoints 386 | ep_rom['h020] <= 2; // bInterfaceClass (Communications Device Class) 387 | ep_rom['h021] <= 2; // bInterfaceSubClass (Abstract Control Model) 388 | ep_rom['h022] <= 1; // bInterfaceProtocol (AT Commands: V.250 etc) 389 | ep_rom['h023] <= 0; // iInterface 390 | 391 | // CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26 392 | ep_rom['h024] <= 5; // bFunctionLength 393 | ep_rom['h025] <= 'h24; // bDescriptorType 394 | ep_rom['h026] <= 'h00; // bDescriptorSubtype 395 | ep_rom['h027] <= 'h10; 396 | ep_rom['h028] <= 'h01; // bcdCDC 397 | 398 | // Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27 399 | ep_rom['h029] <= 5; // bFunctionLength 400 | ep_rom['h02A] <= 'h24; // bDescriptorType 401 | ep_rom['h02B] <= 'h01; // bDescriptorSubtype 402 | ep_rom['h02C] <= 'h00; // bmCapabilities 403 | ep_rom['h02D] <= 1; // bDataInterface 404 | 405 | // Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28 406 | ep_rom['h02E] <= 4; // bFunctionLength 407 | ep_rom['h02F] <= 'h24; // bDescriptorType 408 | ep_rom['h030] <= 'h02; // bDescriptorSubtype 409 | ep_rom['h031] <= 'h06; // bmCapabilities 410 | 411 | // Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33 412 | ep_rom['h032] <= 5; // bFunctionLength 413 | ep_rom['h033] <= 'h24; // bDescriptorType 414 | ep_rom['h034] <= 'h06; // bDescriptorSubtype 415 | ep_rom['h035] <= 0; // bMasterInterface 416 | ep_rom['h036] <= 1; // bSlaveInterface0 417 | 418 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 419 | ep_rom['h037] <= 7; // bLength 420 | ep_rom['h038] <= 5; // bDescriptorType 421 | ep_rom['h039] <= `CDC_ACM_ENDPOINT | 'h80; // bEndpointAddress 422 | ep_rom['h03A] <= 'h03; // bmAttributes (0x03=intr) 423 | ep_rom['h03B] <= 8; // wMaxPacketSize[0] 424 | ep_rom['h03C] <= 0; // wMaxPacketSize[1] 425 | ep_rom['h03D] <= 64; // bInterval 426 | 427 | // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 428 | ep_rom['h03E] <= 9; // bLength 429 | ep_rom['h03F] <= 4; // bDescriptorType 430 | ep_rom['h040] <= 1; // bInterfaceNumber 431 | ep_rom['h041] <= 0; // bAlternateSetting 432 | ep_rom['h042] <= 2; // bNumEndpoints 433 | ep_rom['h043] <= 'h0A; // bInterfaceClass 434 | ep_rom['h044] <= 'h00; // bInterfaceSubClass 435 | ep_rom['h045] <= 'h00; // bInterfaceProtocol 436 | ep_rom['h046] <= 0; // iInterface 437 | 438 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 439 | ep_rom['h047] <= 7; // bLength 440 | ep_rom['h048] <= 5; // bDescriptorType 441 | ep_rom['h049] <= `CDC_RX_ENDPOINT; // bEndpointAddress 442 | ep_rom['h04A] <= 'h02; // bmAttributes (0x02=bulk) 443 | ep_rom['h04B] <= 32; // wMaxPacketSize[0] 444 | ep_rom['h04C] <= 0; // wMaxPacketSize[1] 445 | ep_rom['h04D] <= 0; // bInterval 446 | 447 | // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 448 | ep_rom['h04E] <= 7; // bLength 449 | ep_rom['h04F] <= 5; // bDescriptorType 450 | ep_rom['h050] <= `CDC_TX_ENDPOINT | 'h80; // bEndpointAddress 451 | ep_rom['h051] <= 'h02; // bmAttributes (0x02=bulk) 452 | 453 | ep_rom['h052] <= 32; // wMaxPacketSize[0] 454 | ep_rom['h053] <= 0; // wMaxPacketSize[1] 455 | ep_rom['h054] <= 0; // bInterval 456 | 457 | // LINE_CODING 458 | ep_rom['h055] <= 'h80; // dwDTERate[0] 459 | ep_rom['h056] <= 'h25; // dwDTERate[1] 460 | ep_rom['h057] <= 'h00; // dwDTERate[2] 461 | ep_rom['h058] <= 'h00; // dwDTERate[3] 462 | ep_rom['h059] <= 1; // bCharFormat (1 stop bit) 463 | ep_rom['h05A] <= 0; // bParityType (None) 464 | ep_rom['h05B] <= 8; // bDataBits (8 bits) 465 | 466 | end 467 | 468 | endmodule 469 | -------------------------------------------------------------------------------- /usb/usb_serial_ep.v: -------------------------------------------------------------------------------- 1 | module usb_serial_ep ( 2 | input clk, 3 | input reset, 4 | 5 | 6 | //////////////////// 7 | // out endpoint interface 8 | //////////////////// 9 | output out_ep_req, 10 | input out_ep_grant, 11 | input out_ep_data_avail, 12 | input out_ep_setup, 13 | output out_ep_data_get, 14 | input [7:0] out_ep_data, 15 | output out_ep_stall, 16 | input out_ep_acked, 17 | 18 | 19 | //////////////////// 20 | // in endpoint interface 21 | //////////////////// 22 | output reg in_ep_req = 0, 23 | input in_ep_grant, 24 | input in_ep_data_free, 25 | output reg in_ep_data_put = 0, 26 | output [7:0] in_ep_data, 27 | output reg in_ep_data_done = 0, 28 | output in_ep_stall, 29 | input in_ep_acked, 30 | 31 | 32 | //////////////////// 33 | // uart interface, runs at clk domain 34 | //////////////////// 35 | output uart_tx_ready, 36 | input [7:0] uart_tx_data, 37 | input uart_tx_strobe, 38 | 39 | output [7:0] uart_rx_data, 40 | output uart_rx_strobe 41 | ); 42 | // never stall the USB 43 | // todo: allow backpressure to stall the serial link 44 | assign out_ep_stall = 1'b0; 45 | assign in_ep_stall = 1'b0; 46 | 47 | //////////////////////////////////////////////////////////////////////////////// 48 | // other glue logic 49 | //////////////////////////////////////////////////////////////////////////////// 50 | 51 | // "Out" from the Host to the FPGA. 52 | // new bytes are available from the host when the "out" grant goes high 53 | // and "out" data available. 54 | // FPGA will always request data when it is available from the host 55 | // and always signals that it has read it. 56 | wire out_data_ready = out_ep_grant && out_ep_data_avail; 57 | assign out_ep_req = out_ep_data_avail; 58 | assign out_ep_data_get = out_ep_grant; // always ready 59 | 60 | reg out_data_valid; 61 | reg uart_rx_ready; 62 | reg [7:0] uart_rx_data; 63 | 64 | always @(posedge clk) begin 65 | uart_rx_strobe <= 0; 66 | out_data_valid <= out_data_ready; 67 | 68 | if (out_data_valid) begin 69 | uart_rx_data <= out_ep_data; 70 | uart_rx_strobe <= 1; 71 | end 72 | end 73 | 74 | // "In" from the FPGA to the Host. 75 | // when the host says that there is space free in the outbound 76 | // packet, clock in bytes from the FPGA on the uart_tx_strobe line. 77 | 78 | // the FPGA can send bytes when in "in" grant 79 | // is high and the "in" data is free. 80 | wire byte_in_xfr_ready = in_ep_grant && in_ep_data_free; 81 | 82 | reg [7:0] tx_data; 83 | reg tx_data_valid; 84 | assign uart_tx_ready = !tx_data_valid; 85 | 86 | always @(posedge clk) begin 87 | in_ep_data_put <= 0; 88 | in_ep_req <= 0; 89 | in_ep_data_done <= 0; 90 | if (uart_tx_strobe) begin 91 | tx_data <= uart_tx_data; 92 | tx_data_valid <= 1; 93 | end 94 | if (in_ep_data_free && tx_data_valid) begin 95 | in_ep_req <= 1; 96 | in_ep_data_put <= 1; 97 | in_ep_data_done <= 1; 98 | in_ep_data <= tx_data; 99 | tx_data_valid <= 0; 100 | end 101 | end 102 | 103 | /* 104 | reg in_ep_req_i = 0; 105 | always @(posedge clk) in_ep_req_i <= tx_data_valid && in_ep_data_free; 106 | always @(posedge clk) in_ep_req <= in_ep_req_i; 107 | //always @(posedge clk) in_ep_data_put <= tx_data_valid; 108 | 109 | // how do we know if we're done? 110 | // todo: figure out how to packetize the data or use a 111 | // fifo to keep things fed 112 | reg in_ep_data_done_i = 1; 113 | reg in_ep_data_done_q = 0; 114 | always @(posedge clk) in_ep_data_done_q <= in_ep_data_done_i; 115 | always @(posedge clk) in_ep_data_done <= in_ep_data_done_q; 116 | */ 117 | 118 | endmodule 119 | -------------------------------------------------------------------------------- /usb/usb_uart.v: -------------------------------------------------------------------------------- 1 | `ifndef usb_uart_v 2 | `define usb_uart_v 3 | 4 | `include "usb_serial.v" 5 | `include "../util.v" 6 | 7 | module usb_uart ( 8 | input clk, 9 | input clk_48mhz, 10 | input reset, 11 | 12 | // physical layer 13 | inout pin_usbp, 14 | inout pin_usbn, 15 | output pin_pu, 16 | 17 | // uart 18 | output [7:0] rx_data, 19 | output rx_strobe, 20 | input [7:0] tx_data, 21 | input tx_strobe 22 | ); 23 | wire usb_p_tx; 24 | wire usb_n_tx; 25 | wire usb_p_rx; 26 | wire usb_n_rx; 27 | wire usb_tx_en; 28 | 29 | wire uart_tx_ready; 30 | reg uart_tx_strobe; 31 | 32 | wire uart_rx_strobe = rx_strobe; 33 | wire [7:0] uart_rx_data = rx_data; 34 | reg [7:0] uart_tx_data; 35 | 36 | wire fifo_data_available; 37 | wire [7:0] fifo_tx_data = tx_data; 38 | wire fifo_tx_strobe = tx_strobe; 39 | wire [7:0] fifo_rx_data; 40 | reg fifo_rx_strobe; 41 | 42 | fifo tx_buffer( 43 | .clk(clk), 44 | .reset(reset), 45 | .data_available(fifo_data_available), 46 | .write_data(fifo_tx_data), 47 | .write_strobe(fifo_tx_strobe), 48 | .read_data(fifo_rx_data), 49 | .read_strobe(fifo_rx_strobe) 50 | ); 51 | 52 | // if the fifo has any data and the usb serial is ready 53 | // transmit the data to it and remove it from the fifo 54 | always @(posedge clk) if (!reset) begin 55 | if (uart_tx_ready 56 | && fifo_data_available 57 | && !uart_tx_strobe 58 | ) begin 59 | uart_tx_data <= fifo_rx_data; 60 | uart_tx_strobe <= 1; 61 | fifo_rx_strobe <= 1; 62 | end else begin 63 | uart_tx_strobe <= 0; 64 | fifo_rx_strobe <= 0; 65 | end 66 | end 67 | 68 | usb_serial serial( 69 | .clk_48mhz(clk_48mhz), 70 | .clk(clk), 71 | .reset(reset), 72 | .uart_tx_ready(uart_tx_ready), 73 | .uart_tx_strobe(uart_tx_strobe), 74 | .uart_tx_data(uart_tx_data), 75 | .uart_rx_strobe(uart_rx_strobe), 76 | .uart_rx_data(uart_rx_data), 77 | .usb_p_tx(usb_p_tx), 78 | .usb_n_tx(usb_n_tx), 79 | .usb_p_rx(usb_p_rx), 80 | .usb_n_rx(usb_n_rx), 81 | .usb_tx_en(usb_tx_en) 82 | ); 83 | 84 | assign pin_pu = 1'b1; 85 | 86 | wire usb_p_rx_io; 87 | wire usb_n_rx_io; 88 | assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_rx_io; 89 | assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_rx_io; 90 | 91 | SB_IO #( 92 | .PIN_TYPE(6'b1010_01) // tristatable output 93 | ) buffer [1:0]( 94 | .OUTPUT_ENABLE(usb_tx_en), 95 | .PACKAGE_PIN({pin_usbn, pin_usbp}), 96 | .D_IN_0({usb_n_rx_io, usb_p_rx_io}), 97 | .D_OUT_0({usb_n_tx, usb_p_tx}) 98 | ); 99 | endmodule 100 | 101 | `endif 102 | -------------------------------------------------------------------------------- /util.v: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Utility modules. 3 | */ 4 | `ifndef util_v 5 | `define util_v 6 | 7 | `define CLOG2(x) \ 8 | x <= 2 ? 1 : \ 9 | x <= 4 ? 2 : \ 10 | x <= 8 ? 3 : \ 11 | x <= 16 ? 4 : \ 12 | x <= 32 ? 5 : \ 13 | x <= 64 ? 6 : \ 14 | x <= 128 ? 7 : \ 15 | x <= 256 ? 8 : \ 16 | x <= 512 ? 9 : \ 17 | x <= 1024 ? 10 : \ 18 | x <= 2048 ? 11 : \ 19 | x <= 4096 ? 12 : \ 20 | x <= 8192 ? 13 : \ 21 | x <= 16384 ? 14 : \ 22 | x <= 32768 ? 15 : \ 23 | x <= 65536 ? 16 : \ 24 | -1 25 | 26 | function [7:0] hexdigit; 27 | input [3:0] x; 28 | begin 29 | hexdigit = 30 | x == 0 ? "0" : 31 | x == 1 ? "1" : 32 | x == 2 ? "2" : 33 | x == 3 ? "3" : 34 | x == 4 ? "4" : 35 | x == 5 ? "5" : 36 | x == 6 ? "6" : 37 | x == 7 ? "7" : 38 | x == 8 ? "8" : 39 | x == 9 ? "9" : 40 | x == 10 ? "a" : 41 | x == 11 ? "b" : 42 | x == 12 ? "c" : 43 | x == 13 ? "d" : 44 | x == 14 ? "e" : 45 | x == 15 ? "f" : 46 | "?"; 47 | end 48 | endfunction 49 | 50 | module divide_by_n( 51 | input clk, 52 | input reset, 53 | output reg out 54 | ); 55 | parameter N = 2; 56 | 57 | reg [`CLOG2(N)-1:0] counter; 58 | 59 | always @(posedge clk) 60 | begin 61 | out <= 0; 62 | 63 | if (reset) 64 | counter <= 0; 65 | else 66 | if (counter == 0) 67 | begin 68 | out <= 1; 69 | counter <= N - 1; 70 | end else 71 | counter <= counter - 1; 72 | end 73 | endmodule 74 | 75 | 76 | module fifo( 77 | input clk, 78 | input reset, 79 | output data_available, 80 | input [WIDTH-1:0] write_data, 81 | input write_strobe, 82 | output [WIDTH-1:0] read_data, 83 | input read_strobe 84 | ); 85 | parameter WIDTH = 8; 86 | parameter NUM = 256; 87 | 88 | reg [WIDTH-1:0] buffer[0:NUM-1]; 89 | reg [`CLOG2(NUM)-1:0] write_ptr; 90 | reg [`CLOG2(NUM)-1:0] read_ptr; 91 | 92 | assign read_data = buffer[read_ptr]; 93 | assign data_available = read_ptr != write_ptr; 94 | 95 | always @(posedge clk) begin 96 | if (reset) begin 97 | write_ptr <= 0; 98 | read_ptr <= 0; 99 | end else begin 100 | if (write_strobe) begin 101 | buffer[write_ptr] <= write_data; 102 | write_ptr <= write_ptr + 1; 103 | end 104 | if (read_strobe) begin 105 | read_ptr <= read_ptr + 1; 106 | end 107 | end 108 | end 109 | endmodule 110 | 111 | 112 | module pwm( 113 | input clk, 114 | input [BITS-1:0] bright, 115 | output out 116 | ); 117 | parameter BITS = 8; 118 | 119 | reg [BITS-1:0] counter; 120 | always @(posedge clk) 121 | begin 122 | counter <= counter + 1; 123 | out <= counter < bright; 124 | end 125 | 126 | endmodule 127 | 128 | 129 | /************************************************************************ 130 | * 131 | * Random utility modules. 132 | * 133 | * Micah Dowty 134 | * 135 | ************************************************************************/ 136 | 137 | 138 | module d_flipflop(clk, reset, d_in, d_out); 139 | input clk, reset, d_in; 140 | output d_out; 141 | 142 | reg d_out; 143 | 144 | always @(posedge clk or posedge reset) 145 | if (reset) begin 146 | d_out <= 0; 147 | end 148 | else begin 149 | d_out <= d_in; 150 | end 151 | endmodule 152 | 153 | 154 | module d_flipflop_pair(clk, reset, d_in, d_out); 155 | input clk, reset, d_in; 156 | output d_out; 157 | wire intermediate; 158 | 159 | d_flipflop dff1(clk, reset, d_in, intermediate); 160 | d_flipflop dff2(clk, reset, intermediate, d_out); 161 | endmodule 162 | 163 | 164 | /* 165 | * A set/reset flipflop which is set on sync_set and reset by sync_reset. 166 | */ 167 | module set_reset_flipflop(clk, reset, sync_set, sync_reset, out); 168 | input clk, reset, sync_set, sync_reset; 169 | output out; 170 | reg out; 171 | 172 | always @(posedge clk or posedge reset) 173 | if (reset) 174 | out <= 0; 175 | else if (sync_set) 176 | out <= 1; 177 | else if (sync_reset) 178 | out <= 0; 179 | endmodule 180 | 181 | 182 | /* 183 | * Pulse stretcher. 184 | * 185 | * When the input goes high, the output goes high 186 | * for as long as the input is high, or as long as 187 | * it takes our timer to roll over- whichever is 188 | * longer. 189 | */ 190 | module pulse_stretcher(clk, reset, in, out); 191 | parameter BITS = 20; 192 | 193 | input clk, reset, in; 194 | output out; 195 | reg out; 196 | 197 | reg [BITS-1:0] counter; 198 | 199 | always @(posedge clk or posedge reset) 200 | if (reset) begin 201 | out <= 0; 202 | counter <= 0; 203 | end 204 | else if (counter == 0) begin 205 | out <= in; 206 | counter <= in ? 1 : 0; 207 | end 208 | else if (&counter) begin 209 | if (in) begin 210 | out <= 1; 211 | end 212 | else begin 213 | out <= 0; 214 | counter <= 0; 215 | end 216 | end 217 | else begin 218 | out <= 1; 219 | counter <= counter + 1; 220 | end 221 | endmodule 222 | 223 | 224 | `endif 225 | --------------------------------------------------------------------------------