From 50edcb9576e909931ddd0976e1cb34bf8b2355bb Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 2 Sep 2018 15:44:02 +0200 Subject: [PATCH 01/26] common: Make sure RAM inference works with yosys icecube doesn't care about init values, but yosys does and you can't satisfy them with HW RAM module. So here we remove all the init values and we make sure the reads are not dependent on the reset line Signed-off-by: Sylvain Munaut --- common/usb_fs_in_pe.v | 7 ++++--- common/usb_fs_out_pe.v | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/common/usb_fs_in_pe.v b/common/usb_fs_in_pe.v index d999de4..da64b84 100644 --- a/common/usb_fs_in_pe.v +++ b/common/usb_fs_in_pe.v @@ -51,7 +51,7 @@ module usb_fs_in_pe #( // Data payload to send if any output tx_data_avail, input tx_data_get, - output reg [7:0] tx_data = 0 + output reg [7:0] tx_data ); //////////////////////////////////////////////////////////////////////////////// @@ -344,6 +344,9 @@ module usb_fs_in_pe #( endcase end + always @(posedge clk) + tx_data <= in_data_buffer[buffer_get_addr]; + integer j; always @(posedge clk) begin if (reset) begin @@ -352,8 +355,6 @@ module usb_fs_in_pe #( end else begin in_xfr_state <= in_xfr_state_next; - tx_data <= in_data_buffer[buffer_get_addr]; - if (setup_token_received) begin data_toggle[rx_endp] <= 1; end diff --git a/common/usb_fs_out_pe.v b/common/usb_fs_out_pe.v index 2e43be5..c9307af 100644 --- a/common/usb_fs_out_pe.v +++ b/common/usb_fs_out_pe.v @@ -14,7 +14,7 @@ module usb_fs_out_pe #( output [NUM_OUT_EPS-1:0] out_ep_data_avail, output reg [NUM_OUT_EPS-1:0] out_ep_setup = 0, input [NUM_OUT_EPS-1:0] out_ep_data_get, - output reg [7:0] out_ep_data = 0, + output reg [7:0] out_ep_data, input [NUM_OUT_EPS-1:0] out_ep_stall, output reg [NUM_OUT_EPS-1:0] out_ep_acked = 0, From 1b6dfd84d24046c52856fc3bad67542ebee75061 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 2 Sep 2018 15:42:14 +0200 Subject: [PATCH 02/26] common/serial: Fix syntax error Signed-off-by: Sylvain Munaut --- common/serial.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/serial.v b/common/serial.v index 360d204..b776c70 100644 --- a/common/serial.v +++ b/common/serial.v @@ -11,7 +11,7 @@ module width_adapter #( output data_out_put, input data_out_free, - output [OUTPUT_WIDTH-1:0] data_out, + output [OUTPUT_WIDTH-1:0] data_out ); generate From 483cdf64ff0456b09cce2a59f1d1d9ecba254d65 Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Sun, 2 Sep 2018 15:46:17 +0200 Subject: [PATCH 03/26] common: Make sure to always assign all 'reg's in processes to avoid latches If you don't assign all 'reg's in a process, this effectively describes a latch, and the HW doesn't have any HW latches which leads yosys to create a logic loop, which is definitely not good in FPGA ! Signed-off-by: Sylvain Munaut --- common/usb_fs_in_arb.v | 6 ++---- common/usb_fs_in_pe.v | 4 ++++ common/usb_fs_out_pe.v | 4 ++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/common/usb_fs_in_arb.v b/common/usb_fs_in_arb.v index a331406..186a272 100644 --- a/common/usb_fs_in_arb.v +++ b/common/usb_fs_in_arb.v @@ -20,6 +20,8 @@ module usb_fs_in_arb #( always @* begin grant = 0; + arb_in_ep_data <= 0; + for (i = 0; i < NUM_IN_EPS; i = i + 1) begin in_ep_grant[i] <= 0; @@ -29,9 +31,5 @@ module usb_fs_in_arb #( grant = 1; end end - - if (!grant) begin - arb_in_ep_data <= 0; - end end endmodule diff --git a/common/usb_fs_in_pe.v b/common/usb_fs_in_pe.v index da64b84..16b9faf 100644 --- a/common/usb_fs_in_pe.v +++ b/common/usb_fs_in_pe.v @@ -166,6 +166,8 @@ module usb_fs_in_pe #( always @* begin in_ep_acked[ep_num] <= 0; + ep_state_next[ep_num] <= ep_state[ep_num]; + if (in_ep_stall[ep_num]) begin ep_state_next[ep_num] <= STALL; @@ -277,9 +279,11 @@ module usb_fs_in_pe #( reg rollback_in_xfr; always @* begin + in_xfr_state_next <= in_xfr_state; in_xfr_start <= 0; in_xfr_end <= 0; tx_pkt_start <= 0; + tx_pid <= 4'b0000; rollback_in_xfr <= 0; case (in_xfr_state) diff --git a/common/usb_fs_out_pe.v b/common/usb_fs_out_pe.v index c9307af..26d0802 100644 --- a/common/usb_fs_out_pe.v +++ b/common/usb_fs_out_pe.v @@ -154,6 +154,8 @@ module usb_fs_out_pe #( for (ep_num = 0; ep_num < NUM_OUT_EPS; ep_num = ep_num + 1) begin always @* begin + ep_state_next[ep_num] <= ep_state[ep_num]; + if (out_ep_stall[ep_num]) begin ep_state_next[ep_num] <= STALL; @@ -272,7 +274,9 @@ module usb_fs_out_pe #( //////////////////////////////////////////////////////////////////////////////// always @* begin + out_ep_acked <= 0; out_xfr_start <= 0; + out_xfr_state_next <= out_xfr_state; tx_pkt_start <= 0; tx_pid <= 0; new_pkt_end <= 0; From 50f16d0817b8941fa3077e7754063a1926e5f178 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Sun, 13 Jan 2019 18:16:03 -0500 Subject: [PATCH 04/26] silence warnings --- common/usb_fs_in_pe.v | 8 ++++---- common/usb_fs_rx.v | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/usb_fs_in_pe.v b/common/usb_fs_in_pe.v index 16b9faf..4ce36a7 100644 --- a/common/usb_fs_in_pe.v +++ b/common/usb_fs_in_pe.v @@ -100,9 +100,9 @@ module usb_fs_in_pe #( integer i = 0; initial begin for (i = 0; i < NUM_IN_EPS; i = i + 1) begin - ep_put_addr[i] = 0; - ep_get_addr[i] = 0; - ep_state[i] = 0; + ep_put_addr[i] <= 0; + ep_get_addr[i] <= 0; + ep_state[i] <= 0; end end @@ -400,4 +400,4 @@ module usb_fs_in_pe #( end end -endmodule \ No newline at end of file +endmodule diff --git a/common/usb_fs_rx.v b/common/usb_fs_rx.v index 8c73f68..3ea598d 100644 --- a/common/usb_fs_rx.v +++ b/common/usb_fs_rx.v @@ -224,7 +224,7 @@ module usb_fs_rx ( end end - assign dvalid = dvalid_raw && !(bitstuff_history == 6'b111111); + wire dvalid = dvalid_raw && !(bitstuff_history == 6'b111111); //////////////////////////////////////////////////////////////////////////////// From 50144c08348c46c6f2a52e470787370e5dbe9c52 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 18 Jan 2019 13:22:59 -0500 Subject: [PATCH 05/26] TinyFPGA_BX: enable some IO pins --- boards/TinyFPGA_BX/pins.pcf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/TinyFPGA_BX/pins.pcf b/boards/TinyFPGA_BX/pins.pcf index 2a024b7..913676c 100644 --- a/boards/TinyFPGA_BX/pins.pcf +++ b/boards/TinyFPGA_BX/pins.pcf @@ -8,9 +8,9 @@ #set_io pin_3 B1 #set_io pin_4 C2 #set_io pin_5 C1 -#set_io pin_6 D2 +set_io -nowarn pin_6 D2 #set_io pin_7 D1 -#set_io pin_8 E2 +set_io -nowarn pin_8 E2 #set_io pin_9 E1 #set_io pin_10 G2 #set_io pin_11 H1 From a0676aaeba0413db6568641b50950a35bf713144 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 18 Jan 2019 13:27:39 -0500 Subject: [PATCH 06/26] TinyFPGA_BX: use clock crossing strobe to bridge the 48 MHz USB clock --- boards/TinyFPGA_BX/bootloader.v | 190 +++++++++++++++- boards/TinyFPGA_BX/fifo.v | 391 ++++++++++++++++++++++++++++++++ boards/TinyFPGA_BX/uart.v | 305 +++++++++++++++++++++++++ boards/TinyFPGA_BX/util.v | 220 ++++++++++++++++++ common/strobe.v | 32 +++ common/tinyfpga_bootloader.v | 24 +- common/usb_fs_in_pe.v | 8 + common/usb_fs_out_pe.v | 12 +- common/usb_fs_pe.v | 16 +- common/usb_fs_rx.v | 70 +++--- common/usb_fs_tx.v | 58 ++--- 11 files changed, 1255 insertions(+), 71 deletions(-) create mode 100644 boards/TinyFPGA_BX/fifo.v create mode 100644 boards/TinyFPGA_BX/uart.v create mode 100644 boards/TinyFPGA_BX/util.v create mode 100644 common/strobe.v diff --git a/boards/TinyFPGA_BX/bootloader.v b/boards/TinyFPGA_BX/bootloader.v index 89e3f2b..114aec0 100644 --- a/boards/TinyFPGA_BX/bootloader.v +++ b/boards/TinyFPGA_BX/bootloader.v @@ -1,3 +1,7 @@ +`include "util.v" +`include "fifo.v" +`include "uart.v" + module bootloader ( input pin_clk, @@ -10,8 +14,12 @@ module bootloader ( input pin_29_miso, output pin_30_cs, output pin_31_mosi, - output pin_32_sck + output pin_32_sck, + + output pin_8 // uart ); + wire serial_tx = pin_8; + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////// @@ -20,6 +28,8 @@ module bootloader ( //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// wire clk_48mhz; + wire lock; + wire reset = !lock; SB_PLL40_CORE #( .DIVR(4'b0000), @@ -43,13 +53,17 @@ module bootloader ( .RESETB(1'b1), .BYPASS(1'b0), .LATCHINPUTVALUE(), - .LOCK(), + .LOCK(lock), .SDI(), .SDO(), .SCLK() ); - + reg clk_24mhz; + reg clk_12mhz; + always @(posedge clk_48mhz) clk_24mhz = !clk_24mhz; + always @(posedge clk_24mhz) clk_12mhz = !clk_12mhz; + wire clk = !clk_48mhz; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -74,16 +88,183 @@ module bootloader ( //////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// - wire reset; wire usb_p_tx; wire usb_n_tx; wire usb_p_rx; wire usb_n_rx; wire usb_tx_en; +`ifdef NONONO + + wire bit_strobe; + wire pkt_start; + wire pkt_start; + wire pkt_end; + wire [3:0] pid; + wire [6:0] addr; + wire [3:0] endp; + wire [10:0] frame_num; + wire rx_data_put; + wire [7:0] rx_data; + wire valid_packet; + + usb_fs_rx usb( + .clk_48mhz(clk_48mhz), + .clk(clk), + .reset(reset), + .dp(usb_p_rx), + .dn(usb_n_rx), + .bit_strobe(bit_strobe), + .pkt_start(pkt_start), + .pkt_end(pkt_end), + .pid(pid), + .addr(addr), + .endp(endp), + .frame_num(frame_num), + .rx_data_put(rx_data_put), + .rx_data(rx_data), + .valid_packet(valid_packet) + ); + + assign usb_tx_en = 0; + + parameter FIFO_WIDTH = 24; + reg [FIFO_WIDTH-1:0] fifo_write_data; + reg fifo_write_strobe; + wire [FIFO_WIDTH-1:0] fifo_read_data; + reg fifo_read_strobe; + wire fifo_data_available; + + fifo_bram #(.WIDTH(FIFO_WIDTH)) uart_fifo( + .reset(reset), + .write_clk(clk), + .write_strobe(fifo_write_strobe), + .write_data(fifo_write_data), + .read_clk(clk), + .read_strobe(fifo_read_strobe), + .read_data(fifo_read_data), + .data_available(fifo_data_available) + ); + + always @(posedge clk) + begin + fifo_write_strobe <= 0; + + if (pkt_start) begin + fifo_write_strobe <= 1; + fifo_write_data <= { + 4'hA, + 20'b0, + }; + end else + if (rx_data_put) begin + fifo_write_strobe <= 1; + fifo_write_data <= { + pkt_start ? 4'hA : 4'hB, // 4 + 12'b0, // 12 + rx_data // 8 + }; + end else + if (pkt_end) begin + fifo_write_strobe <= 1; + fifo_write_data <= { + valid_packet ? 4'hC : 4'hF, + pid, // 4 + 1'b0, addr, // 1 + 7 + frame_num[7:0] // 8 + }; + end + end +`endif + + reg uart_strobe; + reg [7:0] uart_data; + wire uart_ready; + + wire clk_1; + divide_by_n #(.N(16)) div48(clk_48mhz, reset, clk_1); + + uart_tx_fifo uart_tx( + .clk(clk), + .reset(reset), + .baud_x1(clk_1), + .data(uart_data), + .data_strobe(uart_strobe), + .serial(serial_tx) + ); + +/* + reg [FIFO_WIDTH-1:0] hexdata; + reg [7:0] len; + reg [12:0] counter; + + always @(posedge clk) + begin + uart_strobe <= 0; + fifo_read_strobe <= 0; + counter <= counter + 1; + pin_led <= 0; + + if (!uart_ready + || uart_strobe + || counter != 0 + ) begin + // nothing + end else + begin + uart_data <= "A"; + uart_strobe <= 1; + pin_led <= 1; + end + end +*/ +/* + always @(posedge clk) + begin + uart_strobe <= 0; + fifo_read_strobe <= 0; + counter <= counter + 1; + pin_led <= 0; + + if (len == 0 + && fifo_data_available + && !fifo_read_strobe) begin + len <= 8; + hexdata <= fifo_read_data; + fifo_read_strobe <= 1; + pin_led <= 1; + end else + if (!uart_ready + || uart_strobe + || counter != 0 + ) begin + // nothing + end else + if (len == 1) begin + uart_data <= "\n"; + uart_strobe <= 1; + len <= 0; + end else + if (len == 2) begin + uart_data <= "\r"; + uart_strobe <= 1; + len <= 1; + end else + if (len != 0) begin + uart_data <= hexdigit(hexdata[FIFO_WIDTH-1:FIFO_WIDTH-4]); + uart_strobe <= 1; + hexdata <= { hexdata[FIFO_WIDTH-5:0], 4'b0 }; + len <= len - 1; + end + end +*/ + tinyfpga_bootloader tinyfpga_bootloader_inst ( .clk_48mhz(clk_48mhz), + .clk(clk), .reset(reset), + .uart_data(uart_data), + .uart_strobe(uart_strobe), .usb_p_tx(usb_p_tx), .usb_n_tx(usb_n_tx), .usb_p_rx(usb_p_rx), @@ -103,5 +284,4 @@ module bootloader ( assign usb_p_rx = usb_tx_en ? 1'b1 : pin_usbp; assign usb_n_rx = usb_tx_en ? 1'b0 : pin_usbn; - assign reset = 1'b0; endmodule diff --git a/boards/TinyFPGA_BX/fifo.v b/boards/TinyFPGA_BX/fifo.v new file mode 100644 index 0000000..304ad9a --- /dev/null +++ b/boards/TinyFPGA_BX/fifo.v @@ -0,0 +1,391 @@ + +/** 256 Kb SPRAM, organized 16 K x 16 bits */ +module spram( + input clk, + input reset = 0, + input cs = 1, + input [DEPTH-1:0] addr, + input write_strobe, + input [15:0] write_data, + output [15:0] read_data +); + parameter DEPTH = 16; + + wire [15:0] read_data_0; + wire [15:0] read_data_1; + wire [15:0] read_data_2; + wire [15:0] read_data_3; + + wire cs0, cs1, cs2, cs3; +/* + generate if (DEPTH == 14) + assign cs0 = cs; + assign cs1 = 0; + assign cs2 = 0; + assign cs3 = 0; + endgenerate + generate if (DEPTH == 15) + assign cs0 = cs & addr[14] == 1'b0; + assign cs1 = cs & addr[14] == 1'b1; + assign cs2 = 0; + assign cs3 = 0; + endgenerate +*/ + generate if (DEPTH == 16) + assign cs0 = cs && addr[15:14] == 2'b00; + assign cs1 = cs && addr[15:14] == 2'b01; + assign cs2 = cs && addr[15:14] == 2'b10; + assign cs3 = cs && addr[15:14] == 2'b11; + endgenerate + + assign read_data = + cs0 ? read_data_0 : + cs1 ? read_data_1 : + cs2 ? read_data_2 : + read_data_3; + + SB_SPRAM256KA spram0( + .DATAOUT(read_data_0), + .ADDRESS(addr[13:0]), + .DATAIN(write_data), + .MASKWREN(4'b1111), + .WREN(write_strobe), + .CHIPSELECT(cs0 && !reset), + .CLOCK(clk), + + // if we cared about power, maybe we would adjust these + .STANDBY(1'b0), + .SLEEP(1'b0), + .POWEROFF(1'b1) + ); + + generate if (DEPTH > 14) + SB_SPRAM256KA spram1( + .DATAOUT(read_data_1), + .ADDRESS(addr[13:0]), + .DATAIN(write_data), + .MASKWREN(4'b1111), + .WREN(write_strobe), + .CHIPSELECT(cs1 && !reset), + .CLOCK(clk), + + // if we cared about power, maybe we would adjust these + .STANDBY(1'b0), + .SLEEP(1'b0), + .POWEROFF(1'b1) + ); + endgenerate + + generate if (DEPTH > 15) + + SB_SPRAM256KA spram2( + .DATAOUT(read_data_2), + .ADDRESS(addr[13:0]), + .DATAIN(write_data), + .MASKWREN(4'b1111), + .WREN(write_strobe), + .CHIPSELECT(cs2 && !reset), + .CLOCK(clk), + + // if we cared about power, maybe we would adjust these + .STANDBY(1'b0), + .SLEEP(1'b0), + .POWEROFF(1'b1) + ); + + SB_SPRAM256KA spram3( + .DATAOUT(read_data_3), + .ADDRESS(addr[13:0]), + .DATAIN(write_data), + .MASKWREN(4'b1111), + .WREN(write_strobe), + .CHIPSELECT(cs3 && !reset), + .CLOCK(clk), + + // if we cared about power, maybe we would adjust these + .STANDBY(1'b0), + .SLEEP(1'b0), + .POWEROFF(1'b1) + ); + endgenerate +endmodule + + +module fifo_spram( + input clk, + input reset, + input [WIDTH-1:0] write_data, + input write_strobe, + output [WIDTH-1:0] read_data, + input read_strobe, + output data_available +); + parameter WIDTH = 16; + parameter DEPTH = 16; // 14 == one SPRAM deep, 15 == two deep, 16 == four + reg [DEPTH-1:0] write_ptr = 0; + reg [DEPTH-1:0] read_ptr = 0; + assign data_available = read_ptr != write_ptr; + + spram #( + .DEPTH(DEPTH) + ) buf0( + .clk(clk), + .reset(reset), + .write_strobe(write_strobe), + .addr(write_strobe ? write_ptr : read_ptr), + .write_data(write_data[15:0]), + .read_data(read_data[15:0]), + ); + + generate if (WIDTH > 16) + spram #( + .DEPTH(DEPTH) + ) buf1( + .clk(clk), + .reset(reset), + .write_strobe(write_strobe), + .addr(write_strobe ? write_ptr : read_ptr), + .write_data(write_data[31:16]), + .read_data(read_data[31:16]), + ); + endgenerate + + generate if (WIDTH > 32) + spram #( + .DEPTH(DEPTH) + ) buf2( + .clk(clk), + .reset(reset), + .write_strobe(write_strobe), + .addr(write_strobe ? write_ptr : read_ptr), + .write_data(write_data[47:32]), + .read_data(read_data[47:32]), + ); + endgenerate + + generate if (WIDTH > 48) + spram #( + .DEPTH(DEPTH) + ) buf3( + .clk(clk), + .reset(reset), + .write_strobe(write_strobe), + .addr(write_strobe ? write_ptr : read_ptr), + .write_data(write_data[63:48]), + .read_data(read_data[63:48]), + ); + endgenerate + + always @(posedge clk) + begin + if (write_strobe) + write_ptr <= write_ptr + 1; + + if (read_strobe) + read_ptr <= read_ptr + 1; + end +endmodule + + + +module fifo_bram( + input reset, + input write_clk, + input write_strobe, + input [WIDTH-1:0] write_data, + input read_clk, + input read_strobe, + output [WIDTH-1:0] read_data, + output data_available +); + parameter WIDTH = 16; // one block RAM wide + parameter DEPTH = 8; // one block RAM deep + reg [DEPTH-1:0] read_ptr; + reg [DEPTH-1:0] write_ptr; + + reg [WIDTH-1:0] fifo[(1 << DEPTH)-1:0]; + + assign read_data = fifo[read_ptr]; + + reg data_available_0; + reg data_available_1; + //reg data_available; + assign data_available = read_ptr != write_ptr; + + always @(posedge read_clk) + begin + if (reset) + read_ptr <= 0; + else + if (read_strobe) + read_ptr <= read_ptr + 1; + + //data_available <= read_ptr != write_ptr; + //data_available <= data_available_0; + //data_available <= data_available_1; + end + + always @(posedge write_clk) + begin + if (reset) + write_ptr <= 0; + else + if (write_strobe) begin + fifo[write_ptr] <= write_data; + write_ptr <= write_ptr + 1; + end + end +endmodule + + +module fifo_combo( + input reset, + input write_clk, + input write_strobe, + input [WIDTH-1:0] write_data, + input read_clk, + input read_strobe, + output [WIDTH-1:0] read_data, + output data_available +); + parameter WIDTH = 16; + +`define NO_SPRAM +`ifdef NO_SPRAM + parameter DEPTH = 12; + // just wire it up + fifo_bram #( + .WIDTH(WIDTH), + .DEPTH(DEPTH) + ) fifo0( + .reset(reset), + .write_clk(write_clk), + .write_strobe(write_strobe), + .write_data(write_data), + .read_clk(read_clk), + .read_strobe(read_strobe), + .read_data(read_data), + .data_available(data_available) + ); +`else + parameter DEPTH = 16; + wire [WIDTH-1:0] fifo0_read_data; + reg fifo0_read_strobe; + wire fifo0_data_available; + reg fifo1_write_strobe; + + fifo_bram #( + .WIDTH(WIDTH), + ) fifo0( + .reset(reset), + .write_clk(write_clk), + .write_strobe(write_strobe), + .write_data(write_data), + .read_clk(read_clk), + .read_strobe(fifo0_read_strobe), + .read_data(fifo0_read_data), + .data_available(fifo0_data_available) + ); + + fifo_spram #( + .WIDTH(WIDTH), + .DEPTH(DEPTH) + ) fifo1( + .reset(reset), + .clk(read_clk), + //.write_data(32'hA55AB00F), + .write_data(fifo0_read_data), + .write_strobe(fifo1_write_strobe), + .read_data(read_data), + .read_strobe(read_strobe), + .data_available(data_available) + ); + + reg [3:0] counter; + + always @(posedge read_clk) begin + fifo0_read_strobe <= 0; + fifo1_write_strobe <= 0; + counter <= counter + 1; + + if (reset) begin + // nothing + end else + if (fifo0_data_available + && !fifo0_read_strobe + && !fifo1_write_strobe + && !read_strobe // don't move if the user is also moving + && counter == 0 + ) begin + // move data from fifo0 into fifo1 + fifo0_read_strobe <= 1; + fifo1_write_strobe <= 1; + end + end +`endif +endmodule + +module fifo_bram_16to8( + input read_clk, + input write_clk, + input reset, + output data_available, + input [16-1:0] write_data, + input write_strobe, + output [8-1:0] read_data, + input read_strobe +); + + reg [BITS-1:0] write_ptr; + reg [BITS-1:0] read_ptr; + + // reads from the SPRAM are 16-bits at a time, + // so we have to pick which byte of the word should be extracted +`undef BUFFER +`ifdef BUFFER + parameter BITS = 13; + reg [15:0] buffer[(1 << BITS)-1:0]; + wire [15:0] rdata_16 = buffer[read_ptr[BITS-1:1]]; +`else + parameter BITS = 8; + wire [15:0] rdata_16; +SB_RAM40_4K #(.READ_MODE(0), .WRITE_MODE(0)) ram256x16_inst ( +.RDATA(rdata_16[15:0]), +.RADDR({ 4'b0, read_ptr[BITS-1:1] }), +.RCLK(read_clk), +.RCLKE(!reset), +.RE(1), +.WADDR({ 4'b0, write_ptr[BITS-1:1] }), +.WCLK(write_clk), +.WCLKE(!reset), +.WDATA(write_data[15:0]), +.WE(write_strobe), +.MASK(16'h0) +); +`endif + assign data_available = read_ptr != write_ptr; + assign read_data = (!read_ptr[0]) ? rdata_16[15:8] : rdata_16[7:0]; + + always @(posedge read_clk) + begin + if (reset) begin + read_ptr <= 0; + end else + if (read_strobe) begin + read_ptr <= read_ptr + 1; + end + end + + always @(posedge write_clk) + begin + if (reset) begin + write_ptr <= 0; + end else + if (write_strobe) begin +`ifdef BUFFER + buffer[write_ptr[BITS-1:1]] <= write_data; +`endif + write_ptr <= write_ptr + 2; + end + end +endmodule diff --git a/boards/TinyFPGA_BX/uart.v b/boards/TinyFPGA_BX/uart.v new file mode 100644 index 0000000..39f1e12 --- /dev/null +++ b/boards/TinyFPGA_BX/uart.v @@ -0,0 +1,305 @@ + /* + * uart.v - High-speed serial support. Includes a baud generator, UART, + * and a simple RFC1662-inspired packet framing protocol. + * + * This module is designed a 3 Mbaud serial port. + * This is the highest data rate supported by + * the popular FT232 USB-to-serial chip. + * + * Copyright (C) 2009 Micah Dowty + * (C) 2018 Trammell Hudson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + +/* + * Byte transmitter, RS-232 8-N-1 + * + * Transmits on 'serial'. When 'ready' goes high, we can accept another byte. + * It should be supplied on 'data' with a pulse on 'data_strobe'. + */ + +module uart_tx( + input clk, + input reset, + input baud_x1, + output serial, + output reg ready, + input [7:0] data, + input data_strobe +); + + /* + * Left-to-right shift register. + * Loaded with data, start bit, and stop bit. + * + * The stop bit doubles as a flag to tell us whether data has been + * loaded; we initialize the whole shift register to zero on reset, + * and when the register goes zero again, it's ready for more data. + */ + reg [7+1+1:0] shiftreg; + + /* + * Serial output register. This is like an extension of the + * shift register, but we never load it separately. This gives + * us one bit period of latency to prepare the next byte. + * + * This register is inverted, so we can give it a reset value + * of zero and still keep the 'serial' output high when idle. + */ + reg serial_r; + assign serial = !serial_r; + + //assign ready = (shiftreg == 0); + + /* + * State machine + */ + + always @(posedge clk) + if (reset) begin + shiftreg <= 0; + serial_r <= 0; + end + else if (data_strobe) begin + shiftreg <= { + 1'b1, // stop bit + data, + 1'b0 // start bit (inverted) + }; + ready <= 0; + end + else if (baud_x1) begin + if (shiftreg == 0) + begin + /* Idle state is idle high, serial_r is inverted */ + serial_r <= 0; + ready <= 1; + end else + serial_r <= !shiftreg[0]; + // shift the output register down + shiftreg <= {1'b0, shiftreg[7+1+1:1]}; + end else + ready <= (shiftreg == 0); + +endmodule + + +/* + * Byte receiver, RS-232 8-N-1 + * + * Receives on 'serial'. When a properly framed byte is + * received, 'data_strobe' pulses while the byte is on 'data'. + * + * Error bytes are ignored. + */ + +module uart_rx(clk, reset, baud_x4, + serial, data, data_strobe); + + input clk, reset, baud_x4, serial; + output [7:0] data; + output data_strobe; + + /* + * Synchronize the serial input to this clock domain + */ + wire serial_sync; + d_flipflop_pair input_dff(clk, reset, serial, serial_sync); + + /* + * State machine: Four clocks per bit, 10 total bits. + */ + reg [8:0] shiftreg; + reg [5:0] state; + reg data_strobe; + wire [3:0] bit_count = state[5:2]; + wire [1:0] bit_phase = state[1:0]; + + wire sampling_phase = (bit_phase == 1); + wire start_bit = (bit_count == 0 && sampling_phase); + wire stop_bit = (bit_count == 9 && sampling_phase); + + wire waiting_for_start = (state == 0 && serial_sync == 1); + + wire error = ( (start_bit && serial_sync == 1) || + (stop_bit && serial_sync == 0) ); + + assign data = shiftreg[7:0]; + + always @(posedge clk or posedge reset) + if (reset) begin + state <= 0; + data_strobe <= 0; + end + else if (baud_x4) begin + + if (waiting_for_start || error || stop_bit) + state <= 0; + else + state <= state + 1; + + if (bit_phase == 1) + shiftreg <= { serial_sync, shiftreg[8:1] }; + + data_strobe <= stop_bit && !error; + + end + else begin + data_strobe <= 0; + end + +endmodule + + +/* + * Output UART with a SPRAM RAM FIFO queue. + * + * Add bytes to the queue and they will be printed when the line is idle. + */ +module uart_tx_fifo( + input clk, + input reset, + input baud_x1, + input [7:0] data, + input data_strobe, + output serial +); + parameter NUM = 32; + + wire uart_txd_ready; // high the UART is ready to take a new byte + reg uart_txd_strobe; // pulse when we have a new byte to transmit + reg [7:0] uart_txd; + + uart_tx txd( + .clk(clk), + .reset(reset), + .baud_x1(baud_x1), + .serial(serial), + .ready(uart_txd_ready), + .data(uart_txd), + .data_strobe(uart_txd_strobe) + ); + + wire fifo_available; + wire fifo_read_strobe; + wire [7:0] fifo_read_data; + + fifo_bram #(.WIDTH(8)) buffer( + .read_clk(clk), + .write_clk(clk), + .reset(reset), + .write_data(data), + .write_strobe(data_strobe), + .data_available(fifo_available), + .read_data(fifo_read_data), + .read_strobe(fifo_read_strobe) + ); + + // drain the fifo into the serial port + reg [3:0] counter; + always @(posedge clk) + begin + uart_txd_strobe <= 0; + fifo_read_strobe <= 0; + counter <= counter + 1; + + if (fifo_available + && uart_txd_ready + && !data_strobe // only single port port RAM + && !uart_txd_strobe // don't TX twice on one byte + && counter == 0 + ) begin + fifo_read_strobe <= 1; + uart_txd_strobe <= 1; + uart_txd <= fifo_read_data; + end + end +endmodule + + +module uart_tx_hexdump( + input clk, + input reset = 0, + input strobe, + input [31:0] data, + input [3:0] len, + input space, + input newline, + output ready, + input uart_txd_ready, + output uart_txd_strobe, + output [7:0] uart_txd +); + reg [3:0] digits; + reg [31:0] bytes; + reg [7:0] uart_txd; + reg in_progress = 0; + reg [8:0] counter; + + assign ready = !in_progress; + + always @(posedge clk) + begin + uart_txd_strobe <= 0; + + if (reset) begin + // nothing to do + in_progress <= 0; + end else + if (strobe) begin + digits <= len; + bytes <= data; + in_progress <= 1; + end else + if (uart_txd_strobe + || !uart_txd_ready + || !in_progress + || counter != 0 + ) begin + // nothing to do until uart is ready + // or we're in progress with an output + counter <= counter + 1; + end else + if (digits != 0) + begin + // time to generate a hex value! + uart_txd_strobe <= 1; + uart_txd <= hexdigit(bytes[31:28]); + + bytes <= { bytes[27:0], 4'b0 }; + digits <= digits - 1; + end else + begin + // after all the digits, output any whitespace + if (space) begin + uart_txd_strobe <= 1; + uart_txd <= " "; + end else + if (newline) begin + uart_txd_strobe <= 1; + uart_txd <= "\n"; + end + + in_progress <= 0; + counter <= 0; + end + end +endmodule diff --git a/boards/TinyFPGA_BX/util.v b/boards/TinyFPGA_BX/util.v new file mode 100644 index 0000000..ec69fc7 --- /dev/null +++ b/boards/TinyFPGA_BX/util.v @@ -0,0 +1,220 @@ +/** \file + * Utility modules. + */ + +`define CLOG2(x) \ + x <= 2 ? 1 : \ + x <= 4 ? 2 : \ + x <= 8 ? 3 : \ + x <= 16 ? 4 : \ + x <= 32 ? 5 : \ + x <= 64 ? 6 : \ + x <= 128 ? 7 : \ + x <= 256 ? 8 : \ + x <= 512 ? 9 : \ + x <= 1024 ? 10 : \ + x <= 2048 ? 11 : \ + x <= 4096 ? 12 : \ + x <= 8192 ? 13 : \ + x <= 16384 ? 14 : \ + x <= 32768 ? 15 : \ + x <= 65536 ? 16 : \ + -1 + +function [7:0] hexdigit; + input [3:0] x; + begin + hexdigit = + x == 0 ? "0" : + x == 1 ? "1" : + x == 2 ? "2" : + x == 3 ? "3" : + x == 4 ? "4" : + x == 5 ? "5" : + x == 6 ? "6" : + x == 7 ? "7" : + x == 8 ? "8" : + x == 9 ? "9" : + x == 10 ? "a" : + x == 11 ? "b" : + x == 12 ? "c" : + x == 13 ? "d" : + x == 14 ? "e" : + x == 15 ? "f" : + "?"; + end +endfunction + +module divide_by_n( + input clk, + input reset, + output reg out +); + parameter N = 2; + + reg [`CLOG2(N)-1:0] counter; + + always @(posedge clk) + begin + out <= 0; + + if (reset) + counter <= 0; + else + if (counter == 0) + begin + out <= 1; + counter <= N - 1; + end else + counter <= counter - 1; + end +endmodule + + +module fifo( + input clk, + input reset, + output data_available, + input [WIDTH-1:0] write_data, + input write_strobe, + output [WIDTH-1:0] read_data, + input read_strobe +); + parameter WIDTH = 8; + parameter NUM = 256; + + reg [WIDTH-1:0] buffer[0:NUM-1]; + reg [`CLOG2(NUM)-1:0] write_ptr; + reg [`CLOG2(NUM)-1:0] read_ptr; + + assign read_data = buffer[read_ptr]; + assign data_available = read_ptr != write_ptr; + + always @(posedge clk) begin + if (reset) begin + write_ptr <= 0; + read_ptr <= 0; + end else begin + if (write_strobe) begin + buffer[write_ptr] <= write_data; + write_ptr <= write_ptr + 1; + end + if (read_strobe) begin + read_ptr <= read_ptr + 1; + end + end + end +endmodule + + +module pwm( + input clk, + input [BITS-1:0] bright, + output out +); + parameter BITS = 8; + + reg [BITS-1:0] counter; + always @(posedge clk) + begin + counter <= counter + 1; + out <= counter < bright; + end + +endmodule + + +/************************************************************************ + * + * Random utility modules. + * + * Micah Dowty + * + ************************************************************************/ + + +module d_flipflop(clk, reset, d_in, d_out); + input clk, reset, d_in; + output d_out; + + reg d_out; + + always @(posedge clk or posedge reset) + if (reset) begin + d_out <= 0; + end + else begin + d_out <= d_in; + end +endmodule + + +module d_flipflop_pair(clk, reset, d_in, d_out); + input clk, reset, d_in; + output d_out; + wire intermediate; + + d_flipflop dff1(clk, reset, d_in, intermediate); + d_flipflop dff2(clk, reset, intermediate, d_out); +endmodule + + +/* + * A set/reset flipflop which is set on sync_set and reset by sync_reset. + */ +module set_reset_flipflop(clk, reset, sync_set, sync_reset, out); + input clk, reset, sync_set, sync_reset; + output out; + reg out; + + always @(posedge clk or posedge reset) + if (reset) + out <= 0; + else if (sync_set) + out <= 1; + else if (sync_reset) + out <= 0; +endmodule + + +/* + * Pulse stretcher. + * + * When the input goes high, the output goes high + * for as long as the input is high, or as long as + * it takes our timer to roll over- whichever is + * longer. + */ +module pulse_stretcher(clk, reset, in, out); + parameter BITS = 20; + + input clk, reset, in; + output out; + reg out; + + reg [BITS-1:0] counter; + + always @(posedge clk or posedge reset) + if (reset) begin + out <= 0; + counter <= 0; + end + else if (counter == 0) begin + out <= in; + counter <= in ? 1 : 0; + end + else if (&counter) begin + if (in) begin + out <= 1; + end + else begin + out <= 0; + counter <= 0; + end + end + else begin + out <= 1; + counter <= counter + 1; + end +endmodule + diff --git a/common/strobe.v b/common/strobe.v new file mode 100644 index 0000000..2ec4bbb --- /dev/null +++ b/common/strobe.v @@ -0,0 +1,32 @@ +module strobe( + input clk_in, + input clk_out, + input strobe_in, + output strobe_out, + input [WIDTH-1:0] data_in, + output [WIDTH-1:0] data_out +); + parameter WIDTH = 1; +`define CLOCK_CROSS +`ifdef CLOCK_CROSS + reg flag; + reg [2:0] sync; + reg [WIDTH-1:0] data; + + always @(posedge clk_in) begin + flag <= flag ^ strobe_in; + if (strobe_in) + data <= data_in; + end + + always @(posedge clk_out) + sync <= { sync[1:0], flag }; + + assign strobe_out = sync[1] ^ sync[0]; + assign data_out = data; + //assign data_out = data_in; +`else + assign strobe_out = strobe_in; + assign data_out = data_in; +`endif +endmodule diff --git a/common/tinyfpga_bootloader.v b/common/tinyfpga_bootloader.v index 578ca22..155327e 100644 --- a/common/tinyfpga_bootloader.v +++ b/common/tinyfpga_bootloader.v @@ -1,7 +1,11 @@ module tinyfpga_bootloader ( input clk_48mhz, + input clk, input reset, + output uart_strobe, + output [7:0] uart_data, + // USB lines. Split into input vs. output and oe control signal to maintain // highest level of compatibility with synthesis tools. output usb_p_tx, @@ -26,6 +30,7 @@ module tinyfpga_bootloader ( // function. output boot ); + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////// @@ -38,7 +43,7 @@ module tinyfpga_bootloader ( reg [5:0] ns_cnt = 0; wire ns_rst = (ns_cnt == 48); - always @(posedge clk_48mhz) begin + always @(posedge clk) begin if (ns_rst) begin ns_cnt <= 0; end else begin @@ -48,7 +53,7 @@ module tinyfpga_bootloader ( reg [9:0] us_cnt = 0; wire us_rst = (us_cnt == 1000); - always @(posedge clk_48mhz) begin + always @(posedge clk) begin if (us_rst) begin us_cnt <= 0; end else if (ns_rst) begin @@ -57,7 +62,7 @@ module tinyfpga_bootloader ( end reg count_down = 0; - always @(posedge clk_48mhz) begin + always @(posedge clk) begin if (us_rst) begin if (count_down) begin if (led_pwm == 0) begin @@ -74,7 +79,7 @@ module tinyfpga_bootloader ( end end end - always @(posedge clk_48mhz) pwm_cnt <= pwm_cnt + 1'b1; + always @(posedge clk) pwm_cnt <= pwm_cnt + 1'b1; assign led = led_pwm > pwm_cnt; @@ -136,7 +141,7 @@ module tinyfpga_bootloader ( assign boot = host_presence_timeout || boot_to_user_design; usb_serial_ctrl_ep ctrl_ep_inst ( - .clk(clk_48mhz), + .clk(clk), .reset(reset), .dev_addr(dev_addr), @@ -163,7 +168,7 @@ module tinyfpga_bootloader ( ); usb_spi_bridge_ep usb_spi_bridge_ep_inst ( - .clk(clk_48mhz), + .clk(clk), .reset(reset), // out endpoint interface @@ -204,8 +209,11 @@ module tinyfpga_bootloader ( .NUM_OUT_EPS(5'd2), .NUM_IN_EPS(5'd3) ) usb_fs_pe_inst ( - .clk(clk_48mhz), + .clk_48mhz(clk_48mhz), + .clk(clk), .reset(reset), + .uart_strobe(uart_strobe), + .uart_data(uart_data), .usb_p_tx(usb_p_tx), .usb_n_tx(usb_n_tx), @@ -246,7 +254,7 @@ module tinyfpga_bootloader ( // host presence detection //////////////////////////////////////////////////////////////////////////////// - always @(posedge clk_48mhz) begin + always @(posedge clk) begin if (sof_valid) begin host_presence_timer <= 0; host_presence_timeout <= 0; diff --git a/common/usb_fs_in_pe.v b/common/usb_fs_in_pe.v index 4ce36a7..99b3b6c 100644 --- a/common/usb_fs_in_pe.v +++ b/common/usb_fs_in_pe.v @@ -5,6 +5,8 @@ module usb_fs_in_pe #( ) ( input clk, input reset, + output uart_strobe, + output [7:0] uart_data, input [NUM_IN_EPS-1:0] reset_ep, input [6:0] dev_addr, @@ -353,11 +355,17 @@ module usb_fs_in_pe #( integer j; always @(posedge clk) begin + uart_strobe <= 0; + if (reset) begin in_xfr_state <= IDLE; end else begin in_xfr_state <= in_xfr_state_next; + if (in_xfr_state != in_xfr_state_next) begin + uart_strobe <= 1; + uart_data <= in_xfr_state_next + "A"; + end if (setup_token_received) begin data_toggle[rx_endp] <= 1; diff --git a/common/usb_fs_out_pe.v b/common/usb_fs_out_pe.v index 26d0802..012e66b 100644 --- a/common/usb_fs_out_pe.v +++ b/common/usb_fs_out_pe.v @@ -5,6 +5,8 @@ module usb_fs_out_pe #( ) ( input clk, input reset, + output uart_strobe, + output [7:0] uart_data, input [NUM_OUT_EPS-1:0] reset_ep, input [6:0] dev_addr, @@ -287,7 +289,6 @@ module usb_fs_out_pe #( if (out_token_received || setup_token_received) begin out_xfr_state_next <= RCVD_OUT; out_xfr_start <= 1; - end else begin out_xfr_state_next <= IDLE; end @@ -296,7 +297,6 @@ module usb_fs_out_pe #( RCVD_OUT : begin if (rx_pkt_start) begin out_xfr_state_next <= RCVD_DATA_START; - end else begin out_xfr_state_next <= RCVD_OUT; end @@ -355,10 +355,18 @@ module usb_fs_out_pe #( integer j; always @(posedge clk) begin + uart_strobe <= 0; + if (reset) begin out_xfr_state <= IDLE; end else begin out_xfr_state <= out_xfr_state_next; + if (out_xfr_state != out_xfr_state_next) begin + uart_strobe <= 1; + uart_data <= out_xfr_state_next + "A"; + if (out_xfr_state == RCVD_DATA_END) + uart_data <= "0" + tx_pid; + end if (out_xfr_start) begin current_endp <= rx_endp; diff --git a/common/usb_fs_pe.v b/common/usb_fs_pe.v index dadb719..924bdff 100644 --- a/common/usb_fs_pe.v +++ b/common/usb_fs_pe.v @@ -2,9 +2,11 @@ module usb_fs_pe #( parameter [4:0] NUM_OUT_EPS = 1, parameter [4:0] NUM_IN_EPS = 1 ) ( + input clk_48mhz, input clk, input [6:0] dev_addr, - + output uart_strobe, + output [7:0] uart_data, //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -123,6 +125,8 @@ module usb_fs_pe #( .NUM_IN_EPS(NUM_IN_EPS) ) usb_fs_in_pe_inst ( .clk(clk), + //.uart_strobe(uart_strobe), + //.uart_data(uart_data), .reset(reset), .reset_ep({NUM_IN_EPS{1'b0}}), .dev_addr(dev_addr), @@ -159,6 +163,8 @@ module usb_fs_pe #( .clk(clk), .reset(reset), .reset_ep({NUM_OUT_EPS{1'b0}}), + .uart_strobe(uart_strobe), + .uart_data(uart_data), .dev_addr(dev_addr), // endpoint interface @@ -187,7 +193,8 @@ module usb_fs_pe #( ); usb_fs_rx usb_fs_rx_inst ( - .clk_48mhz(clk), + .clk_48mhz(clk_48mhz), + .clk(clk), .reset(reset), .dp(usb_p_rx), .dn(usb_n_rx), @@ -218,7 +225,8 @@ module usb_fs_pe #( ); usb_fs_tx usb_fs_tx_inst ( - .clk_48mhz(clk), + .clk_48mhz(clk_48mhz), + .clk(clk), .reset(reset), .bit_strobe(bit_strobe), .oe(usb_tx_en), @@ -231,4 +239,4 @@ module usb_fs_pe #( .tx_data_get(tx_data_get), .tx_data(tx_data) ); -endmodule \ No newline at end of file +endmodule diff --git a/common/usb_fs_rx.v b/common/usb_fs_rx.v index 3ea598d..19ea976 100644 --- a/common/usb_fs_rx.v +++ b/common/usb_fs_rx.v @@ -1,36 +1,39 @@ module usb_fs_rx ( // A 48MHz clock is required to recover the clock from the incoming data. input clk_48mhz, + input clk, input reset, // USB data+ and data- lines. input dp, input dn, - // pulse on every bit transition. + // pulse on every bit transition in clk_48mhz output bit_strobe, - // Pulse on beginning of new packet. + // Pulse on beginning of new packet in clk. output pkt_start, - // Pulse on end of current packet. + // Pulse on end of current packet in clk. output pkt_end, // Most recent packet decoded. output [3:0] pid, - output reg [6:0] addr = 0, - output reg [3:0] endp = 0, - output reg [10:0] frame_num = 0, + output [6:0] addr, + output [3:0] endp, + output [10:0] frame_num, - // Pulse on valid data on rx_data. + // Pulse on valid data on rx_data in clk. output rx_data_put, output [7:0] rx_data, // Most recent packet passes PID and CRC checks output valid_packet ); - wire clk = clk_48mhz; - + wire [3:0] pid_48; + reg [6:0] addr_48; + reg [3:0] endp_48; + reg [10:0] frame_num_48; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////// @@ -51,7 +54,7 @@ module usb_fs_rx ( reg [3:0] dpair_q = 0; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin dpair_q[3:0] <= {dpair_q[1:0], dp, dn}; end @@ -78,7 +81,7 @@ module usb_fs_rx ( wire [1:0] dpair = dpair_q[3:2]; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin case (line_state) // if we are in a transition state, then we can sample the pair and // move to the next corresponding line state @@ -122,7 +125,7 @@ module usb_fs_rx ( wire line_state_valid = (bit_phase == 1); assign bit_strobe = (bit_phase == 2); - always @(posedge clk) begin + always @(posedge clk_48mhz) begin // keep track of phase within each bit if (line_state == DT) begin bit_phase <= 0; @@ -165,7 +168,7 @@ module usb_fs_rx ( end end - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (reset) begin line_history <= 6'b101010; packet_valid <= 0; @@ -214,7 +217,7 @@ module usb_fs_rx ( reg [5:0] bitstuff_history = 0; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (reset || packet_end) begin bitstuff_history <= 6'b000000; end else begin @@ -237,7 +240,7 @@ module usb_fs_rx ( wire pid_valid = full_pid[4:1] == ~full_pid[8:5]; wire pid_complete = full_pid[0]; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (packet_start) begin full_pid <= 9'b100000000; end @@ -253,7 +256,7 @@ module usb_fs_rx ( reg [4:0] crc5 = 0; wire crc5_valid = crc5 == 5'b01100; wire crc5_invert = din ^ crc5[4]; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (packet_start) begin crc5 <= 5'b11111; end @@ -274,7 +277,7 @@ module usb_fs_rx ( wire crc16_valid = crc16 == 16'b1000000000001101; wire crc16_invert = din ^ crc16[15]; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (packet_start) begin crc16 <= 16'b1111111111111111; end @@ -319,7 +322,7 @@ module usb_fs_rx ( reg [11:0] token_payload = 0; wire token_payload_done = token_payload[0]; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (packet_start) begin token_payload <= 12'b100000000000; end @@ -329,17 +332,32 @@ module usb_fs_rx ( end end - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (token_payload_done && pkt_is_token) begin - addr <= token_payload[7:1]; - endp <= token_payload[11:8]; - frame_num <= token_payload[11:1]; + addr_48 <= token_payload[7:1]; + endp_48 <= token_payload[11:8]; + frame_num_48 <= token_payload[11:1]; end end - assign pkt_start = packet_start; - assign pkt_end = packet_end; - assign pid = full_pid[4:1]; + //assign pkt_start = packet_start; + //assign pkt_end = packet_end; + strobe pkt_start_strobe(clk_48mhz, clk, packet_start, pkt_start); + + // at the end of the packet, capture the parameters + strobe #(.WIDTH(26)) pkt_end_strobe( + clk_48mhz, clk, + packet_end, pkt_end, + //{ pid_48, addr_48, endp_48, frame_num_48 }, + //{ pid, addr, endp, frame_num }, + ); + assign pid_48 = full_pid[4:1]; + + assign pid = pid_48; + assign addr = addr_48; + assign endp = endp_48; + assign frame_num = frame_num_48; + //assign addr = token_payload[7:1]; //assign endp = token_payload[11:8]; //assign frame_num = token_payload[11:1]; @@ -353,7 +371,7 @@ module usb_fs_rx ( assign rx_data_put = rx_data_buffer_full; assign rx_data = rx_data_buffer[8:1]; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin if (packet_start || rx_data_buffer_full) begin rx_data_buffer <= 9'b100000000; end diff --git a/common/usb_fs_tx.v b/common/usb_fs_tx.v index c9ba07a..a9ae0d9 100644 --- a/common/usb_fs_tx.v +++ b/common/usb_fs_tx.v @@ -2,9 +2,10 @@ module usb_fs_tx ( // A 48MHz clock is required to receive USB data at 12MHz // it's simpler to juse use 48MHz everywhere input clk_48mhz, + input clk, input reset, - // bit strobe from rx to align with senders clock + // bit strobe from rx to align with senders clock (in clk_48mhz domain) input bit_strobe, // output enable to take ownership of bus and data out @@ -12,28 +13,32 @@ module usb_fs_tx ( output reg dp = 0, output reg dn = 0, - // pulse to initiate new packet transmission + // pulse to initiate new packet transmission in clk domain input pkt_start, output pkt_end, - // pid to send + // pid to send (clk domain) input [3:0] pid, // tx logic pulls data until there is nothing available input tx_data_avail, - output reg tx_data_get = 0, + output tx_data_get, input [7:0] tx_data ); - wire clk = clk_48mhz; - + // convert pkt_start to clk_48mhz domain // save packet parameters at pkt_start - reg [3:0] pidq = 0; - - always @(posedge clk) begin - if (pkt_start) begin - pidq <= pid; - end - end + wire pkt_start_48; + wire [3:0] pidq; + strobe #(.WIDTH(4)) pkt_start_strobe( + clk, clk_48mhz, + pkt_start, pkt_start_48, + pid, pidq + ); + + // convert tx_data_get from 48 to clk + //wire tx_data_get_48 = tx_data_get; + reg tx_data_get_48; + strobe tx_data_get_strobe(clk_48mhz, clk, tx_data_get_48, tx_data_get); reg [7:0] data_shift_reg = 0; reg [7:0] oe_shift_reg = 0; @@ -58,14 +63,15 @@ module usb_fs_tx ( reg bitstuff_qqqq = 0; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin bitstuff_q <= bitstuff; bitstuff_qq <= bitstuff_q; bitstuff_qqq <= bitstuff_qq; bitstuff_qqqq <= bitstuff_qqq; end - assign pkt_end = bit_strobe && se0_shift_reg[1:0] == 2'b01; + wire pkt_end_48 = bit_strobe && se0_shift_reg[1:0] == 2'b01; + strobe pkt_end_strobe(clk_48mhz, pkt_end_48, clk, pkt_end); reg data_payload = 0; @@ -79,10 +85,10 @@ module usb_fs_tx ( reg [15:0] crc16 = 0; - always @(posedge clk) begin + always @(posedge clk_48mhz) begin case (pkt_state) IDLE : begin - if (pkt_start) begin + if (pkt_start_48) begin pkt_state <= SYNC; end end @@ -115,20 +121,20 @@ module usb_fs_tx ( if (tx_data_avail) begin pkt_state <= DATA_OR_CRC16_0; data_payload <= 1; - tx_data_get <= 1; + tx_data_get_48 <= 1; data_shift_reg <= tx_data; oe_shift_reg <= 8'b11111111; se0_shift_reg <= 8'b00000000; end else begin pkt_state <= CRC16_1; data_payload <= 0; - tx_data_get <= 0; + tx_data_get_48 <= 0; data_shift_reg <= ~{crc16[8], crc16[9], crc16[10], crc16[11], crc16[12], crc16[13], crc16[14], crc16[15]}; oe_shift_reg <= 8'b11111111; se0_shift_reg <= 8'b00000000; end end else begin - tx_data_get <= 0; + tx_data_get_48 <= 0; end end @@ -156,7 +162,7 @@ module usb_fs_tx ( byte_strobe <= 0; end - if (pkt_start) begin + if (pkt_start_48) begin bit_count <= 1; bit_history_q <= 0; @@ -184,12 +190,12 @@ module usb_fs_tx ( // calculate crc16 wire crc16_invert = serial_tx_data ^ crc16[15]; - always @(posedge clk) begin - if (pkt_start) begin + always @(posedge clk_48mhz) begin + if (pkt_start_48) begin crc16 <= 16'b1111111111111111; end - if (bit_strobe && data_payload && !bitstuff_qqqq && !pkt_start) begin + if (bit_strobe && data_payload && !bitstuff_qqqq && !pkt_start_48) begin crc16[15] <= crc16[14] ^ crc16_invert; crc16[14] <= crc16[13]; crc16[13] <= crc16[12]; @@ -213,8 +219,8 @@ module usb_fs_tx ( // nrzi and differential driving - always @(posedge clk) begin - if (pkt_start) begin + always @(posedge clk_48mhz) begin + if (pkt_start_48) begin // J dp <= 1; dn <= 0; From ea370fe93b1b084de733d8c54ec911da6cbc6566 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 18 Jan 2019 14:25:23 -0500 Subject: [PATCH 07/26] usb_fs_rx: Document clock domains --- common/usb_fs_rx.v | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/common/usb_fs_rx.v b/common/usb_fs_rx.v index 19ea976..652c367 100644 --- a/common/usb_fs_rx.v +++ b/common/usb_fs_rx.v @@ -8,26 +8,26 @@ module usb_fs_rx ( input dp, input dn, - // pulse on every bit transition in clk_48mhz + // pulse on every bit transition (clk_48mhz domain) output bit_strobe, - // Pulse on beginning of new packet in clk. + // Pulse on beginning of new packet (clk domain) output pkt_start, - // Pulse on end of current packet in clk. + // Pulse on end of current packet (clk domain) output pkt_end, - // Most recent packet decoded. + // Most recent packet decoded (clk domain) output [3:0] pid, output [6:0] addr, output [3:0] endp, output [10:0] frame_num, - // Pulse on valid data on rx_data in clk. + // Pulse on valid data on rx_data (clk domain) output rx_data_put, output [7:0] rx_data, - // Most recent packet passes PID and CRC checks + // Most recent packet passes PID and CRC checks (clk domain) output valid_packet ); wire [3:0] pid_48; @@ -312,12 +312,13 @@ module usb_fs_rx ( // TODO: need to check for data packet babble // TODO: do i need to check for bitstuff error? - assign valid_packet = pid_valid && ( + wire valid_packet_48 = pid_valid && ( (pkt_is_handshake) || (pkt_is_data && crc16_valid) || (pkt_is_token && crc5_valid) ); + strobe valid_packet_strobe(clk_48mhz, clk, valid_packet_48, valid_packet); reg [11:0] token_payload = 0; wire token_payload_done = token_payload[0]; @@ -368,8 +369,14 @@ module usb_fs_rx ( //assign rx_data_put = dvalid && pid_complete && pkt_is_data; reg [8:0] rx_data_buffer = 0; wire rx_data_buffer_full = rx_data_buffer[0]; - assign rx_data_put = rx_data_buffer_full; - assign rx_data = rx_data_buffer[8:1]; + //assign rx_data_put = rx_data_buffer_full; + //assign rx_data = rx_data_buffer[8:1]; + + strobe #(.WIDTH(8)) rx_data_put_strobe( + clk_48mhz, clk, + rx_data_buffer_full, rx_data_put, + rx_data_buffer[8:1], rx_data + ); always @(posedge clk_48mhz) begin if (packet_start || rx_data_buffer_full) begin From e44d6d25d3ee38f6aa6896bc9326bf8c6778b5b5 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 18 Jan 2019 16:51:25 -0500 Subject: [PATCH 08/26] Clock crossing success - endpoint runs at 12 Mhz --- boards/TinyFPGA_BX/Makefile | 6 ++- boards/TinyFPGA_BX/bootloader.v | 66 ++++++++++++++++++++++++++++----- boards/TinyFPGA_BX/pins.pcf | 12 +++--- common/strobe.v | 29 +++++++++++++-- common/tinyfpga_bootloader.v | 8 +++- common/usb_fs_out_pe.v | 8 +++- common/usb_fs_pe.v | 12 ++++-- common/usb_fs_rx.v | 26 ++++++++----- common/usb_fs_tx.v | 10 ++++- 9 files changed, 137 insertions(+), 40 deletions(-) diff --git a/boards/TinyFPGA_BX/Makefile b/boards/TinyFPGA_BX/Makefile index 6ea0de9..b325935 100644 --- a/boards/TinyFPGA_BX/Makefile +++ b/boards/TinyFPGA_BX/Makefile @@ -22,11 +22,15 @@ PKG = cm81 all: $(PROJ).rpt fw.bin +%.json: %.v ../../common/*.v + yosys -q -p 'synth_ice40 -top $(PROJ) -json $@' $^ %.blif: %.v ../../common/*.v - yosys -p 'synth_ice40 -top $(PROJ) -blif $@' $^ + yosys -q -p 'synth_ice40 -top $(PROJ) -blif $@' $^ %.asc: $(PIN_DEF) %.blif arachne-pnr -d 8k -P $(PKG) -o $@ -p $^ +no-%.asc: $(PIN_DEF) %.json + nextpnr-ice40 -d 8k -P $(PKG) -o $@ -p $^ %.bin: %.asc icepack $< $@ diff --git a/boards/TinyFPGA_BX/bootloader.v b/boards/TinyFPGA_BX/bootloader.v index 114aec0..6307584 100644 --- a/boards/TinyFPGA_BX/bootloader.v +++ b/boards/TinyFPGA_BX/bootloader.v @@ -16,9 +16,14 @@ module bootloader ( output pin_31_mosi, output pin_32_sck, - output pin_8 // uart + output pin_2, // debug + output pin_3, // debug + output pin_4, // debug + output pin_5, // debug + output pin_9 // uart ); - wire serial_tx = pin_8; + wire serial_tx = pin_9; + wire [3:0] debug = { pin_5, pin_4, pin_3, pin_2 }; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -60,10 +65,18 @@ module bootloader ( ); reg clk_24mhz; - reg clk_12mhz; always @(posedge clk_48mhz) clk_24mhz = !clk_24mhz; + + reg clk_12mhz; always @(posedge clk_24mhz) clk_12mhz = !clk_12mhz; - wire clk = !clk_48mhz; + + wire clk = clk_12mhz; // half speed clock + //wire clk = !clk_48mhz; // invert the clock for testing + + // generate a 3 MHz clock for the baud rate + wire clk_1; + divide_by_n #(.N(16)) div48(clk_48mhz, reset, clk_1); + //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -176,23 +189,43 @@ module bootloader ( end end `endif + reg hello_done; + reg hello_strobe; + reg [63:0] hello_msg = "\n\r!OLLEH"; + reg [3:0] hello_counter; + reg [7:0] hello_data; + always @(posedge clk) begin + hello_strobe <= 0; + + if (reset) begin + hello_counter <= 0; + hello_done <= 0; + end else + if (hello_counter == 8) + hello_done <= 1; + else + if (!hello_strobe) begin + hello_data <= hello_msg[hello_counter*8+7:hello_counter*8]; + hello_counter <= hello_counter + 1; + hello_strobe <= 1; + end + end + reg uart_strobe; reg [7:0] uart_data; wire uart_ready; - wire clk_1; - divide_by_n #(.N(16)) div48(clk_48mhz, reset, clk_1); - uart_tx_fifo uart_tx( .clk(clk), .reset(reset), .baud_x1(clk_1), - .data(uart_data), - .data_strobe(uart_strobe), + .data(hello_done ? uart_data : hello_data), + .data_strobe(hello_done ? uart_strobe : hello_strobe), .serial(serial_tx) ); + /* reg [FIFO_WIDTH-1:0] hexdata; reg [7:0] len; @@ -270,7 +303,8 @@ module bootloader ( .usb_p_rx(usb_p_rx), .usb_n_rx(usb_n_rx), .usb_tx_en(usb_tx_en), - .led(pin_led), + //.led(pin_5), + .debug(debug), .spi_miso(pin_29_miso), .spi_cs(pin_30_cs), .spi_mosi(pin_31_mosi), @@ -284,4 +318,16 @@ module bootloader ( assign usb_p_rx = usb_tx_en ? 1'b1 : pin_usbp; assign usb_n_rx = usb_tx_en ? 1'b0 : pin_usbn; + + // our own counter pattern for now + reg [5:0] pattern = 5'b10100; + reg [22:0] counter; + assign pin_led = pattern[0]; + + always @(posedge clk) begin + counter <= counter + 1; + if (counter == 0) + pattern <= { pattern[0], pattern[5:1] }; + end + endmodule diff --git a/boards/TinyFPGA_BX/pins.pcf b/boards/TinyFPGA_BX/pins.pcf index 913676c..2736b3a 100644 --- a/boards/TinyFPGA_BX/pins.pcf +++ b/boards/TinyFPGA_BX/pins.pcf @@ -3,15 +3,15 @@ # Package: CM81 ############################################################################### -#set_io pin_1 A2 -#set_io pin_2 A1 -#set_io pin_3 B1 -#set_io pin_4 C2 -#set_io pin_5 C1 +set_io -nowarn pin_1 A2 +set_io -nowarn pin_2 A1 +set_io -nowarn pin_3 B1 +set_io -nowarn pin_4 C2 +set_io -nowarn pin_5 C1 set_io -nowarn pin_6 D2 #set_io pin_7 D1 set_io -nowarn pin_8 E2 -#set_io pin_9 E1 +set_io -nowarn pin_9 E1 #set_io pin_10 G2 #set_io pin_11 H1 #set_io pin_12 J1 diff --git a/common/strobe.v b/common/strobe.v index 2ec4bbb..2791ad9 100644 --- a/common/strobe.v +++ b/common/strobe.v @@ -7,26 +7,47 @@ module strobe( output [WIDTH-1:0] data_out ); parameter WIDTH = 1; + parameter DELAY = 2; // 2 for metastability, larger for testing + `define CLOCK_CROSS `ifdef CLOCK_CROSS reg flag; - reg [2:0] sync; + reg prev_strobe; + reg [DELAY:0] sync; reg [WIDTH-1:0] data; + // flip the flag and clock in the data when strobe is high always @(posedge clk_in) begin + //if ((strobe_in && !prev_strobe) + //|| (!strobe_in && prev_strobe)) flag <= flag ^ strobe_in; + if (strobe_in) data <= data_in; + + prev_strobe <= strobe_in; end + // shift through a chain of flipflop to ensure stability always @(posedge clk_out) - sync <= { sync[1:0], flag }; + sync <= { sync[DELAY-1:0], flag }; - assign strobe_out = sync[1] ^ sync[0]; + assign strobe_out = sync[DELAY] ^ sync[DELAY-1]; assign data_out = data; - //assign data_out = data_in; `else assign strobe_out = strobe_in; assign data_out = data_in; `endif endmodule + + +module dflip( + input clk, + input in, + output out +); + reg [2:0] d; + always @(posedge clk) + d <= { d[1:0], in }; + assign out = d[2]; +endmodule diff --git a/common/tinyfpga_bootloader.v b/common/tinyfpga_bootloader.v index 155327e..033d896 100644 --- a/common/tinyfpga_bootloader.v +++ b/common/tinyfpga_bootloader.v @@ -19,6 +19,9 @@ module tinyfpga_bootloader ( // bootloader indicator light, pulses on and off when bootloader is active output led, + // debug connection for oscilloscope debugging + output [3:0] debug, + // connection to SPI flash output spi_cs, output spi_sck, @@ -80,7 +83,7 @@ module tinyfpga_bootloader ( end end always @(posedge clk) pwm_cnt <= pwm_cnt + 1'b1; - assign led = led_pwm > pwm_cnt; + //assign led = led_pwm > pwm_cnt; @@ -214,6 +217,7 @@ module tinyfpga_bootloader ( .reset(reset), .uart_strobe(uart_strobe), .uart_data(uart_data), + .debug(debug), .usb_p_tx(usb_p_tx), .usb_n_tx(usb_n_tx), @@ -266,4 +270,4 @@ module tinyfpga_bootloader ( host_presence_timeout <= 1; end end -endmodule \ No newline at end of file +endmodule diff --git a/common/usb_fs_out_pe.v b/common/usb_fs_out_pe.v index 012e66b..715fba0 100644 --- a/common/usb_fs_out_pe.v +++ b/common/usb_fs_out_pe.v @@ -356,6 +356,10 @@ module usb_fs_out_pe #( integer j; always @(posedge clk) begin uart_strobe <= 0; + if (rx_pkt_start && !uart_strobe) begin + uart_strobe <= 1; + uart_data <= "R"; + end if (reset) begin out_xfr_state <= IDLE; @@ -363,7 +367,7 @@ module usb_fs_out_pe #( out_xfr_state <= out_xfr_state_next; if (out_xfr_state != out_xfr_state_next) begin uart_strobe <= 1; - uart_data <= out_xfr_state_next + "A"; + uart_data <= out_xfr_state_next + "0"; if (out_xfr_state == RCVD_DATA_END) uart_data <= "0" + tx_pid; end @@ -418,4 +422,4 @@ module usb_fs_out_pe #( end end -endmodule \ No newline at end of file +endmodule diff --git a/common/usb_fs_pe.v b/common/usb_fs_pe.v index 924bdff..c330995 100644 --- a/common/usb_fs_pe.v +++ b/common/usb_fs_pe.v @@ -7,6 +7,7 @@ module usb_fs_pe #( input [6:0] dev_addr, output uart_strobe, output [7:0] uart_data, + output [3:0] debug, //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -70,6 +71,8 @@ module usb_fs_pe #( // in pe interface wire [7:0] arb_in_ep_data; +assign debug[3] = usb_tx_en; + // rx interface wire bit_strobe; wire rx_pkt_start; @@ -125,8 +128,8 @@ module usb_fs_pe #( .NUM_IN_EPS(NUM_IN_EPS) ) usb_fs_in_pe_inst ( .clk(clk), - //.uart_strobe(uart_strobe), - //.uart_data(uart_data), + .uart_strobe(uart_strobe), + .uart_data(uart_data), .reset(reset), .reset_ep({NUM_IN_EPS{1'b0}}), .dev_addr(dev_addr), @@ -163,8 +166,8 @@ module usb_fs_pe #( .clk(clk), .reset(reset), .reset_ep({NUM_OUT_EPS{1'b0}}), - .uart_strobe(uart_strobe), - .uart_data(uart_data), + //.uart_strobe(uart_strobe), + //.uart_data(uart_data), .dev_addr(dev_addr), // endpoint interface @@ -196,6 +199,7 @@ module usb_fs_pe #( .clk_48mhz(clk_48mhz), .clk(clk), .reset(reset), + .debug(debug), .dp(usb_p_rx), .dn(usb_n_rx), .bit_strobe(bit_strobe), diff --git a/common/usb_fs_rx.v b/common/usb_fs_rx.v index 652c367..74e0c61 100644 --- a/common/usb_fs_rx.v +++ b/common/usb_fs_rx.v @@ -3,8 +3,9 @@ module usb_fs_rx ( input clk_48mhz, input clk, input reset, + output [3:0] debug, - // USB data+ and data- lines. + // USB data+ and data- lines (clk_48mhz domain) input dp, input dn, @@ -318,7 +319,8 @@ module usb_fs_rx ( (pkt_is_token && crc5_valid) ); - strobe valid_packet_strobe(clk_48mhz, clk, valid_packet_48, valid_packet); + // valid is level, not a strobe + dflip valid_buffer(clk, valid_packet_48, valid_packet); reg [11:0] token_payload = 0; wire token_payload_done = token_payload[0]; @@ -344,20 +346,24 @@ module usb_fs_rx ( //assign pkt_start = packet_start; //assign pkt_end = packet_end; strobe pkt_start_strobe(clk_48mhz, clk, packet_start, pkt_start); + assign debug[0] = valid_packet_48; + assign debug[1] = valid_packet; + assign debug[2] = din; + //assign debug[3] = bit_strobe; // at the end of the packet, capture the parameters strobe #(.WIDTH(26)) pkt_end_strobe( clk_48mhz, clk, packet_end, pkt_end, - //{ pid_48, addr_48, endp_48, frame_num_48 }, - //{ pid, addr, endp, frame_num }, + { pid_48, addr_48, endp_48, frame_num_48 }, + { pid, addr, endp, frame_num }, ); assign pid_48 = full_pid[4:1]; - assign pid = pid_48; - assign addr = addr_48; - assign endp = endp_48; - assign frame_num = frame_num_48; + //assign pid = pid_48; + //assign addr = addr_48; + //assign endp = endp_48; + //assign frame_num = frame_num_48; //assign addr = token_payload[7:1]; //assign endp = token_payload[11:8]; @@ -372,7 +378,9 @@ module usb_fs_rx ( //assign rx_data_put = rx_data_buffer_full; //assign rx_data = rx_data_buffer[8:1]; - strobe #(.WIDTH(8)) rx_data_put_strobe( + // convert the rx_data_put to clk domain + //dflip rx_data_put_flop(clk, rx_data_buffer_full, rx_data_put); + strobe #(.WIDTH(8)) rx_data_strobe( clk_48mhz, clk, rx_data_buffer_full, rx_data_put, rx_data_buffer[8:1], rx_data diff --git a/common/usb_fs_tx.v b/common/usb_fs_tx.v index a9ae0d9..723f318 100644 --- a/common/usb_fs_tx.v +++ b/common/usb_fs_tx.v @@ -13,8 +13,10 @@ module usb_fs_tx ( output reg dp = 0, output reg dn = 0, - // pulse to initiate new packet transmission in clk domain + // pulse to initiate new packet transmission (clk domain) input pkt_start, + + // pulse to indicate end of packet transmission (clk domain) output pkt_end, // pid to send (clk domain) @@ -35,6 +37,10 @@ module usb_fs_tx ( pid, pidq ); + wire tx_data_avail_48; + dflip tx_data_avail_buffer(clk_48mhz, tx_data_avail, tx_data_avail_48); + //wire tx_data_avail_48 = tx_data_avail; + // convert tx_data_get from 48 to clk //wire tx_data_get_48 = tx_data_get; reg tx_data_get_48; @@ -118,7 +124,7 @@ module usb_fs_tx ( DATA_OR_CRC16_0 : begin if (byte_strobe) begin - if (tx_data_avail) begin + if (tx_data_avail_48) begin pkt_state <= DATA_OR_CRC16_0; data_payload <= 1; tx_data_get_48 <= 1; From 324eae5fa76006aa5381a081f7982a214001e3c3 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 18 Jan 2019 16:58:26 -0500 Subject: [PATCH 09/26] Clock crossing: cleanup uart debugging code --- boards/TinyFPGA_BX/bootloader.v | 221 +------------------------------- common/tinyfpga_bootloader.v | 12 +- common/usb_fs_in_pe.v | 8 -- common/usb_fs_out_pe.v | 14 -- common/usb_fs_pe.v | 10 -- common/usb_fs_rx.v | 18 +-- 6 files changed, 4 insertions(+), 279 deletions(-) diff --git a/boards/TinyFPGA_BX/bootloader.v b/boards/TinyFPGA_BX/bootloader.v index 6307584..61917c0 100644 --- a/boards/TinyFPGA_BX/bootloader.v +++ b/boards/TinyFPGA_BX/bootloader.v @@ -1,7 +1,3 @@ -`include "util.v" -`include "fifo.v" -`include "uart.v" - module bootloader ( input pin_clk, @@ -15,16 +11,7 @@ module bootloader ( output pin_30_cs, output pin_31_mosi, output pin_32_sck, - - output pin_2, // debug - output pin_3, // debug - output pin_4, // debug - output pin_5, // debug - output pin_9 // uart ); - wire serial_tx = pin_9; - wire [3:0] debug = { pin_5, pin_4, pin_3, pin_2 }; - //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////// @@ -71,12 +58,6 @@ module bootloader ( always @(posedge clk_24mhz) clk_12mhz = !clk_12mhz; wire clk = clk_12mhz; // half speed clock - //wire clk = !clk_48mhz; // invert the clock for testing - - // generate a 3 MHz clock for the baud rate - wire clk_1; - divide_by_n #(.N(16)) div48(clk_48mhz, reset, clk_1); - //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -107,204 +88,16 @@ module bootloader ( wire usb_n_rx; wire usb_tx_en; -`ifdef NONONO - - wire bit_strobe; - wire pkt_start; - wire pkt_start; - wire pkt_end; - wire [3:0] pid; - wire [6:0] addr; - wire [3:0] endp; - wire [10:0] frame_num; - wire rx_data_put; - wire [7:0] rx_data; - wire valid_packet; - - usb_fs_rx usb( - .clk_48mhz(clk_48mhz), - .clk(clk), - .reset(reset), - .dp(usb_p_rx), - .dn(usb_n_rx), - .bit_strobe(bit_strobe), - .pkt_start(pkt_start), - .pkt_end(pkt_end), - .pid(pid), - .addr(addr), - .endp(endp), - .frame_num(frame_num), - .rx_data_put(rx_data_put), - .rx_data(rx_data), - .valid_packet(valid_packet) - ); - - assign usb_tx_en = 0; - - parameter FIFO_WIDTH = 24; - reg [FIFO_WIDTH-1:0] fifo_write_data; - reg fifo_write_strobe; - wire [FIFO_WIDTH-1:0] fifo_read_data; - reg fifo_read_strobe; - wire fifo_data_available; - - fifo_bram #(.WIDTH(FIFO_WIDTH)) uart_fifo( - .reset(reset), - .write_clk(clk), - .write_strobe(fifo_write_strobe), - .write_data(fifo_write_data), - .read_clk(clk), - .read_strobe(fifo_read_strobe), - .read_data(fifo_read_data), - .data_available(fifo_data_available) - ); - - always @(posedge clk) - begin - fifo_write_strobe <= 0; - - if (pkt_start) begin - fifo_write_strobe <= 1; - fifo_write_data <= { - 4'hA, - 20'b0, - }; - end else - if (rx_data_put) begin - fifo_write_strobe <= 1; - fifo_write_data <= { - pkt_start ? 4'hA : 4'hB, // 4 - 12'b0, // 12 - rx_data // 8 - }; - end else - if (pkt_end) begin - fifo_write_strobe <= 1; - fifo_write_data <= { - valid_packet ? 4'hC : 4'hF, - pid, // 4 - 1'b0, addr, // 1 + 7 - frame_num[7:0] // 8 - }; - end - end -`endif - reg hello_done; - reg hello_strobe; - reg [63:0] hello_msg = "\n\r!OLLEH"; - reg [3:0] hello_counter; - reg [7:0] hello_data; - always @(posedge clk) begin - hello_strobe <= 0; - - if (reset) begin - hello_counter <= 0; - hello_done <= 0; - end else - if (hello_counter == 8) - hello_done <= 1; - else - if (!hello_strobe) begin - hello_data <= hello_msg[hello_counter*8+7:hello_counter*8]; - hello_counter <= hello_counter + 1; - hello_strobe <= 1; - end - end - - - reg uart_strobe; - reg [7:0] uart_data; - wire uart_ready; - - uart_tx_fifo uart_tx( - .clk(clk), - .reset(reset), - .baud_x1(clk_1), - .data(hello_done ? uart_data : hello_data), - .data_strobe(hello_done ? uart_strobe : hello_strobe), - .serial(serial_tx) - ); - - -/* - reg [FIFO_WIDTH-1:0] hexdata; - reg [7:0] len; - reg [12:0] counter; - - always @(posedge clk) - begin - uart_strobe <= 0; - fifo_read_strobe <= 0; - counter <= counter + 1; - pin_led <= 0; - - if (!uart_ready - || uart_strobe - || counter != 0 - ) begin - // nothing - end else - begin - uart_data <= "A"; - uart_strobe <= 1; - pin_led <= 1; - end - end -*/ -/* - always @(posedge clk) - begin - uart_strobe <= 0; - fifo_read_strobe <= 0; - counter <= counter + 1; - pin_led <= 0; - - if (len == 0 - && fifo_data_available - && !fifo_read_strobe) begin - len <= 8; - hexdata <= fifo_read_data; - fifo_read_strobe <= 1; - pin_led <= 1; - end else - if (!uart_ready - || uart_strobe - || counter != 0 - ) begin - // nothing - end else - if (len == 1) begin - uart_data <= "\n"; - uart_strobe <= 1; - len <= 0; - end else - if (len == 2) begin - uart_data <= "\r"; - uart_strobe <= 1; - len <= 1; - end else - if (len != 0) begin - uart_data <= hexdigit(hexdata[FIFO_WIDTH-1:FIFO_WIDTH-4]); - uart_strobe <= 1; - hexdata <= { hexdata[FIFO_WIDTH-5:0], 4'b0 }; - len <= len - 1; - end - end -*/ - tinyfpga_bootloader tinyfpga_bootloader_inst ( .clk_48mhz(clk_48mhz), .clk(clk), .reset(reset), - .uart_data(uart_data), - .uart_strobe(uart_strobe), .usb_p_tx(usb_p_tx), .usb_n_tx(usb_n_tx), .usb_p_rx(usb_p_rx), .usb_n_rx(usb_n_rx), .usb_tx_en(usb_tx_en), - //.led(pin_5), - .debug(debug), + .led(pin_led), .spi_miso(pin_29_miso), .spi_cs(pin_30_cs), .spi_mosi(pin_31_mosi), @@ -318,16 +111,4 @@ module bootloader ( assign usb_p_rx = usb_tx_en ? 1'b1 : pin_usbp; assign usb_n_rx = usb_tx_en ? 1'b0 : pin_usbn; - - // our own counter pattern for now - reg [5:0] pattern = 5'b10100; - reg [22:0] counter; - assign pin_led = pattern[0]; - - always @(posedge clk) begin - counter <= counter + 1; - if (counter == 0) - pattern <= { pattern[0], pattern[5:1] }; - end - endmodule diff --git a/common/tinyfpga_bootloader.v b/common/tinyfpga_bootloader.v index 033d896..7b43ee3 100644 --- a/common/tinyfpga_bootloader.v +++ b/common/tinyfpga_bootloader.v @@ -3,9 +3,6 @@ module tinyfpga_bootloader ( input clk, input reset, - output uart_strobe, - output [7:0] uart_data, - // USB lines. Split into input vs. output and oe control signal to maintain // highest level of compatibility with synthesis tools. output usb_p_tx, @@ -19,9 +16,6 @@ module tinyfpga_bootloader ( // bootloader indicator light, pulses on and off when bootloader is active output led, - // debug connection for oscilloscope debugging - output [3:0] debug, - // connection to SPI flash output spi_cs, output spi_sck, @@ -83,8 +77,7 @@ module tinyfpga_bootloader ( end end always @(posedge clk) pwm_cnt <= pwm_cnt + 1'b1; - //assign led = led_pwm > pwm_cnt; - + assign led = led_pwm > pwm_cnt; //////////////////////////////////////////////////////////////////////////////// @@ -215,9 +208,6 @@ module tinyfpga_bootloader ( .clk_48mhz(clk_48mhz), .clk(clk), .reset(reset), - .uart_strobe(uart_strobe), - .uart_data(uart_data), - .debug(debug), .usb_p_tx(usb_p_tx), .usb_n_tx(usb_n_tx), diff --git a/common/usb_fs_in_pe.v b/common/usb_fs_in_pe.v index 99b3b6c..4ce36a7 100644 --- a/common/usb_fs_in_pe.v +++ b/common/usb_fs_in_pe.v @@ -5,8 +5,6 @@ module usb_fs_in_pe #( ) ( input clk, input reset, - output uart_strobe, - output [7:0] uart_data, input [NUM_IN_EPS-1:0] reset_ep, input [6:0] dev_addr, @@ -355,17 +353,11 @@ module usb_fs_in_pe #( integer j; always @(posedge clk) begin - uart_strobe <= 0; - if (reset) begin in_xfr_state <= IDLE; end else begin in_xfr_state <= in_xfr_state_next; - if (in_xfr_state != in_xfr_state_next) begin - uart_strobe <= 1; - uart_data <= in_xfr_state_next + "A"; - end if (setup_token_received) begin data_toggle[rx_endp] <= 1; diff --git a/common/usb_fs_out_pe.v b/common/usb_fs_out_pe.v index 715fba0..dba7112 100644 --- a/common/usb_fs_out_pe.v +++ b/common/usb_fs_out_pe.v @@ -5,8 +5,6 @@ module usb_fs_out_pe #( ) ( input clk, input reset, - output uart_strobe, - output [7:0] uart_data, input [NUM_OUT_EPS-1:0] reset_ep, input [6:0] dev_addr, @@ -355,22 +353,10 @@ module usb_fs_out_pe #( integer j; always @(posedge clk) begin - uart_strobe <= 0; - if (rx_pkt_start && !uart_strobe) begin - uart_strobe <= 1; - uart_data <= "R"; - end - if (reset) begin out_xfr_state <= IDLE; end else begin out_xfr_state <= out_xfr_state_next; - if (out_xfr_state != out_xfr_state_next) begin - uart_strobe <= 1; - uart_data <= out_xfr_state_next + "0"; - if (out_xfr_state == RCVD_DATA_END) - uart_data <= "0" + tx_pid; - end if (out_xfr_start) begin current_endp <= rx_endp; diff --git a/common/usb_fs_pe.v b/common/usb_fs_pe.v index c330995..dee04c6 100644 --- a/common/usb_fs_pe.v +++ b/common/usb_fs_pe.v @@ -5,9 +5,6 @@ module usb_fs_pe #( input clk_48mhz, input clk, input [6:0] dev_addr, - output uart_strobe, - output [7:0] uart_data, - output [3:0] debug, //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -71,8 +68,6 @@ module usb_fs_pe #( // in pe interface wire [7:0] arb_in_ep_data; -assign debug[3] = usb_tx_en; - // rx interface wire bit_strobe; wire rx_pkt_start; @@ -128,8 +123,6 @@ assign debug[3] = usb_tx_en; .NUM_IN_EPS(NUM_IN_EPS) ) usb_fs_in_pe_inst ( .clk(clk), - .uart_strobe(uart_strobe), - .uart_data(uart_data), .reset(reset), .reset_ep({NUM_IN_EPS{1'b0}}), .dev_addr(dev_addr), @@ -166,8 +159,6 @@ assign debug[3] = usb_tx_en; .clk(clk), .reset(reset), .reset_ep({NUM_OUT_EPS{1'b0}}), - //.uart_strobe(uart_strobe), - //.uart_data(uart_data), .dev_addr(dev_addr), // endpoint interface @@ -199,7 +190,6 @@ assign debug[3] = usb_tx_en; .clk_48mhz(clk_48mhz), .clk(clk), .reset(reset), - .debug(debug), .dp(usb_p_rx), .dn(usb_n_rx), .bit_strobe(bit_strobe), diff --git a/common/usb_fs_rx.v b/common/usb_fs_rx.v index 74e0c61..fed9906 100644 --- a/common/usb_fs_rx.v +++ b/common/usb_fs_rx.v @@ -3,7 +3,6 @@ module usb_fs_rx ( input clk_48mhz, input clk, input reset, - output [3:0] debug, // USB data+ and data- lines (clk_48mhz domain) input dp, @@ -343,15 +342,10 @@ module usb_fs_rx ( end end - //assign pkt_start = packet_start; - //assign pkt_end = packet_end; + // cross the packet start signal to the endpoint clk domain strobe pkt_start_strobe(clk_48mhz, clk, packet_start, pkt_start); - assign debug[0] = valid_packet_48; - assign debug[1] = valid_packet; - assign debug[2] = din; - //assign debug[3] = bit_strobe; - // at the end of the packet, capture the parameters + // at the end of the packet, capture the parameters to the clk domain strobe #(.WIDTH(26)) pkt_end_strobe( clk_48mhz, clk, packet_end, pkt_end, @@ -360,11 +354,6 @@ module usb_fs_rx ( ); assign pid_48 = full_pid[4:1]; - //assign pid = pid_48; - //assign addr = addr_48; - //assign endp = endp_48; - //assign frame_num = frame_num_48; - //assign addr = token_payload[7:1]; //assign endp = token_payload[11:8]; //assign frame_num = token_payload[11:1]; @@ -375,11 +364,8 @@ module usb_fs_rx ( //assign rx_data_put = dvalid && pid_complete && pkt_is_data; reg [8:0] rx_data_buffer = 0; wire rx_data_buffer_full = rx_data_buffer[0]; - //assign rx_data_put = rx_data_buffer_full; - //assign rx_data = rx_data_buffer[8:1]; // convert the rx_data_put to clk domain - //dflip rx_data_put_flop(clk, rx_data_buffer_full, rx_data_put); strobe #(.WIDTH(8)) rx_data_strobe( clk_48mhz, clk, rx_data_buffer_full, rx_data_put, From 8a6bc3aca69f5f41a05010f763706823195df5f0 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 18 Jan 2019 16:59:38 -0500 Subject: [PATCH 10/26] Clock crossing: cleanup uart debugging code and helpers --- boards/TinyFPGA_BX/fifo.v | 391 -------------------------------------- boards/TinyFPGA_BX/uart.v | 305 ----------------------------- boards/TinyFPGA_BX/util.v | 220 --------------------- 3 files changed, 916 deletions(-) delete mode 100644 boards/TinyFPGA_BX/fifo.v delete mode 100644 boards/TinyFPGA_BX/uart.v delete mode 100644 boards/TinyFPGA_BX/util.v diff --git a/boards/TinyFPGA_BX/fifo.v b/boards/TinyFPGA_BX/fifo.v deleted file mode 100644 index 304ad9a..0000000 --- a/boards/TinyFPGA_BX/fifo.v +++ /dev/null @@ -1,391 +0,0 @@ - -/** 256 Kb SPRAM, organized 16 K x 16 bits */ -module spram( - input clk, - input reset = 0, - input cs = 1, - input [DEPTH-1:0] addr, - input write_strobe, - input [15:0] write_data, - output [15:0] read_data -); - parameter DEPTH = 16; - - wire [15:0] read_data_0; - wire [15:0] read_data_1; - wire [15:0] read_data_2; - wire [15:0] read_data_3; - - wire cs0, cs1, cs2, cs3; -/* - generate if (DEPTH == 14) - assign cs0 = cs; - assign cs1 = 0; - assign cs2 = 0; - assign cs3 = 0; - endgenerate - generate if (DEPTH == 15) - assign cs0 = cs & addr[14] == 1'b0; - assign cs1 = cs & addr[14] == 1'b1; - assign cs2 = 0; - assign cs3 = 0; - endgenerate -*/ - generate if (DEPTH == 16) - assign cs0 = cs && addr[15:14] == 2'b00; - assign cs1 = cs && addr[15:14] == 2'b01; - assign cs2 = cs && addr[15:14] == 2'b10; - assign cs3 = cs && addr[15:14] == 2'b11; - endgenerate - - assign read_data = - cs0 ? read_data_0 : - cs1 ? read_data_1 : - cs2 ? read_data_2 : - read_data_3; - - SB_SPRAM256KA spram0( - .DATAOUT(read_data_0), - .ADDRESS(addr[13:0]), - .DATAIN(write_data), - .MASKWREN(4'b1111), - .WREN(write_strobe), - .CHIPSELECT(cs0 && !reset), - .CLOCK(clk), - - // if we cared about power, maybe we would adjust these - .STANDBY(1'b0), - .SLEEP(1'b0), - .POWEROFF(1'b1) - ); - - generate if (DEPTH > 14) - SB_SPRAM256KA spram1( - .DATAOUT(read_data_1), - .ADDRESS(addr[13:0]), - .DATAIN(write_data), - .MASKWREN(4'b1111), - .WREN(write_strobe), - .CHIPSELECT(cs1 && !reset), - .CLOCK(clk), - - // if we cared about power, maybe we would adjust these - .STANDBY(1'b0), - .SLEEP(1'b0), - .POWEROFF(1'b1) - ); - endgenerate - - generate if (DEPTH > 15) - - SB_SPRAM256KA spram2( - .DATAOUT(read_data_2), - .ADDRESS(addr[13:0]), - .DATAIN(write_data), - .MASKWREN(4'b1111), - .WREN(write_strobe), - .CHIPSELECT(cs2 && !reset), - .CLOCK(clk), - - // if we cared about power, maybe we would adjust these - .STANDBY(1'b0), - .SLEEP(1'b0), - .POWEROFF(1'b1) - ); - - SB_SPRAM256KA spram3( - .DATAOUT(read_data_3), - .ADDRESS(addr[13:0]), - .DATAIN(write_data), - .MASKWREN(4'b1111), - .WREN(write_strobe), - .CHIPSELECT(cs3 && !reset), - .CLOCK(clk), - - // if we cared about power, maybe we would adjust these - .STANDBY(1'b0), - .SLEEP(1'b0), - .POWEROFF(1'b1) - ); - endgenerate -endmodule - - -module fifo_spram( - input clk, - input reset, - input [WIDTH-1:0] write_data, - input write_strobe, - output [WIDTH-1:0] read_data, - input read_strobe, - output data_available -); - parameter WIDTH = 16; - parameter DEPTH = 16; // 14 == one SPRAM deep, 15 == two deep, 16 == four - reg [DEPTH-1:0] write_ptr = 0; - reg [DEPTH-1:0] read_ptr = 0; - assign data_available = read_ptr != write_ptr; - - spram #( - .DEPTH(DEPTH) - ) buf0( - .clk(clk), - .reset(reset), - .write_strobe(write_strobe), - .addr(write_strobe ? write_ptr : read_ptr), - .write_data(write_data[15:0]), - .read_data(read_data[15:0]), - ); - - generate if (WIDTH > 16) - spram #( - .DEPTH(DEPTH) - ) buf1( - .clk(clk), - .reset(reset), - .write_strobe(write_strobe), - .addr(write_strobe ? write_ptr : read_ptr), - .write_data(write_data[31:16]), - .read_data(read_data[31:16]), - ); - endgenerate - - generate if (WIDTH > 32) - spram #( - .DEPTH(DEPTH) - ) buf2( - .clk(clk), - .reset(reset), - .write_strobe(write_strobe), - .addr(write_strobe ? write_ptr : read_ptr), - .write_data(write_data[47:32]), - .read_data(read_data[47:32]), - ); - endgenerate - - generate if (WIDTH > 48) - spram #( - .DEPTH(DEPTH) - ) buf3( - .clk(clk), - .reset(reset), - .write_strobe(write_strobe), - .addr(write_strobe ? write_ptr : read_ptr), - .write_data(write_data[63:48]), - .read_data(read_data[63:48]), - ); - endgenerate - - always @(posedge clk) - begin - if (write_strobe) - write_ptr <= write_ptr + 1; - - if (read_strobe) - read_ptr <= read_ptr + 1; - end -endmodule - - - -module fifo_bram( - input reset, - input write_clk, - input write_strobe, - input [WIDTH-1:0] write_data, - input read_clk, - input read_strobe, - output [WIDTH-1:0] read_data, - output data_available -); - parameter WIDTH = 16; // one block RAM wide - parameter DEPTH = 8; // one block RAM deep - reg [DEPTH-1:0] read_ptr; - reg [DEPTH-1:0] write_ptr; - - reg [WIDTH-1:0] fifo[(1 << DEPTH)-1:0]; - - assign read_data = fifo[read_ptr]; - - reg data_available_0; - reg data_available_1; - //reg data_available; - assign data_available = read_ptr != write_ptr; - - always @(posedge read_clk) - begin - if (reset) - read_ptr <= 0; - else - if (read_strobe) - read_ptr <= read_ptr + 1; - - //data_available <= read_ptr != write_ptr; - //data_available <= data_available_0; - //data_available <= data_available_1; - end - - always @(posedge write_clk) - begin - if (reset) - write_ptr <= 0; - else - if (write_strobe) begin - fifo[write_ptr] <= write_data; - write_ptr <= write_ptr + 1; - end - end -endmodule - - -module fifo_combo( - input reset, - input write_clk, - input write_strobe, - input [WIDTH-1:0] write_data, - input read_clk, - input read_strobe, - output [WIDTH-1:0] read_data, - output data_available -); - parameter WIDTH = 16; - -`define NO_SPRAM -`ifdef NO_SPRAM - parameter DEPTH = 12; - // just wire it up - fifo_bram #( - .WIDTH(WIDTH), - .DEPTH(DEPTH) - ) fifo0( - .reset(reset), - .write_clk(write_clk), - .write_strobe(write_strobe), - .write_data(write_data), - .read_clk(read_clk), - .read_strobe(read_strobe), - .read_data(read_data), - .data_available(data_available) - ); -`else - parameter DEPTH = 16; - wire [WIDTH-1:0] fifo0_read_data; - reg fifo0_read_strobe; - wire fifo0_data_available; - reg fifo1_write_strobe; - - fifo_bram #( - .WIDTH(WIDTH), - ) fifo0( - .reset(reset), - .write_clk(write_clk), - .write_strobe(write_strobe), - .write_data(write_data), - .read_clk(read_clk), - .read_strobe(fifo0_read_strobe), - .read_data(fifo0_read_data), - .data_available(fifo0_data_available) - ); - - fifo_spram #( - .WIDTH(WIDTH), - .DEPTH(DEPTH) - ) fifo1( - .reset(reset), - .clk(read_clk), - //.write_data(32'hA55AB00F), - .write_data(fifo0_read_data), - .write_strobe(fifo1_write_strobe), - .read_data(read_data), - .read_strobe(read_strobe), - .data_available(data_available) - ); - - reg [3:0] counter; - - always @(posedge read_clk) begin - fifo0_read_strobe <= 0; - fifo1_write_strobe <= 0; - counter <= counter + 1; - - if (reset) begin - // nothing - end else - if (fifo0_data_available - && !fifo0_read_strobe - && !fifo1_write_strobe - && !read_strobe // don't move if the user is also moving - && counter == 0 - ) begin - // move data from fifo0 into fifo1 - fifo0_read_strobe <= 1; - fifo1_write_strobe <= 1; - end - end -`endif -endmodule - -module fifo_bram_16to8( - input read_clk, - input write_clk, - input reset, - output data_available, - input [16-1:0] write_data, - input write_strobe, - output [8-1:0] read_data, - input read_strobe -); - - reg [BITS-1:0] write_ptr; - reg [BITS-1:0] read_ptr; - - // reads from the SPRAM are 16-bits at a time, - // so we have to pick which byte of the word should be extracted -`undef BUFFER -`ifdef BUFFER - parameter BITS = 13; - reg [15:0] buffer[(1 << BITS)-1:0]; - wire [15:0] rdata_16 = buffer[read_ptr[BITS-1:1]]; -`else - parameter BITS = 8; - wire [15:0] rdata_16; -SB_RAM40_4K #(.READ_MODE(0), .WRITE_MODE(0)) ram256x16_inst ( -.RDATA(rdata_16[15:0]), -.RADDR({ 4'b0, read_ptr[BITS-1:1] }), -.RCLK(read_clk), -.RCLKE(!reset), -.RE(1), -.WADDR({ 4'b0, write_ptr[BITS-1:1] }), -.WCLK(write_clk), -.WCLKE(!reset), -.WDATA(write_data[15:0]), -.WE(write_strobe), -.MASK(16'h0) -); -`endif - assign data_available = read_ptr != write_ptr; - assign read_data = (!read_ptr[0]) ? rdata_16[15:8] : rdata_16[7:0]; - - always @(posedge read_clk) - begin - if (reset) begin - read_ptr <= 0; - end else - if (read_strobe) begin - read_ptr <= read_ptr + 1; - end - end - - always @(posedge write_clk) - begin - if (reset) begin - write_ptr <= 0; - end else - if (write_strobe) begin -`ifdef BUFFER - buffer[write_ptr[BITS-1:1]] <= write_data; -`endif - write_ptr <= write_ptr + 2; - end - end -endmodule diff --git a/boards/TinyFPGA_BX/uart.v b/boards/TinyFPGA_BX/uart.v deleted file mode 100644 index 39f1e12..0000000 --- a/boards/TinyFPGA_BX/uart.v +++ /dev/null @@ -1,305 +0,0 @@ - /* - * uart.v - High-speed serial support. Includes a baud generator, UART, - * and a simple RFC1662-inspired packet framing protocol. - * - * This module is designed a 3 Mbaud serial port. - * This is the highest data rate supported by - * the popular FT232 USB-to-serial chip. - * - * Copyright (C) 2009 Micah Dowty - * (C) 2018 Trammell Hudson - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - - -/* - * Byte transmitter, RS-232 8-N-1 - * - * Transmits on 'serial'. When 'ready' goes high, we can accept another byte. - * It should be supplied on 'data' with a pulse on 'data_strobe'. - */ - -module uart_tx( - input clk, - input reset, - input baud_x1, - output serial, - output reg ready, - input [7:0] data, - input data_strobe -); - - /* - * Left-to-right shift register. - * Loaded with data, start bit, and stop bit. - * - * The stop bit doubles as a flag to tell us whether data has been - * loaded; we initialize the whole shift register to zero on reset, - * and when the register goes zero again, it's ready for more data. - */ - reg [7+1+1:0] shiftreg; - - /* - * Serial output register. This is like an extension of the - * shift register, but we never load it separately. This gives - * us one bit period of latency to prepare the next byte. - * - * This register is inverted, so we can give it a reset value - * of zero and still keep the 'serial' output high when idle. - */ - reg serial_r; - assign serial = !serial_r; - - //assign ready = (shiftreg == 0); - - /* - * State machine - */ - - always @(posedge clk) - if (reset) begin - shiftreg <= 0; - serial_r <= 0; - end - else if (data_strobe) begin - shiftreg <= { - 1'b1, // stop bit - data, - 1'b0 // start bit (inverted) - }; - ready <= 0; - end - else if (baud_x1) begin - if (shiftreg == 0) - begin - /* Idle state is idle high, serial_r is inverted */ - serial_r <= 0; - ready <= 1; - end else - serial_r <= !shiftreg[0]; - // shift the output register down - shiftreg <= {1'b0, shiftreg[7+1+1:1]}; - end else - ready <= (shiftreg == 0); - -endmodule - - -/* - * Byte receiver, RS-232 8-N-1 - * - * Receives on 'serial'. When a properly framed byte is - * received, 'data_strobe' pulses while the byte is on 'data'. - * - * Error bytes are ignored. - */ - -module uart_rx(clk, reset, baud_x4, - serial, data, data_strobe); - - input clk, reset, baud_x4, serial; - output [7:0] data; - output data_strobe; - - /* - * Synchronize the serial input to this clock domain - */ - wire serial_sync; - d_flipflop_pair input_dff(clk, reset, serial, serial_sync); - - /* - * State machine: Four clocks per bit, 10 total bits. - */ - reg [8:0] shiftreg; - reg [5:0] state; - reg data_strobe; - wire [3:0] bit_count = state[5:2]; - wire [1:0] bit_phase = state[1:0]; - - wire sampling_phase = (bit_phase == 1); - wire start_bit = (bit_count == 0 && sampling_phase); - wire stop_bit = (bit_count == 9 && sampling_phase); - - wire waiting_for_start = (state == 0 && serial_sync == 1); - - wire error = ( (start_bit && serial_sync == 1) || - (stop_bit && serial_sync == 0) ); - - assign data = shiftreg[7:0]; - - always @(posedge clk or posedge reset) - if (reset) begin - state <= 0; - data_strobe <= 0; - end - else if (baud_x4) begin - - if (waiting_for_start || error || stop_bit) - state <= 0; - else - state <= state + 1; - - if (bit_phase == 1) - shiftreg <= { serial_sync, shiftreg[8:1] }; - - data_strobe <= stop_bit && !error; - - end - else begin - data_strobe <= 0; - end - -endmodule - - -/* - * Output UART with a SPRAM RAM FIFO queue. - * - * Add bytes to the queue and they will be printed when the line is idle. - */ -module uart_tx_fifo( - input clk, - input reset, - input baud_x1, - input [7:0] data, - input data_strobe, - output serial -); - parameter NUM = 32; - - wire uart_txd_ready; // high the UART is ready to take a new byte - reg uart_txd_strobe; // pulse when we have a new byte to transmit - reg [7:0] uart_txd; - - uart_tx txd( - .clk(clk), - .reset(reset), - .baud_x1(baud_x1), - .serial(serial), - .ready(uart_txd_ready), - .data(uart_txd), - .data_strobe(uart_txd_strobe) - ); - - wire fifo_available; - wire fifo_read_strobe; - wire [7:0] fifo_read_data; - - fifo_bram #(.WIDTH(8)) buffer( - .read_clk(clk), - .write_clk(clk), - .reset(reset), - .write_data(data), - .write_strobe(data_strobe), - .data_available(fifo_available), - .read_data(fifo_read_data), - .read_strobe(fifo_read_strobe) - ); - - // drain the fifo into the serial port - reg [3:0] counter; - always @(posedge clk) - begin - uart_txd_strobe <= 0; - fifo_read_strobe <= 0; - counter <= counter + 1; - - if (fifo_available - && uart_txd_ready - && !data_strobe // only single port port RAM - && !uart_txd_strobe // don't TX twice on one byte - && counter == 0 - ) begin - fifo_read_strobe <= 1; - uart_txd_strobe <= 1; - uart_txd <= fifo_read_data; - end - end -endmodule - - -module uart_tx_hexdump( - input clk, - input reset = 0, - input strobe, - input [31:0] data, - input [3:0] len, - input space, - input newline, - output ready, - input uart_txd_ready, - output uart_txd_strobe, - output [7:0] uart_txd -); - reg [3:0] digits; - reg [31:0] bytes; - reg [7:0] uart_txd; - reg in_progress = 0; - reg [8:0] counter; - - assign ready = !in_progress; - - always @(posedge clk) - begin - uart_txd_strobe <= 0; - - if (reset) begin - // nothing to do - in_progress <= 0; - end else - if (strobe) begin - digits <= len; - bytes <= data; - in_progress <= 1; - end else - if (uart_txd_strobe - || !uart_txd_ready - || !in_progress - || counter != 0 - ) begin - // nothing to do until uart is ready - // or we're in progress with an output - counter <= counter + 1; - end else - if (digits != 0) - begin - // time to generate a hex value! - uart_txd_strobe <= 1; - uart_txd <= hexdigit(bytes[31:28]); - - bytes <= { bytes[27:0], 4'b0 }; - digits <= digits - 1; - end else - begin - // after all the digits, output any whitespace - if (space) begin - uart_txd_strobe <= 1; - uart_txd <= " "; - end else - if (newline) begin - uart_txd_strobe <= 1; - uart_txd <= "\n"; - end - - in_progress <= 0; - counter <= 0; - end - end -endmodule diff --git a/boards/TinyFPGA_BX/util.v b/boards/TinyFPGA_BX/util.v deleted file mode 100644 index ec69fc7..0000000 --- a/boards/TinyFPGA_BX/util.v +++ /dev/null @@ -1,220 +0,0 @@ -/** \file - * Utility modules. - */ - -`define CLOG2(x) \ - x <= 2 ? 1 : \ - x <= 4 ? 2 : \ - x <= 8 ? 3 : \ - x <= 16 ? 4 : \ - x <= 32 ? 5 : \ - x <= 64 ? 6 : \ - x <= 128 ? 7 : \ - x <= 256 ? 8 : \ - x <= 512 ? 9 : \ - x <= 1024 ? 10 : \ - x <= 2048 ? 11 : \ - x <= 4096 ? 12 : \ - x <= 8192 ? 13 : \ - x <= 16384 ? 14 : \ - x <= 32768 ? 15 : \ - x <= 65536 ? 16 : \ - -1 - -function [7:0] hexdigit; - input [3:0] x; - begin - hexdigit = - x == 0 ? "0" : - x == 1 ? "1" : - x == 2 ? "2" : - x == 3 ? "3" : - x == 4 ? "4" : - x == 5 ? "5" : - x == 6 ? "6" : - x == 7 ? "7" : - x == 8 ? "8" : - x == 9 ? "9" : - x == 10 ? "a" : - x == 11 ? "b" : - x == 12 ? "c" : - x == 13 ? "d" : - x == 14 ? "e" : - x == 15 ? "f" : - "?"; - end -endfunction - -module divide_by_n( - input clk, - input reset, - output reg out -); - parameter N = 2; - - reg [`CLOG2(N)-1:0] counter; - - always @(posedge clk) - begin - out <= 0; - - if (reset) - counter <= 0; - else - if (counter == 0) - begin - out <= 1; - counter <= N - 1; - end else - counter <= counter - 1; - end -endmodule - - -module fifo( - input clk, - input reset, - output data_available, - input [WIDTH-1:0] write_data, - input write_strobe, - output [WIDTH-1:0] read_data, - input read_strobe -); - parameter WIDTH = 8; - parameter NUM = 256; - - reg [WIDTH-1:0] buffer[0:NUM-1]; - reg [`CLOG2(NUM)-1:0] write_ptr; - reg [`CLOG2(NUM)-1:0] read_ptr; - - assign read_data = buffer[read_ptr]; - assign data_available = read_ptr != write_ptr; - - always @(posedge clk) begin - if (reset) begin - write_ptr <= 0; - read_ptr <= 0; - end else begin - if (write_strobe) begin - buffer[write_ptr] <= write_data; - write_ptr <= write_ptr + 1; - end - if (read_strobe) begin - read_ptr <= read_ptr + 1; - end - end - end -endmodule - - -module pwm( - input clk, - input [BITS-1:0] bright, - output out -); - parameter BITS = 8; - - reg [BITS-1:0] counter; - always @(posedge clk) - begin - counter <= counter + 1; - out <= counter < bright; - end - -endmodule - - -/************************************************************************ - * - * Random utility modules. - * - * Micah Dowty - * - ************************************************************************/ - - -module d_flipflop(clk, reset, d_in, d_out); - input clk, reset, d_in; - output d_out; - - reg d_out; - - always @(posedge clk or posedge reset) - if (reset) begin - d_out <= 0; - end - else begin - d_out <= d_in; - end -endmodule - - -module d_flipflop_pair(clk, reset, d_in, d_out); - input clk, reset, d_in; - output d_out; - wire intermediate; - - d_flipflop dff1(clk, reset, d_in, intermediate); - d_flipflop dff2(clk, reset, intermediate, d_out); -endmodule - - -/* - * A set/reset flipflop which is set on sync_set and reset by sync_reset. - */ -module set_reset_flipflop(clk, reset, sync_set, sync_reset, out); - input clk, reset, sync_set, sync_reset; - output out; - reg out; - - always @(posedge clk or posedge reset) - if (reset) - out <= 0; - else if (sync_set) - out <= 1; - else if (sync_reset) - out <= 0; -endmodule - - -/* - * Pulse stretcher. - * - * When the input goes high, the output goes high - * for as long as the input is high, or as long as - * it takes our timer to roll over- whichever is - * longer. - */ -module pulse_stretcher(clk, reset, in, out); - parameter BITS = 20; - - input clk, reset, in; - output out; - reg out; - - reg [BITS-1:0] counter; - - always @(posedge clk or posedge reset) - if (reset) begin - out <= 0; - counter <= 0; - end - else if (counter == 0) begin - out <= in; - counter <= in ? 1 : 0; - end - else if (&counter) begin - if (in) begin - out <= 1; - end - else begin - out <= 0; - counter <= 0; - end - end - else begin - out <= 1; - counter <= counter + 1; - end -endmodule - From 28a72be0a36fb09b6dd8106fc60fa16f000648d5 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 18 Jan 2019 17:08:30 -0500 Subject: [PATCH 11/26] TinyFPGA_BX: enable all the pins, with -nowarn --- boards/TinyFPGA_BX/pins.pcf | 68 ++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/boards/TinyFPGA_BX/pins.pcf b/boards/TinyFPGA_BX/pins.pcf index 2736b3a..6fa7e18 100644 --- a/boards/TinyFPGA_BX/pins.pcf +++ b/boards/TinyFPGA_BX/pins.pcf @@ -9,40 +9,40 @@ set_io -nowarn pin_3 B1 set_io -nowarn pin_4 C2 set_io -nowarn pin_5 C1 set_io -nowarn pin_6 D2 -#set_io pin_7 D1 +set_io -nowarn pin_7 D1 set_io -nowarn pin_8 E2 set_io -nowarn pin_9 E1 -#set_io pin_10 G2 -#set_io pin_11 H1 -#set_io pin_12 J1 -#set_io pin_13 H2 -#set_io pin_14 H9 -#set_io pin_15 D9 -#set_io pin_16 D8 -#set_io pin_17 C9 -#set_io pin_18 A9 -#set_io pin_19 B8 -#set_io pin_20 A8 -#set_io pin_21 B7 -#set_io pin_22 A7 -#set_io pin_23 B6 -#set_io pin_24 A6 -#set_io pin_25 G1 -#set_io pin_26 J3 -#set_io pin_27 J4 -#set_io pin_28 H4 -set_io pin_29_miso H7 -set_io pin_30_cs F7 -set_io pin_31_mosi G6 -set_io pin_32_sck G7 -#set_io pin_33 J8 -#set_io pin_34 G9 -#set_io pin_35 J9 -#set_io pin_36 E8 -#set_io pin_37 J2 -set_io pin_led B3 -set_io pin_usbp B4 -set_io pin_usbn A4 -set_io pin_pu A3 -set_io pin_clk B2 +set_io -nowarn pin_10 G2 +set_io -nowarn pin_11 H1 +set_io -nowarn pin_12 J1 +set_io -nowarn pin_13 H2 +set_io -nowarn pin_14 H9 +set_io -nowarn pin_15 D9 +set_io -nowarn pin_16 D8 +set_io -nowarn pin_17 C9 +set_io -nowarn pin_18 A9 +set_io -nowarn pin_19 B8 +set_io -nowarn pin_20 A8 +set_io -nowarn pin_21 B7 +set_io -nowarn pin_22 A7 +set_io -nowarn pin_23 B6 +set_io -nowarn pin_24 A6 +set_io -nowarn pin_25 G1 +set_io -nowarn pin_26 J3 +set_io -nowarn pin_27 J4 +set_io -nowarn pin_28 H4 +set_io -nowarn pin_29_miso H7 +set_io -nowarn pin_30_cs F7 +set_io -nowarn pin_31_mosi G6 +set_io -nowarn pin_32_sck G7 +set_io -nowarn pin_33 J8 +set_io -nowarn pin_34 G9 +set_io -nowarn pin_35 J9 +set_io -nowarn pin_36 E8 +set_io -nowarn pin_37 J2 +set_io -nowarn pin_led B3 +set_io -nowarn pin_usbp B4 +set_io -nowarn pin_usbn A4 +set_io -nowarn pin_pu A3 +set_io -nowarn pin_clk B2 From 84959e7287d2f04c2f7bf3dcf15abb2750b24101 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 18 Jan 2019 17:08:56 -0500 Subject: [PATCH 12/26] TinyFPGA_BX: use nextpnr-ice40 --- boards/TinyFPGA_BX/Makefile | 12 ++++++--- boards/TinyFPGA_BX/bootloader.v | 45 +++++++++++++++++++++++++++------ 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/boards/TinyFPGA_BX/Makefile b/boards/TinyFPGA_BX/Makefile index b325935..eb006a1 100644 --- a/boards/TinyFPGA_BX/Makefile +++ b/boards/TinyFPGA_BX/Makefile @@ -27,10 +27,16 @@ all: $(PROJ).rpt fw.bin %.blif: %.v ../../common/*.v yosys -q -p 'synth_ice40 -top $(PROJ) -blif $@' $^ -%.asc: $(PIN_DEF) %.blif +NO-%.asc: $(PIN_DEF) %.blif arachne-pnr -d 8k -P $(PKG) -o $@ -p $^ -no-%.asc: $(PIN_DEF) %.json - nextpnr-ice40 -d 8k -P $(PKG) -o $@ -p $^ + +%.asc: $(PIN_DEF) %.json + nextpnr-ice40 \ + --$(DEVICE) \ + --package $(PKG) \ + --asc $@ \ + --pcf $(PIN_DEF) \ + --json $(basename $@).json \ %.bin: %.asc icepack $< $@ diff --git a/boards/TinyFPGA_BX/bootloader.v b/boards/TinyFPGA_BX/bootloader.v index 61917c0..471cbe3 100644 --- a/boards/TinyFPGA_BX/bootloader.v +++ b/boards/TinyFPGA_BX/bootloader.v @@ -10,7 +10,7 @@ module bootloader ( input pin_29_miso, output pin_30_cs, output pin_31_mosi, - output pin_32_sck, + output pin_32_sck ); //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -52,12 +52,11 @@ module bootloader ( ); reg clk_24mhz; - always @(posedge clk_48mhz) clk_24mhz = !clk_24mhz; - reg clk_12mhz; + always @(posedge clk_48mhz) clk_24mhz = !clk_24mhz; always @(posedge clk_24mhz) clk_12mhz = !clk_12mhz; - wire clk = clk_12mhz; // half speed clock + wire clk = clk_12mhz; // quarter speed clock //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// @@ -106,9 +105,39 @@ module bootloader ( ); assign pin_pu = 1'b1; - assign pin_usbp = usb_tx_en ? usb_p_tx : 1'bz; - assign pin_usbn = usb_tx_en ? usb_n_tx : 1'bz; - assign usb_p_rx = usb_tx_en ? 1'b1 : pin_usbp; - assign usb_n_rx = usb_tx_en ? 1'b0 : pin_usbn; + wire usb_p_rx_io; + wire usb_n_rx_io; + assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_rx_io; + assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_rx_io; + + tristate usbn_buffer( + .pin(pin_usbn), + .enable(usb_tx_en), + .data_in(usb_n_rx_io), + .data_out(usb_n_tx) + ); + + tristate usbp_buffer( + .pin(pin_usbp), + .enable(usb_tx_en), + .data_in(usb_p_rx_io), + .data_out(usb_p_tx) + ); +endmodule + +module tristate( + inout pin, + input enable, + input data_out, + output data_in +); + SB_IO #( + .PIN_TYPE(6'b1010_01) // tristatable output + ) buffer( + .PACKAGE_PIN(pin), + .OUTPUT_ENABLE(enable), + .D_IN_0(data_in), + .D_OUT_0(data_out) + ); endmodule From 70c1234ad052e092b2d022370a80035a36300095 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 18 Jan 2019 22:57:07 -0500 Subject: [PATCH 13/26] test: generate 24 Mhz clk for tinyfpga_bootloader endpoint --- tests/file_list.txt | 1 + tests/top_tb_header.vh | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/tests/file_list.txt b/tests/file_list.txt index 1c65819..076f817 100644 --- a/tests/file_list.txt +++ b/tests/file_list.txt @@ -1,5 +1,6 @@ test.v ../../common/edge_detect.v +../../common/strobe.v ../../common/tinyfpga_bootloader.v ../../common/usb_fs_in_arb.v ../../common/usb_fs_in_pe.v diff --git a/tests/top_tb_header.vh b/tests/top_tb_header.vh index db174bf..a0d656b 100644 --- a/tests/top_tb_header.vh +++ b/tests/top_tb_header.vh @@ -25,6 +25,7 @@ module top_tb; end reg clk_48mhz; + reg clk = 0; reg reset = 0; initial begin @@ -34,6 +35,8 @@ module top_tb; end end + always @(posedge clk_48mhz) clk <= !clk; + // usb interface wire usb_p_tx_raw; wire usb_n_tx_raw; @@ -59,6 +62,7 @@ module top_tb; tinyfpga_bootloader dut ( .clk_48mhz(clk_48mhz), + .clk(clk), .reset(reset), .usb_p_tx(usb_p_tx_raw), From dac0dc3566e5642ab4fc2504d2c41e511baca362 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 18 Jan 2019 22:58:19 -0500 Subject: [PATCH 14/26] usb: iverilog fixes for clock-crossing strobes --- common/usb_fs_rx.v | 9 +++++++-- common/usb_fs_tx.v | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/common/usb_fs_rx.v b/common/usb_fs_rx.v index fed9906..ab9c73c 100644 --- a/common/usb_fs_rx.v +++ b/common/usb_fs_rx.v @@ -343,14 +343,19 @@ module usb_fs_rx ( end // cross the packet start signal to the endpoint clk domain - strobe pkt_start_strobe(clk_48mhz, clk, packet_start, pkt_start); + strobe pkt_start_strobe( + .clk_in(clk_48mhz), + .clk_out(clk), + .strobe_in(packet_start), + .strobe_out(pkt_start) + ); // at the end of the packet, capture the parameters to the clk domain strobe #(.WIDTH(26)) pkt_end_strobe( clk_48mhz, clk, packet_end, pkt_end, { pid_48, addr_48, endp_48, frame_num_48 }, - { pid, addr, endp, frame_num }, + { pid, addr, endp, frame_num } ); assign pid_48 = full_pid[4:1]; diff --git a/common/usb_fs_tx.v b/common/usb_fs_tx.v index 723f318..34d2377 100644 --- a/common/usb_fs_tx.v +++ b/common/usb_fs_tx.v @@ -44,7 +44,12 @@ module usb_fs_tx ( // convert tx_data_get from 48 to clk //wire tx_data_get_48 = tx_data_get; reg tx_data_get_48; - strobe tx_data_get_strobe(clk_48mhz, clk, tx_data_get_48, tx_data_get); + strobe tx_data_get_strobe( + .clk_in(clk_48mhz), + .clk_out(clk), + .strobe_in(tx_data_get_48), + .strobe_out(tx_data_get) + ); reg [7:0] data_shift_reg = 0; reg [7:0] oe_shift_reg = 0; @@ -77,7 +82,12 @@ module usb_fs_tx ( end wire pkt_end_48 = bit_strobe && se0_shift_reg[1:0] == 2'b01; - strobe pkt_end_strobe(clk_48mhz, pkt_end_48, clk, pkt_end); + strobe pkt_end_strobe( + .clk_in(clk_48mhz), + .clk_out(clk), + .strobe_in(pkt_end_48), + .strobe_out(pkt_end) + ); reg data_payload = 0; From b76d0f2607305dc67b18e5a5e3c9f6b4b4794de2 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 5 Jul 2019 19:20:13 +0200 Subject: [PATCH 15/26] ignore generated ecp5 files --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index f1af15c..2c3eb5e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,8 @@ synlog.tcl gerbers/ build/ *.pyc +*.bit +*.json +.*.d +.*.sw* +gmon.out From 8dc4253792ef9e15de6f43bf7cd29b24959cb387 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 5 Jul 2019 19:20:43 +0200 Subject: [PATCH 16/26] usb_fs_rx: fix yosys error on dvalid --- common/usb_fs_rx.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/usb_fs_rx.v b/common/usb_fs_rx.v index 8c73f68..3ea598d 100644 --- a/common/usb_fs_rx.v +++ b/common/usb_fs_rx.v @@ -224,7 +224,7 @@ module usb_fs_rx ( end end - assign dvalid = dvalid_raw && !(bitstuff_history == 6'b111111); + wire dvalid = dvalid_raw && !(bitstuff_history == 6'b111111); //////////////////////////////////////////////////////////////////////////////// From ad18a5ff519cdc74f8e41510ae58364d6b34a7bc Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 5 Jul 2019 19:21:15 +0200 Subject: [PATCH 17/26] ulx3s: bootloader compiles, but does not yet enumerate on USB correctly --- boards/ULX3S/Makefile | 37 +++ boards/ULX3S/bootloader.v | 121 ++++++++++ boards/ULX3S/pll_240.v | 40 ++++ boards/ULX3S/pll_48.v | 40 ++++ boards/ULX3S/ulx3s_v20.lpf | 462 +++++++++++++++++++++++++++++++++++++ 5 files changed, 700 insertions(+) create mode 100644 boards/ULX3S/Makefile create mode 100644 boards/ULX3S/bootloader.v create mode 100644 boards/ULX3S/pll_240.v create mode 100644 boards/ULX3S/pll_48.v create mode 100644 boards/ULX3S/ulx3s_v20.lpf diff --git a/boards/ULX3S/Makefile b/boards/ULX3S/Makefile new file mode 100644 index 0000000..52481fd --- /dev/null +++ b/boards/ULX3S/Makefile @@ -0,0 +1,37 @@ +# +# Bootloader for the ulx3s ECP5 board +# Builds with nextpnr-ecp5 and prjtrellis from git +# +IDCODE ?= 0x21111043 # 12f + +all: bootloader.bit + +%.json: %.v + yosys \ + -p "read_verilog -I../../common $<" \ + -p "synth_ecp5 -json $@" \ + -E .$(basename $@).d \ + -q \ + +%.config: %.json + nextpnr-ecp5 \ + --json $< \ + --textcfg $@ \ + --lpf ulx3s_v20.lpf \ + --timing-allow-fail \ + --25k + +%.bit: %.config + ecppack --idcode $(IDCODE) $< $@ + +%.svf: %.config + ecppack --idcode $(IDCODE) --input $< --svf $@ + +%.flash: %.bit + ujprog $< +%.terminal: %.bit + ujprog -t -b 3000000 $< + +clean: + $(RM) *.config *.bit .*.d *.svf +-include .*.d diff --git a/boards/ULX3S/bootloader.v b/boards/ULX3S/bootloader.v new file mode 100644 index 0000000..0704e43 --- /dev/null +++ b/boards/ULX3S/bootloader.v @@ -0,0 +1,121 @@ +`default_nettype none +`include "tinyfpga_bootloader.v" +`include "edge_detect.v" +`include "usb_fs_pe.v" +`include "usb_fs_in_arb.v" +`include "usb_fs_in_pe.v" +`include "usb_fs_out_arb.v" +`include "usb_fs_out_pe.v" +`include "usb_fs_rx.v" +`include "usb_fs_tx.v" +`include "usb_fs_tx_mux.v" +`include "usb_reset_det.v" +`include "usb_serial_ctrl_ep.v" +`include "usb_spi_bridge_ep.v" +`include "pll_240.v" +`include "pll_48.v" + + +module top( + input clk_25mhz, + output [7:0] led, + output wifi_gpio0, + + //input ftdi_txd, // from the ftdi chip + //output ftdi_rxd, // to the ftdi chip + + // USB port directly wired to serial port + inout usb_fpga_bd_dn, + inout usb_fpga_bd_dp, + output usb_fpga_pu_dp, + output usb_fpga_pu_dn, + + // onboard SPI flash + output flash_csn, + //output flash_clk, // special - see USRMCLK below + output flash_mosi, + input flash_miso, + output flash_holdn, + output flash_wpn, + + // select a reboot from the user space on the flash + output user_programn +); + // avoid reboot? + assign wifi_gpio0 = 1; + + // 25 MHz input clock, 240 MHz output + wire clk_240mhz, clk_48mhz; + wire locked; + wire reset = !locked; + pll_240 pll_240_i(clk_25mhz, clk_240mhz); + pll_48 pll_48_i(clk_240mhz, clk_48mhz, locked); + + // configure as a full speed device (pull up on dp) + assign usb_fpga_pu_dp = 1; // full speed 1.1 device + assign usb_fpga_pu_dn = 0; // full speed 1.1 device + wire usb_tx_en; + wire usb_p_tx, usb_n_tx; + wire usb_p_rx, usb_n_rx; + + TRELLIS_IO #(.DIR("BIDIR")) usb_p_buf( + .T(!usb_tx_en), + .B(usb_fpga_bd_dp), + .I(usb_p_tx), + .O(usb_p_rx), + ); + TRELLIS_IO #(.DIR("BIDIR")) usb_n_buf( + .T(!usb_tx_en), + .B(usb_fpga_bd_dn), + .I(usb_n_tx), + .O(usb_n_rx), + ); + + // ensure that the flash aux pins are in a stable state + // and allow flash updates + assign flash_holdn = 1; + assign flash_wpn = 1; + + // the U3 pin on the package is special and requires magic to drive it + wire flash_clk; + wire flash_csn_i; // needs to be a wire? + assign flash_csn = flash_csn_i; + USRMCLK usrmclk_inst ( + .USRMCLKI(flash_clk), + .USRMCLKTS(flash_csn_i) + ) /* synthesis syn_noprune=1 */; + + + wire boot; + + tinyfpga_bootloader tinyfgpa_bootloader_inst( + .clk_48mhz(clk_48mhz), + .reset(reset), + .usb_p_tx(usb_p_tx), + .usb_n_tx(usb_n_tx), + .usb_p_rx(usb_tx_en ? 1'b1 : usb_p_rx), + .usb_n_rx(usb_tx_en ? 1'b0 : usb_n_rx), + .usb_tx_en(usb_tx_en), + .led(led[0]), + .spi_miso(flash_miso), + .spi_cs(flash_csn_i), + .spi_mosi(flash_mosi), + .spi_sck(flash_clk), + .boot(boot) + ); + + reg initiate_boot = 0; + reg [8:0] boot_delay = 0; + + assign user_programn = ~boot_delay[8]; // initiate user program + assign led[7:1] = 0; + + always @(posedge clk_48mhz) begin + if (boot) + initiate_boot <= 1; + + if (initiate_boot) begin + boot_delay <= boot_delay + 1'b1; + end + end +endmodule diff --git a/boards/ULX3S/pll_240.v b/boards/ULX3S/pll_240.v new file mode 100644 index 0000000..98ebd4f --- /dev/null +++ b/boards/ULX3S/pll_240.v @@ -0,0 +1,40 @@ +module pll_240 +( + input clkin, // 25 MHz, 0 deg + output clkout0, // 240 MHz, 0 deg + output locked +); +wire clkfb; +wire clkos; +wire clkop; +(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *) +EHXPLLL #( + .PLLRST_ENA("DISABLED"), + .INTFB_WAKE("DISABLED"), + .STDBY_ENABLE("DISABLED"), + .DPHASE_SOURCE("DISABLED"), + .CLKOP_FPHASE(0), + .CLKOP_CPHASE(0), + .OUTDIVIDER_MUXA("DIVA"), + .CLKOP_ENABLE("ENABLED"), + .CLKOP_DIV(2), + .CLKFB_DIV(48), + .CLKI_DIV(5), + .FEEDBK_PATH("INT_OP") + ) pll_i ( + .CLKI(clkin), + .CLKFB(clkfb), + .CLKINTFB(clkfb), + .CLKOP(clkop), + .RST(1'b0), + .STDBY(1'b0), + .PHASESEL0(1'b0), + .PHASESEL1(1'b0), + .PHASEDIR(1'b0), + .PHASESTEP(1'b0), + .PLLWAKESYNC(1'b0), + .ENCLKOP(1'b0), + .LOCK(locked) + ); +assign clkout0 = clkop; +endmodule diff --git a/boards/ULX3S/pll_48.v b/boards/ULX3S/pll_48.v new file mode 100644 index 0000000..9bc45ca --- /dev/null +++ b/boards/ULX3S/pll_48.v @@ -0,0 +1,40 @@ +module pll_48 +( + input clkin, // 240 MHz, 0 deg + output clkout0, // 48 MHz, 0 deg + output locked +); +wire clkfb; +wire clkos; +wire clkop; +(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *) +EHXPLLL #( + .PLLRST_ENA("DISABLED"), + .INTFB_WAKE("DISABLED"), + .STDBY_ENABLE("DISABLED"), + .DPHASE_SOURCE("DISABLED"), + .CLKOP_FPHASE(0), + .CLKOP_CPHASE(5), + .OUTDIVIDER_MUXA("DIVA"), + .CLKOP_ENABLE("ENABLED"), + .CLKOP_DIV(12), + .CLKFB_DIV(1), + .CLKI_DIV(5), + .FEEDBK_PATH("INT_OP") + ) pll_i ( + .CLKI(clkin), + .CLKFB(clkfb), + .CLKINTFB(clkfb), + .CLKOP(clkop), + .RST(1'b0), + .STDBY(1'b0), + .PHASESEL0(1'b0), + .PHASESEL1(1'b0), + .PHASEDIR(1'b0), + .PHASESTEP(1'b0), + .PLLWAKESYNC(1'b0), + .ENCLKOP(1'b0), + .LOCK(locked) + ); +assign clkout0 = clkop; +endmodule diff --git a/boards/ULX3S/ulx3s_v20.lpf b/boards/ULX3S/ulx3s_v20.lpf new file mode 100644 index 0000000..310e231 --- /dev/null +++ b/boards/ULX3S/ulx3s_v20.lpf @@ -0,0 +1,462 @@ +BLOCK RESETPATHS; +BLOCK ASYNCPATHS; +## ULX3S v2.x.x and v3.0.x + +# The clock "usb" and "gpdi" sheet +LOCATE COMP "clk_25mhz" SITE "G2"; +IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33; +FREQUENCY PORT "clk_25mhz" 25 MHZ; + +# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash +# write to FLASH possible any time from JTAG: +#SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=ENABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE; +# write to FLASH possible from user bitstream: +SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=DISABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE; + +## USBSERIAL FTDI-FPGA serial port "usb" sheet +LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi +LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi +LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives +LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives +LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives +IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33; + +## LED indicators "blinkey" and "gpio" sheet +LOCATE COMP "led[7]" SITE "H3"; +LOCATE COMP "led[6]" SITE "E1"; +LOCATE COMP "led[5]" SITE "E2"; +LOCATE COMP "led[4]" SITE "D1"; +LOCATE COMP "led[3]" SITE "D2"; +LOCATE COMP "led[2]" SITE "C1"; +LOCATE COMP "led[1]" SITE "C2"; +LOCATE COMP "led[0]" SITE "B2"; +IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet +LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic) +LOCATE COMP "btn[1]" SITE "R1"; # FIRE1 +LOCATE COMP "btn[2]" SITE "T1"; # FIRE2 +LOCATE COMP "btn[3]" SITE "R18"; # UP +LOCATE COMP "btn[4]" SITE "V1"; # DOWN +LOCATE COMP "btn[5]" SITE "U1"; # LEFT +LOCATE COMP "btn[6]" SITE "H16"; # RIGHT +IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33; + +## DIP switch "blinkey", "gpio" sheet +LOCATE COMP "sw[0]" SITE "E8"; # SW1 +LOCATE COMP "sw[1]" SITE "D8"; # SW2 +LOCATE COMP "sw[2]" SITE "D7"; # SW3 +LOCATE COMP "sw[3]" SITE "E7"; # SW4 +IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33; +IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33; + +## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet +LOCATE COMP "oled_clk" SITE "P4"; +LOCATE COMP "oled_mosi" SITE "P3"; +LOCATE COMP "oled_dc" SITE "P1"; +LOCATE COMP "oled_resn" SITE "P2"; +LOCATE COMP "oled_csn" SITE "N2"; +IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SPI Flash chip "flash" sheet +LOCATE COMP "flash_csn" SITE "R2"; +LOCATE COMP "flash_clk" SITE "U3"; +LOCATE COMP "flash_mosi" SITE "W2"; +LOCATE COMP "flash_miso" SITE "V2"; +LOCATE COMP "flash_holdn" SITE "W1"; +LOCATE COMP "flash_wpn" SITE "Y2"; +#LOCATE COMP "flash_csspin" SITE "AJ3"; +#LOCATE COMP "flash_initn" SITE "AG4"; +#LOCATE COMP "flash_done" SITE "AJ4"; +#LOCATE COMP "flash_programn" SITE "AH4"; +#LOCATE COMP "flash_cfg_select[0]" SITE "AM4"; +#LOCATE COMP "flash_cfg_select[1]" SITE "AL4"; +#LOCATE COMP "flash_cfg_select[2]" SITE "AK4"; +IOBUF PORT "flash_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_mosi" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_miso" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_holdn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_wpn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## SD card "sdcard", "usb" sheet +LOCATE COMP "sd_clk" SITE "H2"; # sd_clk WiFi_GPIO14 +LOCATE COMP "sd_cmd" SITE "J1"; # sd_cmd_di (MOSI) WiFi GPIO15 +LOCATE COMP "sd_d[0]" SITE "J3"; # sd_dat0_do (MISO) WiFi GPIO2 +LOCATE COMP "sd_d[1]" SITE "H1"; # sd_dat1_irq WiFi GPIO4 +LOCATE COMP "sd_d[2]" SITE "K1"; # sd_dat2 WiFi_GPIO12 +LOCATE COMP "sd_d[3]" SITE "K2"; # sd_dat3_csn WiFi_GPIO13 +LOCATE COMP "sd_wp" SITE "P5"; # not connected +LOCATE COMP "sd_cdn" SITE "N5"; # not connected +IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement +IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## ADC SPI (MAX11123) "analog", "ram" sheet +LOCATE COMP "adc_csn" SITE "R17"; +LOCATE COMP "adc_mosi" SITE "R16"; +LOCATE COMP "adc_miso" SITE "U16"; +LOCATE COMP "adc_sclk" SITE "P17"; +IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## Audio 4-bit DAC "analog", "gpio" sheet +# Output impedance 75 ohm. +# Strong enough to drive 16 ohm earphones. +LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio) +LOCATE COMP "audio_l[2]" SITE "C3"; +LOCATE COMP "audio_l[1]" SITE "D3"; +LOCATE COMP "audio_l[0]" SITE "E4"; +LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio) +LOCATE COMP "audio_r[2]" SITE "D5"; +LOCATE COMP "audio_r[1]" SITE "B5"; +LOCATE COMP "audio_r[0]" SITE "A3"; +LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio) +LOCATE COMP "audio_v[2]" SITE "F5"; +LOCATE COMP "audio_v[1]" SITE "F2"; +LOCATE COMP "audio_v[0]" SITE "H5"; +IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; + +## WiFi ESP-32 "wifi", "usb", "flash" sheet +# other pins are shared with GP/GN, SD card and JTAG +LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi +LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi +LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi +LOCATE COMP "wifi_gpio0" SITE "L2"; +LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED +LOCATE COMP "wifi_gpio16" SITE "L1"; # Serial1 RX +LOCATE COMP "wifi_gpio17" SITE "N3"; # Serial1 TX +# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active +IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio5" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## PCB antenna 433 MHz (may be also used for FM) "usb" sheet +LOCATE COMP "ant_433mhz" SITE "G1"; +IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## Second USB port "US2" going directly into FPGA "usb", "ram" sheet +LOCATE COMP "usb_fpga_dp" SITE "E16"; # single ended or differential input only +LOCATE COMP "usb_fpga_dn" SITE "F16"; +IOBUF PORT "usb_fpga_dp" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=16; +IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=16; +LOCATE COMP "usb_fpga_bd_dp" SITE "D15"; # single-ended bidirectional +LOCATE COMP "usb_fpga_bd_dn" SITE "E15"; +IOBUF PORT "usb_fpga_bd_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "usb_fpga_bd_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "usb_fpga_pu_dp" SITE "B12"; # pull up/down control +LOCATE COMP "usb_fpga_pu_dn" SITE "C12"; +IOBUF PORT "usb_fpga_pu_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; + +## JTAG ESP-32 "usb" sheet +# connected to FT231X and ESP-32 +# commented out because those are dedicated pins, not directly useable as GPIO +# but could be used by some vendor-specific JTAG bridging (boundary scan) module +#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives +#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits +#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives +#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives +#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SDRAM "ram" sheet +LOCATE COMP "sdram_clk" SITE "F19"; +LOCATE COMP "sdram_cke" SITE "F20"; +LOCATE COMP "sdram_csn" SITE "P20"; +LOCATE COMP "sdram_wen" SITE "T20"; +LOCATE COMP "sdram_rasn" SITE "R20"; +LOCATE COMP "sdram_casn" SITE "T19"; +LOCATE COMP "sdram_a[0]" SITE "M20"; +LOCATE COMP "sdram_a[1]" SITE "M19"; +LOCATE COMP "sdram_a[2]" SITE "L20"; +LOCATE COMP "sdram_a[3]" SITE "L19"; +LOCATE COMP "sdram_a[4]" SITE "K20"; +LOCATE COMP "sdram_a[5]" SITE "K19"; +LOCATE COMP "sdram_a[6]" SITE "K18"; +LOCATE COMP "sdram_a[7]" SITE "J20"; +LOCATE COMP "sdram_a[8]" SITE "J19"; +LOCATE COMP "sdram_a[9]" SITE "H20"; +LOCATE COMP "sdram_a[10]" SITE "N19"; +LOCATE COMP "sdram_a[11]" SITE "G20"; +LOCATE COMP "sdram_a[12]" SITE "G19"; +LOCATE COMP "sdram_ba[0]" SITE "P19"; +LOCATE COMP "sdram_ba[1]" SITE "N20"; +LOCATE COMP "sdram_dqm[0]" SITE "U19"; +LOCATE COMP "sdram_dqm[1]" SITE "E20"; +LOCATE COMP "sdram_d[0]" SITE "J16"; +LOCATE COMP "sdram_d[1]" SITE "L18"; +LOCATE COMP "sdram_d[2]" SITE "M18"; +LOCATE COMP "sdram_d[3]" SITE "N18"; +LOCATE COMP "sdram_d[4]" SITE "P18"; +LOCATE COMP "sdram_d[5]" SITE "T18"; +LOCATE COMP "sdram_d[6]" SITE "T17"; +LOCATE COMP "sdram_d[7]" SITE "U20"; +LOCATE COMP "sdram_d[8]" SITE "E19"; +LOCATE COMP "sdram_d[9]" SITE "D20"; +LOCATE COMP "sdram_d[10]" SITE "D19"; +LOCATE COMP "sdram_d[11]" SITE "C20"; +LOCATE COMP "sdram_d[12]" SITE "E18"; +LOCATE COMP "sdram_d[13]" SITE "F18"; +LOCATE COMP "sdram_d[14]" SITE "J18"; +LOCATE COMP "sdram_d[15]" SITE "J17"; +IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +# GPDI differential interface (Video) "gpdi" sheet +LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue + +LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue - +LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green + +LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green - +LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red + +LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Red - +LOCATE COMP "gpdi_dp[3]" SITE "A17"; # Clock + +LOCATE COMP "gpdi_dn[3]" SITE "B18"; # Clock - +LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet + +LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet - +LOCATE COMP "gpdi_cec" SITE "A18"; +LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC +LOCATE COMP "gpdi_scl" SITE "E12"; # I2C shared with RTC C12->E12 +IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dp[3]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[3]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet +# Physical connector pins: +# *** when FEMALE ANGLED (90 deg PMOD) soldered *** +# Jm_n- = Jm_n, Jm_n+ = Jm_n+1 +# example: J1_5- is J1_5 phsyical, J1_5+ is J1_6 physical +# *** when MALE VERTICAL soldered *** +# Jm_n+ = Jm_n, Jm_n- = Jm_n+1 +# example: J1_5+ is J1_5 physical, J1_5- is J1_6 physical +# Pins enumerated gp[0-27], gn[0-27]. +# With differential mode enabled on Lattice, +# gp[] (+) are used, gn[] (-) are ignored from design +# as they handle inverted signal by default. +# To enable differential, rename LVCMOS33->LVCMOS33D +# To enable clock i/o, add this (example): +#FREQUENCY PORT "gp[12]" 25.00 MHZ; +LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0 PCLK +LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0 PCLK +LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1 PCLK +LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1 PCLK +LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2 GR_PCLK +LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2 GR_PCLK +LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3 +LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3 +LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4 +LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4 +LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5 +LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5 +LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6 +LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6 +IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7 +LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7 +LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8 +LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8 DIFF +LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9 DIFF +LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9 DIFF +LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 DIFF +LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10 DIFF +LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 DIFF WIFI_GPIO26 +LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 DIFF WIFI_GPIO25 +LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 DIFF WIFI_GPIO33 PCLK +LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 DIFF WIFI_GPIO32 PCLK +LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 DIFF WIFI_GPIO35 +LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 DIFF WIFI_GPIO34 +IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14 DIFF ADC1 +LOCATE COMP "gn[14]" SITE "U17"; # J2_5- GN14 DIFF ADC0 +LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15 DIFF ADC3 +LOCATE COMP "gn[15]" SITE "P16"; # J2_7- GN15 DIFF ADC2 +LOCATE COMP "gp[16]" SITE "N16"; # J2_9+ GP16 DIFF ADC5 +LOCATE COMP "gn[16]" SITE "M17"; # J2_9- GN16 DIFF ADC4 +LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17 DIFF ADC7 GR_PCLK +LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17 DIFF ADC6 +LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18 DIFF +LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18 DIFF +LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19 DIFF +LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19 DIFF +LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20 DIFF +LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20 DIFF +IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[17]" IO_TYPE=LVCMOS33 SLEWRATE=FAST ; // MISO +IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33; +LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21 DIFF +LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21 DIFF +LOCATE COMP "gp[22]" SITE "B15"; # J2_25+ GP22 +LOCATE COMP "gn[22]" SITE "C15"; # J2_25- GN22 +LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23 +LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23 +LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24 +LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24 +LOCATE COMP "gp[25]" SITE "D14"; # J2_31+ GP25 +LOCATE COMP "gn[25]" SITE "E14"; # J2_31- GN25 +LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26 +LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26 +LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27 +LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27 +IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33; + +## PROGRAMN (reload bitstream from FLASH, exit from bootloader) +# PCB v2.0.5 and higher +LOCATE COMP "user_programn" SITE "M4"; +IOBUF PORT "user_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5) +# on PCB v1.7 shutdown is not connected to FPGA +LOCATE COMP "shutdown" SITE "G16"; # FPGA receives +IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; From 7c5c51453e5ca0aa83a46a74f4af148b406dbe4f Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 5 Jul 2019 19:44:12 +0200 Subject: [PATCH 18/26] ulx3s: works with the clock-crossing USB driver --- boards/ULX3S/bootloader.v | 34 ++++++++++++++------------- boards/ULX3S/{pll_240.v => pll_132.v} | 18 +++++++++----- boards/ULX3S/pll_48.v | 6 ++--- 3 files changed, 33 insertions(+), 25 deletions(-) rename boards/ULX3S/{pll_240.v => pll_132.v} (71%) diff --git a/boards/ULX3S/bootloader.v b/boards/ULX3S/bootloader.v index 0704e43..24d3482 100644 --- a/boards/ULX3S/bootloader.v +++ b/boards/ULX3S/bootloader.v @@ -1,6 +1,7 @@ `default_nettype none `include "tinyfpga_bootloader.v" `include "edge_detect.v" +`include "strobe.v" `include "usb_fs_pe.v" `include "usb_fs_in_arb.v" `include "usb_fs_in_pe.v" @@ -12,7 +13,7 @@ `include "usb_reset_det.v" `include "usb_serial_ctrl_ep.v" `include "usb_spi_bridge_ep.v" -`include "pll_240.v" +`include "pll_132.v" `include "pll_48.v" @@ -44,31 +45,31 @@ module top( // avoid reboot? assign wifi_gpio0 = 1; - // 25 MHz input clock, 240 MHz output - wire clk_240mhz, clk_48mhz; + // 25 MHz input clock, 132 MHz output + wire clk_132mhz, clk_48mhz; wire locked; wire reset = !locked; - pll_240 pll_240_i(clk_25mhz, clk_240mhz); - pll_48 pll_48_i(clk_240mhz, clk_48mhz, locked); + pll_132 pll_132_i(.clkin(clk_25mhz), .clkout0(clk_132mhz), .locked(locked)); + pll_48 pll_48_i(clk_132mhz, clk_48mhz); // configure as a full speed device (pull up on dp) assign usb_fpga_pu_dp = 1; // full speed 1.1 device assign usb_fpga_pu_dn = 0; // full speed 1.1 device wire usb_tx_en; - wire usb_p_tx, usb_n_tx; - wire usb_p_rx, usb_n_rx; + wire usb_n_in, usb_n_out; + wire usb_p_in, usb_p_out; TRELLIS_IO #(.DIR("BIDIR")) usb_p_buf( .T(!usb_tx_en), .B(usb_fpga_bd_dp), - .I(usb_p_tx), - .O(usb_p_rx), + .I(usb_p_out), + .O(usb_p_in), ); TRELLIS_IO #(.DIR("BIDIR")) usb_n_buf( .T(!usb_tx_en), .B(usb_fpga_bd_dn), - .I(usb_n_tx), - .O(usb_n_rx), + .I(usb_n_out), + .O(usb_n_in), ); // ensure that the flash aux pins are in a stable state @@ -90,11 +91,12 @@ module top( tinyfpga_bootloader tinyfgpa_bootloader_inst( .clk_48mhz(clk_48mhz), + .clk(clk_132mhz), .reset(reset), - .usb_p_tx(usb_p_tx), - .usb_n_tx(usb_n_tx), - .usb_p_rx(usb_tx_en ? 1'b1 : usb_p_rx), - .usb_n_rx(usb_tx_en ? 1'b0 : usb_n_rx), + .usb_p_tx(usb_p_out), + .usb_n_tx(usb_n_out), + .usb_p_rx(usb_tx_en ? 1'b1 : usb_p_in), + .usb_n_rx(usb_tx_en ? 1'b0 : usb_n_in), .usb_tx_en(usb_tx_en), .led(led[0]), .spi_miso(flash_miso), @@ -110,7 +112,7 @@ module top( assign user_programn = ~boot_delay[8]; // initiate user program assign led[7:1] = 0; - always @(posedge clk_48mhz) begin + always @(posedge clk_132mhz) begin if (boot) initiate_boot <= 1; diff --git a/boards/ULX3S/pll_240.v b/boards/ULX3S/pll_132.v similarity index 71% rename from boards/ULX3S/pll_240.v rename to boards/ULX3S/pll_132.v index 98ebd4f..8f49422 100644 --- a/boards/ULX3S/pll_240.v +++ b/boards/ULX3S/pll_132.v @@ -1,7 +1,8 @@ -module pll_240 +module pll_132 ( input clkin, // 25 MHz, 0 deg - output clkout0, // 240 MHz, 0 deg + output clkout0, // 132.143 MHz, 0 deg + output clkout1, // 132.143 MHz, 180 deg output locked ); wire clkfb; @@ -14,18 +15,23 @@ EHXPLLL #( .STDBY_ENABLE("DISABLED"), .DPHASE_SOURCE("DISABLED"), .CLKOP_FPHASE(0), - .CLKOP_CPHASE(0), + .CLKOP_CPHASE(2), .OUTDIVIDER_MUXA("DIVA"), .CLKOP_ENABLE("ENABLED"), - .CLKOP_DIV(2), - .CLKFB_DIV(48), - .CLKI_DIV(5), + .CLKOP_DIV(5), + .CLKOS_ENABLE("ENABLED"), + .CLKOS_DIV(5), + .CLKOS_CPHASE(4), + .CLKOS_FPHASE(4), + .CLKFB_DIV(37), + .CLKI_DIV(7), .FEEDBK_PATH("INT_OP") ) pll_i ( .CLKI(clkin), .CLKFB(clkfb), .CLKINTFB(clkfb), .CLKOP(clkop), + .CLKOS(clkout1), .RST(1'b0), .STDBY(1'b0), .PHASESEL0(1'b0), diff --git a/boards/ULX3S/pll_48.v b/boards/ULX3S/pll_48.v index 9bc45ca..8d5df70 100644 --- a/boards/ULX3S/pll_48.v +++ b/boards/ULX3S/pll_48.v @@ -1,6 +1,6 @@ module pll_48 ( - input clkin, // 240 MHz, 0 deg + input clkin, // 132 MHz, 0 deg output clkout0, // 48 MHz, 0 deg output locked ); @@ -18,8 +18,8 @@ EHXPLLL #( .OUTDIVIDER_MUXA("DIVA"), .CLKOP_ENABLE("ENABLED"), .CLKOP_DIV(12), - .CLKFB_DIV(1), - .CLKI_DIV(5), + .CLKFB_DIV(4), + .CLKI_DIV(11), .FEEDBK_PATH("INT_OP") ) pll_i ( .CLKI(clkin), From 1dd31e0afaecb1765854c95470bbee8d54f9be37 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 5 Jul 2019 20:53:13 +0200 Subject: [PATCH 19/26] tinyprog: allow updates to the security pages --- programmer/tinyprog/__init__.py | 10 +++++++++ programmer/tinyprog/__main__.py | 36 ++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/programmer/tinyprog/__init__.py b/programmer/tinyprog/__init__.py index ed585a9..c777e37 100644 --- a/programmer/tinyprog/__init__.py +++ b/programmer/tinyprog/__init__.py @@ -2,6 +2,7 @@ import platform import re import struct +import time from functools import reduce from pkg_resources import get_distribution, DistributionNotFound @@ -566,3 +567,12 @@ def program_bitstream_fast(self, addr, bitstream): self.wake() self.progress(str(len(bitstream)) + " bytes to program") return self.program_fast(addr, bitstream) + + def program_security_page(self, page, data): + self.progress("Waking up SPI flash") + self.wake() + self.progress("Erasing security page " + str(page)) + self.erase_security_register_page(page) + self.progress(str(len(data)) + " bytes to program") + return self.program_security_register_page(page, data) + diff --git a/programmer/tinyprog/__main__.py b/programmer/tinyprog/__main__.py index cf45634..16f4d5c 100644 --- a/programmer/tinyprog/__main__.py +++ b/programmer/tinyprog/__main__.py @@ -266,6 +266,10 @@ def parse_int(str_value): "--meta", action="store_true", help="dump out the metadata for all connected boards in JSON") + parser.add_argument( + "--security", + type=str, + help="update the security page in the flash at address addr") parser.add_argument( "--update-bootloader", action="store_true", @@ -372,6 +376,7 @@ def parse_int(str_value): # program the flash memory if (args.program is not None) or ( args.program_userdata is not None) or ( + args.security is not None) or ( args.program_image is not None): boot_fpga = False @@ -381,6 +386,7 @@ def progress(info): with active_port: fpga = TinyProg(active_port, progress) + force = False if args.program is not None: print(" Programming %s with %s" % ( @@ -390,6 +396,7 @@ def progress(info): if args.addr is not None: addr = parse_int(args.addr) + force = True else: addr = fpga.meta.userimage_addr_range()[0] @@ -400,7 +407,7 @@ def progress(info): print(" Bootloader not active") sys.exit(1) - if check_if_overwrite_bootloader( + if force or check_if_overwrite_bootloader( addr, len(bitstream), fpga.meta.userimage_addr_range()): boot_fpga = True @@ -417,6 +424,7 @@ def progress(info): if args.addr is not None: addr = parse_int(args.addr) + force = True else: addr = fpga.meta.userdata_addr_range()[0] @@ -427,7 +435,7 @@ def progress(info): print(" Bootloader not active") sys.exit(1) - if check_if_overwrite_bootloader( + if force or check_if_overwrite_bootloader( addr, len(bitstream), fpga.meta.userdata_addr_range()): boot_fpga = True @@ -444,6 +452,7 @@ def progress(info): if args.addr is not None: addr = parse_int(args.addr) + force = True else: addr = fpga.meta.userimage_addr_range()[0] @@ -454,7 +463,7 @@ def progress(info): print(" Bootloader not active") sys.exit(1) - if check_if_overwrite_bootloader( + if force or check_if_overwrite_bootloader( addr, len(bitstream), (fpga.meta.userimage_addr_range()[0], fpga.meta.userdata_addr_range()[1])): @@ -463,6 +472,27 @@ def progress(info): if not fpga.program_bitstream(addr, bitstream): sys.exit(1) + if args.security is not None: + print(" Programming %s security page with %s" % ( + active_port, args.security)) + + data = open(args.security, 'r').read() + + if args.addr is not None: + addr = parse_int(args.addr) + else: + addr = 1 + + if addr < 0: + print(" Negative write addr: {}".format(addr)) + sys.exit(1) + if not fpga.is_bootloader_active(): + print(" Bootloader not active") + sys.exit(1) + + if not fpga.program_security_page(addr, data): + sys.exit(1) + if boot_fpga: fpga.boot() print("") From bfdfcced5577910f2971efda4761c410197947af Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 5 Jul 2019 21:22:45 +0200 Subject: [PATCH 20/26] ulx3s: multi-boot image creation and SFDP security page json files --- boards/ULX3S/Makefile | 16 ++++++++++++++-- boards/ULX3S/boardmeta.json | 6 ++++++ boards/ULX3S/bootmeta.json | 10 ++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 boards/ULX3S/boardmeta.json create mode 100644 boards/ULX3S/bootmeta.json diff --git a/boards/ULX3S/Makefile b/boards/ULX3S/Makefile index 52481fd..8205752 100644 --- a/boards/ULX3S/Makefile +++ b/boards/ULX3S/Makefile @@ -1,10 +1,22 @@ # # Bootloader for the ulx3s ECP5 board -# Builds with nextpnr-ecp5 and prjtrellis from git +# Builds with nextpnr-ecp5 and prjtrellis from git as of 2019-07-05 # IDCODE ?= 0x21111043 # 12f -all: bootloader.bit +all: fw.bin + +fw.bin: bootloader.bit + ecpmulti \ + --input-idcode 0x41111043 \ + --output-idcode $(IDCODE) \ + -v \ + --output $@ \ + --flashsize 128 \ + --input $< \ + --address 0x100000 \ + --input $< + %.json: %.v yosys \ diff --git a/boards/ULX3S/boardmeta.json b/boards/ULX3S/boardmeta.json new file mode 100644 index 0000000..f7d7d42 --- /dev/null +++ b/boards/ULX3S/boardmeta.json @@ -0,0 +1,6 @@ +{"boardmeta":{ + "name": "ULX3S", + "fpga": "ecp5-12f", + "hver": "1.0.0", + "serial": 31415 +}} diff --git a/boards/ULX3S/bootmeta.json b/boards/ULX3S/bootmeta.json new file mode 100644 index 0000000..04d94be --- /dev/null +++ b/boards/ULX3S/bootmeta.json @@ -0,0 +1,10 @@ +{"bootmeta":{ +"bootloader":"TinyFPGA USB Bootloader", +"bver":"2.0.0", +"update":"https://tinyfpga.com/update/ulx3s", +"addrmap":{ +"bootloader":"0x0-0xFFFFF", +"userimage":"0x100000-0x1EFFFF", +"userdata":"0x200000-0xFFFFFF", +"desc.tgz":"0x1F0000-0x1FFFFF" +}}} From 3876b7d45307447a18297d638b1619b2ea888689 Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 5 Jul 2019 21:28:35 +0200 Subject: [PATCH 21/26] ulx3s: bootstrap flow --- boards/ULX3S/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 boards/ULX3S/README.md diff --git a/boards/ULX3S/README.md b/boards/ULX3S/README.md new file mode 100644 index 0000000..c399e40 --- /dev/null +++ b/boards/ULX3S/README.md @@ -0,0 +1,20 @@ +ULX3S ECP5 FPGA +--- + +To bootstrap the bootloader: + +* `make` should build `bootloader.bit` +* Connect both USB ports `US1` and `US2` to the computer +* `sudo ujprog bootloader.bit` will load it into the FPGA SRAM via US1 +* The TinyFPGA bootloader should enumerate as `/dev/ttyACM0` via US2 +* Load the security pages into the SPI flash SFDP pages: +``` +sudo tinyprog -a 1 --security boardmeta.json +sudo tinyprog -a 2 --security bootmeta.json +``` +* `tinyprog -m` should now show the meta data +* `tinyprog --program-image fw.bin` should write the multiboot image into the flash +* Disconnect both the USB ports and reconnect just US2. +* The bootloader should be running and flashing LED0, and show up again as `/dev/ttyACM0` +* Load your own user image with `tinyprog -p userimage.bit` + From 803df7d9eaf3b283d78aa366e4a22261f2c603cd Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 5 Jul 2019 21:31:47 +0200 Subject: [PATCH 22/26] ignore generated ecp5 files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2c3eb5e..7614d15 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ build/ .*.d .*.sw* gmon.out +*.bin From 5d043fd0961aa6ad4adaf7cea8fbd2729693dd1f Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Fri, 5 Jul 2019 21:37:35 +0200 Subject: [PATCH 23/26] tinyprog: fix tab/whitespace issue --- programmer/tinyprog/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programmer/tinyprog/__init__.py b/programmer/tinyprog/__init__.py index c777e37..2a1632e 100644 --- a/programmer/tinyprog/__init__.py +++ b/programmer/tinyprog/__init__.py @@ -572,7 +572,7 @@ def program_security_page(self, page, data): self.progress("Waking up SPI flash") self.wake() self.progress("Erasing security page " + str(page)) - self.erase_security_register_page(page) + self.erase_security_register_page(page) self.progress(str(len(data)) + " bytes to program") - return self.program_security_register_page(page, data) + return self.program_security_register_page(page, data) From 43672180fbcd60b4e30bbce99744e37b011fe3ce Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Sat, 6 Jul 2019 16:04:23 +0200 Subject: [PATCH 24/26] tinyprog: optimize re-writes by not erasing matching sectors or empty pages --- programmer/tinyprog/__init__.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/programmer/tinyprog/__init__.py b/programmer/tinyprog/__init__.py index 2a1632e..3648c38 100644 --- a/programmer/tinyprog/__init__.py +++ b/programmer/tinyprog/__init__.py @@ -494,12 +494,32 @@ def program_sectors(self, addr, data): for offset in range(0, len(data), sector_size): current_addr = addr + offset current_write_data = data[offset:offset + sector_size] + + # Determine if we need to write this sector at all + current_flash_data = self.read( + current_addr, + sector_size, + disable_progress=True, + max_length=sector_size) + + if current_flash_data == current_write_data: + # skip this sector since it matches + pbar.update(sector_size) + continue + self.erase(current_addr, sector_size, disable_progress=True) minor_sector_size = 256 for minor_offset in range(0, 4 * 1024, minor_sector_size): minor_write_data = current_write_data[ minor_offset:minor_offset + minor_sector_size] + + # if the minor data is all 0xFF then it will match + # the erased bits and doesn't need to be re-sent + if minor_write_data == chr(0xFF) * len(minor_write_data): + pbar.update(len(minor_write_data)) + continue; + self.write( current_addr + minor_offset, minor_write_data, From c2d36e2938d9944754d9b2a71b159bb393b6cf9f Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Thu, 29 Aug 2019 13:39:06 +0200 Subject: [PATCH 25/26] ulx3s: flash target and updated documentation for write address --- boards/ULX3S/Makefile | 10 ++++++++++ boards/ULX3S/README.md | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/boards/ULX3S/Makefile b/boards/ULX3S/Makefile index 8205752..df7e310 100644 --- a/boards/ULX3S/Makefile +++ b/boards/ULX3S/Makefile @@ -6,6 +6,16 @@ IDCODE ?= 0x21111043 # 12f all: fw.bin +flash: fw.bin bootloader.bit + @echo "-- Plug in both USB ports on the ecp5 --" + ujprog bootloader.bit + sleep 2 + -tinyprog -a 1 --security boardmeta.json + -tinyprog -a 2 --security bootmeta.json + tinyprog -a 0 --program-image fw.bin + sleep 2 + tinyprog -m + fw.bin: bootloader.bit ecpmulti \ --input-idcode 0x41111043 \ diff --git a/boards/ULX3S/README.md b/boards/ULX3S/README.md index c399e40..c377e32 100644 --- a/boards/ULX3S/README.md +++ b/boards/ULX3S/README.md @@ -13,8 +13,11 @@ sudo tinyprog -a 1 --security boardmeta.json sudo tinyprog -a 2 --security bootmeta.json ``` * `tinyprog -m` should now show the meta data -* `tinyprog --program-image fw.bin` should write the multiboot image into the flash +* `tinyprog -a 0 --program-image fw.bin` should write the multiboot image into the flash * Disconnect both the USB ports and reconnect just US2. * The bootloader should be running and flashing LED0, and show up again as `/dev/ttyACM0` * Load your own user image with `tinyprog -p userimage.bit` +---- + +Maybe that no longer works? Had to write the From fbfa25d2ccdd7dd17ecad7fba8fe27d7791372fe Mon Sep 17 00:00:00 2001 From: Trammell hudson Date: Thu, 29 Aug 2019 13:58:46 +0200 Subject: [PATCH 26/26] tinyprog: successful return code from security page write --- boards/ULX3S/Makefile | 6 +++--- programmer/tinyprog/__init__.py | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/boards/ULX3S/Makefile b/boards/ULX3S/Makefile index df7e310..9cdde35 100644 --- a/boards/ULX3S/Makefile +++ b/boards/ULX3S/Makefile @@ -10,10 +10,10 @@ flash: fw.bin bootloader.bit @echo "-- Plug in both USB ports on the ecp5 --" ujprog bootloader.bit sleep 2 - -tinyprog -a 1 --security boardmeta.json - -tinyprog -a 2 --security bootmeta.json + tinyprog -a 1 --security boardmeta.json + tinyprog -a 2 --security bootmeta.json tinyprog -a 0 --program-image fw.bin - sleep 2 + sleep 5 tinyprog -m fw.bin: bootloader.bit diff --git a/programmer/tinyprog/__init__.py b/programmer/tinyprog/__init__.py index 3648c38..e8106a9 100644 --- a/programmer/tinyprog/__init__.py +++ b/programmer/tinyprog/__init__.py @@ -354,6 +354,7 @@ def program_security_register_page(self, page, data): self.security_page_write_cmd, page << (8 + self.security_page_bit_offset), data) self.wait_while_busy() + return True def read_security_register_page(self, page): return self.cmd( @@ -518,7 +519,7 @@ def program_sectors(self, addr, data): # the erased bits and doesn't need to be re-sent if minor_write_data == chr(0xFF) * len(minor_write_data): pbar.update(len(minor_write_data)) - continue; + continue self.write( current_addr + minor_offset,