diff options
Diffstat (limited to 'usrp2/gpmc')
-rw-r--r-- | usrp2/gpmc/.gitignore | 2 | ||||
-rw-r--r-- | usrp2/gpmc/burst_data_write.txt | 16 | ||||
-rw-r--r-- | usrp2/gpmc/dbsm.v | 80 | ||||
-rw-r--r-- | usrp2/gpmc/edge_sync.v | 22 | ||||
-rw-r--r-- | usrp2/gpmc/fifo_to_gpmc_async.v | 38 | ||||
-rw-r--r-- | usrp2/gpmc/fifo_to_gpmc_sync.v | 26 | ||||
-rw-r--r-- | usrp2/gpmc/fifo_watcher.v | 54 | ||||
-rw-r--r-- | usrp2/gpmc/gpmc_async.v | 111 | ||||
-rw-r--r-- | usrp2/gpmc/gpmc_sync.v | 107 | ||||
-rw-r--r-- | usrp2/gpmc/gpmc_to_fifo_async.v | 68 | ||||
-rw-r--r-- | usrp2/gpmc/gpmc_to_fifo_sync.v | 57 | ||||
-rw-r--r-- | usrp2/gpmc/gpmc_wb.v | 57 | ||||
-rwxr-xr-x | usrp2/gpmc/make_timing_diag | 6 | ||||
-rw-r--r-- | usrp2/gpmc/ram_to_fifo.v | 46 | ||||
-rw-r--r-- | usrp2/gpmc/single_data_read.txt | 12 | ||||
-rw-r--r-- | usrp2/gpmc/single_data_write.txt | 10 |
16 files changed, 712 insertions, 0 deletions
diff --git a/usrp2/gpmc/.gitignore b/usrp2/gpmc/.gitignore new file mode 100644 index 000000000..3e14fa4f7 --- /dev/null +++ b/usrp2/gpmc/.gitignore @@ -0,0 +1,2 @@ +*.gif + diff --git a/usrp2/gpmc/burst_data_write.txt b/usrp2/gpmc/burst_data_write.txt new file mode 100644 index 000000000..3b5dfc785 --- /dev/null +++ b/usrp2/gpmc/burst_data_write.txt @@ -0,0 +1,16 @@ +# OMAP burst writes to FPGA + +CLK=0,nWE=1,nCS=1,nOE=1,DATA=Z. +CLK=1. +CLK=0,nWE=0,nCS=0,DATA=WR_DATA1. +CLK=1. +CLK=0,nWE=0,nCS=0,DATA=WR_DATA2. +CLK=1. +CLK=0,nWE=0,nCS=0,DATA=WR_DATA3. +CLK=1. +CLK=0,nWE=0,nCS=0,DATA=WR_DATA4. +CLK=1. +CLK=0,nWE=1,nCS=1,DATA=Z. +CLK=1. + + diff --git a/usrp2/gpmc/dbsm.v b/usrp2/gpmc/dbsm.v new file mode 100644 index 000000000..530af7205 --- /dev/null +++ b/usrp2/gpmc/dbsm.v @@ -0,0 +1,80 @@ + +module bsm + (input clk, input reset, input clear, + input write_done, + input read_done, + output readable, + output writeable); + + reg state; + localparam ST_WRITEABLE = 0; + localparam ST_READABLE = 1; + + always @(posedge clk) + if(reset | clear) + state <= ST_WRITEABLE; + else + case(state) + ST_WRITEABLE : + if(write_done) + state <= ST_READABLE; + ST_READABLE : + if(read_done) + state <= ST_WRITEABLE; + endcase // case (state) + + assign readable = (state == ST_READABLE); + assign writeable = (state == ST_WRITEABLE); + +endmodule // bsm + +module dbsm + (input clk, input reset, input clear, + output reg read_sel, output read_ready, input read_done, + output reg write_sel, output write_ready, input write_done); + + localparam NUM_BUFS = 2; + + wire [NUM_BUFS-1:0] readable, writeable, read_done_buf, write_done_buf; + + // Two of these buffer state machines + genvar i; + generate + for(i=0;i<NUM_BUFS;i=i+1) + begin : BSMS + bsm bsm(.clk(clk), .reset(reset), .clear(clear), + .write_done((write_sel == i) & write_done), + .read_done((read_sel == i) & read_done), + .readable(readable[i]), .writeable(writeable[i])); + end + endgenerate + + reg full; + + always @(posedge clk) + if(reset | clear) + begin + write_sel <= 0; + full <= 0; + end + else + if(write_done & writeable[write_sel]) + if(write_sel ==(NUM_BUFS-1)) + write_sel <= 0; + else + write_sel <= write_sel + 1; + + always @(posedge clk) + if(reset | clear) + read_sel <= 0; + else + if(read_done & readable[read_sel]) + if(read_sel==(NUM_BUFS-1)) + read_sel <= 0; + else + read_sel <= read_sel + 1; + + assign write_ready = writeable[write_sel]; + assign read_ready = readable[read_sel]; + +endmodule // dbsm diff --git a/usrp2/gpmc/edge_sync.v b/usrp2/gpmc/edge_sync.v new file mode 100644 index 000000000..5d9417c08 --- /dev/null +++ b/usrp2/gpmc/edge_sync.v @@ -0,0 +1,22 @@ + + +module edge_sync + #(parameter POSEDGE = 1) + (input clk, + input rst, + input sig, + output trig); + + reg [1:0] delay; + + always @(posedge clk) + if(rst) + delay <= 2'b00; + else + delay <= {delay[0],sig}; + + assign trig = POSEDGE ? (delay==2'b01) : (delay==2'b10); + +endmodule // edge_sync + + diff --git a/usrp2/gpmc/fifo_to_gpmc_async.v b/usrp2/gpmc/fifo_to_gpmc_async.v new file mode 100644 index 000000000..5ac8b19bd --- /dev/null +++ b/usrp2/gpmc/fifo_to_gpmc_async.v @@ -0,0 +1,38 @@ + +// Assumes an asynchronous GPMC cycle +// If a packet bigger or smaller than we are told is sent, behavior is undefined. +// If dst_rdy_i is low when we get data, behavior is undefined and we signal bus error. +// If there is a bus error, we should be reset + +module fifo_to_gpmc_async + (input clk, input reset, input clear, + input [17:0] data_i, input src_rdy_i, output dst_rdy_o, + output [15:0] EM_D, input EM_NCS, input EM_NOE, + input [15:0] frame_len); + + // Synchronize the async control signals + reg [1:0] cs_del, oe_del; + reg [15:0] counter; + + always @(posedge clk) + if(reset) + begin + cs_del <= 2'b11; + oe_del <= 2'b11; + end + else + begin + cs_del <= { cs_del[0], EM_NCS }; + oe_del <= { oe_del[0], EM_NOE }; + end + + //wire do_read = (~cs_del[0] & (oe_del == 2'b10)); + wire do_read = (~cs_del[1] & (oe_del == 2'b01)); // change output on trailing edge + wire first_read = (counter == 0); + wire last_read = ((counter+1) == frame_len); + + assign EM_D = data_i[15:0]; + + assign dst_rdy_o = do_read; + +endmodule // fifo_to_gpmc_async diff --git a/usrp2/gpmc/fifo_to_gpmc_sync.v b/usrp2/gpmc/fifo_to_gpmc_sync.v new file mode 100644 index 000000000..ef59d7137 --- /dev/null +++ b/usrp2/gpmc/fifo_to_gpmc_sync.v @@ -0,0 +1,26 @@ + +// Assumes a GPMC cycle with GPMC clock, as in the timing diagrams +// If a packet bigger or smaller than we are told is sent, behavior is undefined. +// If dst_rdy_i is low when we get data, behavior is undefined and we signal bus error. +// If there is a bus error, we should be reset + +module fifo_to_gpmc_sync + (input arst, + input [17:0] data_i, input src_rdy_i, output dst_rdy_o, + input EM_CLK, output [15:0] EM_D, input EM_NCS, input EM_NOE, + output fifo_ready, + output reg bus_error); + + assign EM_D = data_i[15:0]; + wire read_access = ~EM_NCS & ~EM_NOE; + + assign dst_rdy_o = read_access; + + always @(posedge EM_CLK or posedge arst) + if(arst) + bus_error <= 0; + else if(dst_rdy_o & ~src_rdy_i) + bus_error <= 1; + + +endmodule // fifo_to_gpmc_sync diff --git a/usrp2/gpmc/fifo_watcher.v b/usrp2/gpmc/fifo_watcher.v new file mode 100644 index 000000000..4bba142b0 --- /dev/null +++ b/usrp2/gpmc/fifo_watcher.v @@ -0,0 +1,54 @@ + + +module fifo_watcher + (input clk, input reset, input clear, + input src_rdy1, input dst_rdy1, input sof1, input eof1, + input src_rdy2, input dst_rdy2, input sof2, input eof2, + output reg have_packet, output [15:0] length, output reg bus_error); + + wire write = src_rdy1 & dst_rdy1 & eof1; + wire read = src_rdy2 & dst_rdy2 & eof2; + wire have_packet_int; + reg [15:0] counter; + wire [4:0] pkt_count; + + fifo_short #(.WIDTH(16)) frame_lengths + (.clk(clk), .reset(reset), .clear(clear), + .datain(counter), .src_rdy_i(write), .dst_rdy_o(), + .dataout(length), .src_rdy_o(have_packet_int), .dst_rdy_i(read), + .occupied(pkt_count), .space()); + + always @(posedge clk) + if(reset | clear) + counter <= 1; // Start at 1 + else if(src_rdy1 & dst_rdy1) + if(eof1) + counter <= 1; + else + counter <= counter + 1; + + always @(posedge clk) + if(reset | clear) + bus_error <= 0; + else if(dst_rdy2 & ~src_rdy2) + bus_error <= 1; + else if(read & ~have_packet_int) + bus_error <= 1; + + reg in_packet; + always @(posedge clk) + if(reset | clear) + have_packet <= 0; + else + have_packet <= (have_packet_int & ~in_packet) | (pkt_count>1) ; + + always @(posedge clk) + if(reset | clear) + in_packet <= 0; + else if(src_rdy2 & dst_rdy2) + if(eof2) + in_packet <= 0; + else + in_packet <= 1; + +endmodule // fifo_watcher diff --git a/usrp2/gpmc/gpmc_async.v b/usrp2/gpmc/gpmc_async.v new file mode 100644 index 000000000..dd06478b3 --- /dev/null +++ b/usrp2/gpmc/gpmc_async.v @@ -0,0 +1,111 @@ +////////////////////////////////////////////////////////////////////////////////// + +module gpmc_async + (// GPMC signals + input arst, + input EM_CLK, inout [15:0] EM_D, input [10:1] EM_A, input [1:0] EM_NBE, + input EM_WAIT0, input EM_NCS4, input EM_NCS6, input EM_NWE, input EM_NOE, + + // GPIOs for FIFO signalling + output rx_have_data, output tx_have_space, output reg bus_error, input bus_reset, + + // Wishbone signals + input wb_clk, input wb_rst, + output [10:0] wb_adr_o, output [15:0] wb_dat_mosi, input [15:0] wb_dat_miso, + output [1:0] wb_sel_o, output wb_cyc_o, output wb_stb_o, output wb_we_o, input wb_ack_i, + + // FIFO interface + input fifo_clk, input fifo_rst, + output [35:0] tx_data_o, output tx_src_rdy_o, input tx_dst_rdy_i, + input [35:0] rx_data_i, input rx_src_rdy_i, output rx_dst_rdy_o, + + input [15:0] tx_frame_len, output [15:0] rx_frame_len, + + output [31:0] debug + ); + + wire EM_output_enable = (~EM_NOE & (~EM_NCS4 | ~EM_NCS6)); + wire [15:0] EM_D_fifo; + wire [15:0] EM_D_wb; + + assign EM_D = ~EM_output_enable ? 16'bz : ~EM_NCS4 ? EM_D_fifo : EM_D_wb; + + wire bus_error_tx, bus_error_rx; + + always @(posedge fifo_clk) + if(fifo_rst) + bus_error <= 0; + else + bus_error <= bus_error_tx | bus_error_rx; + + // CS4 is RAM_2PORT for DATA PATH (high-speed data) + // Writes go into one RAM, reads come from the other + // CS6 is for CONTROL PATH (wishbone) + + // //////////////////////////////////////////// + // TX Data Path + + wire [17:0] tx18_data, tx18b_data; + wire tx18_src_rdy, tx18_dst_rdy, tx18b_src_rdy, tx18b_dst_rdy; + wire [15:0] tx_fifo_space; + + gpmc_to_fifo_async gpmc_to_fifo_async + (.EM_D(EM_D), .EM_NBE(EM_NBE), .EM_NCS(EM_NCS4), .EM_NWE(EM_NWE), + .fifo_clk(fifo_clk), .fifo_rst(fifo_rst), + .data_o(tx18_data), .src_rdy_o(tx18_src_rdy), .dst_rdy_i(tx18_dst_rdy), + .frame_len(tx_frame_len), .fifo_space(tx_fifo_space), .fifo_ready(tx_have_space), + .bus_error(bus_error_tx) ); + + fifo_cascade #(.WIDTH(18), .SIZE(10)) tx_fifo + (.clk(fifo_clk), .reset(fifo_rst), .clear(0), + .datain(tx18_data), .src_rdy_i(tx18_src_rdy), .dst_rdy_o(tx18_dst_rdy), .space(tx_fifo_space), + .dataout(tx18b_data), .src_rdy_o(tx18b_src_rdy), .dst_rdy_i(tx18b_dst_rdy), .occupied()); + + fifo19_to_fifo36 f19_to_f36 + (.clk(fifo_clk), .reset(fifo_rst), .clear(0), + .f19_datain({1'b0,tx18b_data}), .f19_src_rdy_i(tx18b_src_rdy), .f19_dst_rdy_o(tx18b_dst_rdy), + .f36_dataout(tx_data_o), .f36_src_rdy_o(tx_src_rdy_o), .f36_dst_rdy_i(tx_dst_rdy_i)); + + // //////////////////////////////////////////// + // RX Data Path + + wire [17:0] rx18_data, rx18b_data; + wire rx18_src_rdy, rx18_dst_rdy, rx18b_src_rdy, rx18b_dst_rdy; + wire [15:0] rx_fifo_space; + + fifo36_to_fifo18 f18_to_f36 + (.clk(fifo_clk), .reset(fifo_rst), .clear(0), + .f36_datain(rx_data_i), .f36_src_rdy_i(rx_src_rdy_i), .f36_dst_rdy_o(rx_dst_rdy_o), + .f18_dataout(rx18_data), .f18_src_rdy_o(rx18_src_rdy), .f18_dst_rdy_i(rx18_dst_rdy) ); + + fifo_cascade #(.WIDTH(18), .SIZE(12)) rx_fifo + (.clk(fifo_clk), .reset(fifo_rst), .clear(0), + .datain(rx18_data), .src_rdy_i(rx18_src_rdy), .dst_rdy_o(rx18_dst_rdy), .space(rx_fifo_space), + .dataout(rx18b_data), .src_rdy_o(rx18b_src_rdy), .dst_rdy_i(rx18b_dst_rdy), .occupied()); + + fifo_to_gpmc_async fifo_to_gpmc_async + (.clk(fifo_clk), .reset(fifo_rst), .clear(0), + .data_i(rx18b_data), .src_rdy_i(rx18b_src_rdy), .dst_rdy_o(rx18b_dst_rdy), + .EM_D(EM_D_fifo), .EM_NCS(EM_NCS4), .EM_NOE(EM_NOE), + .frame_len(rx_frame_len) ); + + fifo_watcher fifo_watcher + (.clk(fifo_clk), .reset(fifo_rst), .clear(0), + .src_rdy1(rx18_src_rdy), .dst_rdy1(rx18_dst_rdy), .sof1(rx18_data[16]), .eof1(rx18_data[17]), + .src_rdy2(rx18b_src_rdy), .dst_rdy2(rx18b_dst_rdy), .sof2(rx18b_data[16]), .eof2(rx18b_data[17]), + .have_packet(rx_have_data), .length(rx_frame_len), .bus_error(bus_error_rx) ); + + // //////////////////////////////////////////// + // Control path on CS6 + + gpmc_wb gpmc_wb + (.EM_CLK(EM_CLK), .EM_D_in(EM_D), .EM_D_out(EM_D_wb), .EM_A(EM_A), .EM_NBE(EM_NBE), + .EM_NCS(EM_NCS6), .EM_NWE(EM_NWE), .EM_NOE(EM_NOE), + .wb_clk(wb_clk), .wb_rst(wb_rst), + .wb_adr_o(wb_adr_o), .wb_dat_mosi(wb_dat_mosi), .wb_dat_miso(wb_dat_miso), + .wb_sel_o(wb_sel_o), .wb_cyc_o(wb_cyc_o), .wb_stb_o(wb_stb_o), .wb_we_o(wb_we_o), + .wb_ack_i(wb_ack_i) ); + + assign debug = 0; + +endmodule // gpmc_async diff --git a/usrp2/gpmc/gpmc_sync.v b/usrp2/gpmc/gpmc_sync.v new file mode 100644 index 000000000..825d131d8 --- /dev/null +++ b/usrp2/gpmc/gpmc_sync.v @@ -0,0 +1,107 @@ +////////////////////////////////////////////////////////////////////////////////// + +module gpmc_sync + (// GPMC signals + input arst, + input EM_CLK, inout [15:0] EM_D, input [10:1] EM_A, input [1:0] EM_NBE, + input EM_WAIT0, input EM_NCS4, input EM_NCS6, input EM_NWE, input EM_NOE, + + // GPIOs for FIFO signalling + output rx_have_data, output tx_have_space, output bus_error, input bus_reset, + + // Wishbone signals + input wb_clk, input wb_rst, + output [10:0] wb_adr_o, output [15:0] wb_dat_mosi, input [15:0] wb_dat_miso, + output [1:0] wb_sel_o, output wb_cyc_o, output wb_stb_o, output wb_we_o, input wb_ack_i, + + // FIFO interface + input fifo_clk, input fifo_rst, + output [35:0] tx_data_o, output tx_src_rdy_o, input tx_dst_rdy_i, + input [35:0] rx_data_i, input rx_src_rdy_i, output rx_dst_rdy_o, + + output [31:0] debug + ); + + wire EM_output_enable = (~EM_NOE & (~EM_NCS4 | ~EM_NCS6)); + wire [15:0] EM_D_fifo; + wire [15:0] EM_D_wb; + + assign EM_D = ~EM_output_enable ? 16'bz : ~EM_NCS4 ? EM_D_fifo : EM_D_wb; + + wire bus_error_tx, bus_error_rx; + assign bus_error = bus_error_tx | bus_error_rx; + + // CS4 is RAM_2PORT for DATA PATH (high-speed data) + // Writes go into one RAM, reads come from the other + // CS6 is for CONTROL PATH (wishbone) + + // //////////////////////////////////////////// + // TX Data Path + + wire [17:0] tx18_data, tx18b_data; + wire tx18_src_rdy, tx18_dst_rdy, tx18b_src_rdy, tx18b_dst_rdy; + wire [15:0] tx_fifo_space, tx_frame_len; + + assign tx_frame_len = 10; + + gpmc_to_fifo_sync gpmc_to_fifo_sync + (.arst(arst), + .EM_CLK(EM_CLK), .EM_D(EM_D), .EM_NBE(EM_NBE), .EM_NCS(EM_NCS4), .EM_NWE(EM_NWE), + .data_o(tx18_data), .src_rdy_o(tx18_src_rdy), .dst_rdy_i(tx18_dst_rdy), + .frame_len(tx_frame_len), .fifo_space(tx_fifo_space), .fifo_ready(tx_have_space), + .bus_error(bus_error_tx) ); + + fifo_2clock_cascade #(.WIDTH(18), .SIZE(4)) tx_fifo + (.wclk(EM_CLK), .datain(tx18_data), + .src_rdy_i(tx18_src_rdy), .dst_rdy_o(tx18_dst_rdy), .space(tx_fifo_space), + .rclk(fifo_clk), .dataout(tx18b_data), + .src_rdy_o(tx18b_src_rdy), .dst_rdy_i(tx18b_dst_rdy), .occupied(), .arst(arst)); + + fifo19_to_fifo36 f19_to_f36 + (.clk(fifo_clk), .reset(fifo_rst), .clear(0), + .f19_datain({1'b0,tx18b_data}), .f19_src_rdy_i(tx18b_src_rdy), .f19_dst_rdy_o(tx18b_dst_rdy), + .f36_dataout(tx_data_o), .f36_src_rdy_o(tx_src_rdy_o), .f36_dst_rdy_i(tx_dst_rdy_i)); + + // //////////////////////////////////////////// + // RX Data Path + + wire [17:0] rx18_data, rx18b_data; + wire rx18_src_rdy, rx18_dst_rdy, rx18b_src_rdy, rx18b_dst_rdy; + wire [15:0] rx_fifo_space, rx_frame_len; + + fifo36_to_fifo18 f18_to_f36 + (.clk(fifo_clk), .reset(fifo_rst), .clear(0), + .f36_datain(rx_data_i), .f36_src_rdy_i(rx_src_rdy_i), .f36_dst_rdy_o(rx_dst_rdy_o), + .f18_dataout(rx18_data), .f18_src_rdy_o(rx18_src_rdy), .f18_dst_rdy_i(rx18_dst_rdy) ); + + fifo_2clock_cascade #(.WIDTH(18), .SIZE(10)) rx_fifo + (.wclk(fifo_clk), .datain(rx18_data), + .src_rdy_i(rx18_src_rdy), .dst_rdy_o(rx18_dst_rdy), .space(rx_fifo_space), + .rclk(EM_CLK), .dataout(rx18b_data), + .src_rdy_o(rx18b_src_rdy), .dst_rdy_i(rx18b_dst_rdy), .occupied(), .arst(arst)); + + fifo_to_gpmc_sync fifo_to_gpmc_sync + (.arst(arst), + .data_i(rx18b_data), .src_rdy_i(rx18b_src_rdy), .dst_rdy_o(rx18b_dst_rdy), + .EM_CLK(EM_CLK), .EM_D(EM_D_fifo), .EM_NCS(EM_NCS4), .EM_NOE(EM_NOE), + .fifo_ready(rx_have_data) ); + + fifo_watcher fifo_watcher + (.clk(fifo_clk), .reset(fifo_rst), .clear(0), + .src_rdy(rx18_src_rdy), .dst_rdy(rx18_dst_rdy), .sof(rx18_data[16]), .eof(rx18_data[17]), + .have_packet(), .length(), .next() ); + + // //////////////////////////////////////////// + // Control path on CS6 + + gpmc_wb gpmc_wb + (.EM_CLK(EM_CLK), .EM_D_in(EM_D), .EM_D_out(EM_D_wb), .EM_A(EM_A), .EM_NBE(EM_NBE), + .EM_NCS(EM_NCS6), .EM_NWE(EM_NWE), .EM_NOE(EM_NOE), + .wb_clk(wb_clk), .wb_rst(wb_rst), + .wb_adr_o(wb_adr_o), .wb_dat_mosi(wb_dat_mosi), .wb_dat_miso(wb_dat_miso), + .wb_sel_o(wb_sel_o), .wb_cyc_o(wb_cyc_o), .wb_stb_o(wb_stb_o), .wb_we_o(wb_we_o), + .wb_ack_i(wb_ack_i) ); + + assign debug = 0; + +endmodule // gpmc_sync diff --git a/usrp2/gpmc/gpmc_to_fifo_async.v b/usrp2/gpmc/gpmc_to_fifo_async.v new file mode 100644 index 000000000..3d29745a2 --- /dev/null +++ b/usrp2/gpmc/gpmc_to_fifo_async.v @@ -0,0 +1,68 @@ + +module gpmc_to_fifo_async + (input [15:0] EM_D, input [1:0] EM_NBE, input EM_NCS, input EM_NWE, + + input fifo_clk, input fifo_rst, + output reg [17:0] data_o, output reg src_rdy_o, input dst_rdy_i, + + input [15:0] frame_len, input [15:0] fifo_space, output reg fifo_ready, + output reg bus_error ); + + reg [15:0] counter; + // Synchronize the async control signals + reg [1:0] cs_del, we_del; + always @(posedge fifo_clk) + if(fifo_rst) + begin + cs_del <= 2'b11; + we_del <= 2'b11; + end + else + begin + cs_del <= { cs_del[0], EM_NCS }; + we_del <= { we_del[0], EM_NWE }; + end + + wire do_write = (~cs_del[0] & (we_del == 2'b10)); + wire first_write = (counter == 0); + wire last_write = ((counter+1) == frame_len); + + always @(posedge fifo_clk) + if(do_write) + begin + data_o[15:0] <= EM_D; + data_o[16] <= first_write; + data_o[17] <= last_write; + // no byte writes data_o[18] <= |EM_NBE; // mark half full if either is not enabled FIXME + end + + always @(posedge fifo_clk) + if(fifo_rst) + src_rdy_o <= 0; + else if(do_write) + src_rdy_o <= 1; + else + src_rdy_o <= 0; // Assume it was taken + + always @(posedge fifo_clk) + if(fifo_rst) + counter <= 0; + else if(do_write) + if(last_write) + counter <= 0; + else + counter <= counter + 1; + + always @(posedge fifo_clk) + if(fifo_rst) + fifo_ready <= 0; + else + fifo_ready <= /* first_write & */ (fifo_space > 16'd1023); + + always @(posedge fifo_clk) + if(fifo_rst) + bus_error <= 0; + else if(src_rdy_o & ~dst_rdy_i) + bus_error <= 1; + +endmodule // gpmc_to_fifo_async diff --git a/usrp2/gpmc/gpmc_to_fifo_sync.v b/usrp2/gpmc/gpmc_to_fifo_sync.v new file mode 100644 index 000000000..688de0e17 --- /dev/null +++ b/usrp2/gpmc/gpmc_to_fifo_sync.v @@ -0,0 +1,57 @@ + +// Assumes a GPMC cycle with GPMC clock, as in the timing diagrams +// If a packet bigger or smaller than we are told is sent, behavior is undefined. +// If dst_rdy_i is low when we get data, behavior is undefined and we signal bus error. +// If there is a bus error, we should be reset + +module gpmc_to_fifo_sync + (input arst, + input EM_CLK, input [15:0] EM_D, input [1:0] EM_NBE, + input EM_NCS, input EM_NWE, + output reg [17:0] data_o, output reg src_rdy_o, input dst_rdy_i, + input [15:0] frame_len, input [15:0] fifo_space, output fifo_ready, + output reg bus_error); + + reg [10:0] counter; + wire first_write = (counter == 0); + wire last_write = ((counter+1) == frame_len); + wire do_write = ~EM_NCS & ~EM_NWE; + + always @(posedge EM_CLK or posedge arst) + if(arst) + data_o <= 0; + else if(do_write) + begin + data_o[15:0] <= EM_D; + data_o[16] <= first_write; + data_o[17] <= last_write; + // no byte writes data_o[18] <= |EM_NBE; // mark half full if either is not enabled FIXME + end + + always @(posedge EM_CLK or posedge arst) + if(arst) + src_rdy_o <= 0; + else if(do_write & ~bus_error) // Don't put junk in if there is a bus error + src_rdy_o <= 1; + else + src_rdy_o <= 0; // Assume it was taken, ignore dst_rdy_i + + always @(posedge EM_CLK or posedge arst) + if(arst) + counter <= 0; + else if(do_write) + if(last_write) + counter <= 0; + else + counter <= counter + 1; + + assign fifo_ready = first_write & (fifo_space > frame_len); + + always @(posedge EM_CLK or posedge arst) + if(arst) + bus_error <= 0; + else if(src_rdy_o & ~dst_rdy_i) + bus_error <= 1; + // must be reset to make the error go away + +endmodule // gpmc_to_fifo_sync diff --git a/usrp2/gpmc/gpmc_wb.v b/usrp2/gpmc/gpmc_wb.v new file mode 100644 index 000000000..db6fbc6e9 --- /dev/null +++ b/usrp2/gpmc/gpmc_wb.v @@ -0,0 +1,57 @@ + + +module gpmc_wb + (input EM_CLK, input [15:0] EM_D_in, output [15:0] EM_D_out, input [10:1] EM_A, input [1:0] EM_NBE, + input EM_NCS, input EM_NWE, input EM_NOE, + + input wb_clk, input wb_rst, + output reg [10:0] wb_adr_o, output reg [15:0] wb_dat_mosi, input [15:0] wb_dat_miso, + output reg [1:0] wb_sel_o, output wb_cyc_o, output reg wb_stb_o, output reg wb_we_o, input wb_ack_i); + + // //////////////////////////////////////////// + // Control Path, Wishbone bus bridge (wb master) + reg [1:0] cs_del, we_del, oe_del; + + // Synchronize the async control signals + always @(posedge wb_clk) + begin + cs_del <= { cs_del[0], EM_NCS }; + we_del <= { we_del[0], EM_NWE }; + oe_del <= { oe_del[0], EM_NOE }; + end + + always @(posedge wb_clk) + if(cs_del == 2'b10) // Falling Edge + wb_adr_o <= { EM_A, 1'b0 }; + + always @(posedge wb_clk) + if(we_del == 2'b10) // Falling Edge + begin + wb_dat_mosi <= EM_D_in; + wb_sel_o <= ~EM_NBE; + end + + reg [15:0] EM_D_hold; + + always @(posedge wb_clk) + if(wb_ack_i) + EM_D_hold <= wb_dat_miso; + + assign EM_D_out = wb_ack_i ? wb_dat_miso : EM_D_hold; + + assign wb_cyc_o = wb_stb_o; + + always @(posedge wb_clk) + if(~cs_del[0] & (we_del == 2'b10) ) + wb_we_o <= 1; + else if(wb_ack_i) // Turn off we when done. Could also use we_del[0], others... + wb_we_o <= 0; + + // FIXME should this look at cs_del[1]? + always @(posedge wb_clk) + if(~cs_del[0] & ((we_del == 2'b10) | (oe_del == 2'b10))) + wb_stb_o <= 1; + else if(wb_ack_i) + wb_stb_o <= 0; + +endmodule // gpmc_wb diff --git a/usrp2/gpmc/make_timing_diag b/usrp2/gpmc/make_timing_diag new file mode 100755 index 000000000..03166ad35 --- /dev/null +++ b/usrp2/gpmc/make_timing_diag @@ -0,0 +1,6 @@ +#!/bin/sh +drawtiming -o single_data_write.gif single_data_write.txt +drawtiming -o single_data_read.gif single_data_read.txt +drawtiming -o burst_data_write.gif burst_data_write.txt +#drawtiming -o burst_data_read.gif burst_data_read.txt + diff --git a/usrp2/gpmc/ram_to_fifo.v b/usrp2/gpmc/ram_to_fifo.v new file mode 100644 index 000000000..8549dcc35 --- /dev/null +++ b/usrp2/gpmc/ram_to_fifo.v @@ -0,0 +1,46 @@ + + +module ram_to_fifo + (input clk, input reset, + input [10:0] read_length, // From the dbsm (?) + output read_en, output reg [8:0] read_addr, input [31:0] read_data, input read_ready, output read_done, + output [35:0] data_o, output src_rdy_o, input dst_rdy_i); + + // read_length/2 = number of 32 bit lines, numbered 0 through read_length/2-1 + wire [8:0] last_line = (read_length[10:1]-1); + + reg read_phase, sop; + + assign read_en = (read_phase == 0) | dst_rdy_i; + assign src_rdy_o = (read_phase == 1); + + always @(posedge clk) + if(reset) + begin + read_addr <= 0; + read_phase <= 0; + sop <= 1; + end + else + if(read_phase == 0) + begin + read_addr <= read_ready; + read_phase <= read_ready; + end + else if(dst_rdy_i) + begin + sop <= 0; + if(read_addr == last_line) + begin + read_addr <= 0; + read_phase <= 0; + end + else + read_addr <= read_addr + 1; + end + + assign read_done = (read_phase == 1) & (read_addr == last_line) & dst_rdy_i; + wire eop = (read_addr == last_line); + assign data_o = { 2'b00, eop, sop, read_data }; + +endmodule // ram_to_fifo diff --git a/usrp2/gpmc/single_data_read.txt b/usrp2/gpmc/single_data_read.txt new file mode 100644 index 000000000..1dc0e3a78 --- /dev/null +++ b/usrp2/gpmc/single_data_read.txt @@ -0,0 +1,12 @@ +# OMAP writes to FPGA +# initialize the signals +CLK=0,nWE=1,nCS=1,nOE=1,DATA=Z. +CLK=1. +CLK=0,nOE=0,nCS=0,DATA=RD_DATA. +CLK=1. +CLK=0. +CLK=1. +CLK=0,nOE=1,nCS=1,DATA=Z. +CLK=1. + + diff --git a/usrp2/gpmc/single_data_write.txt b/usrp2/gpmc/single_data_write.txt new file mode 100644 index 000000000..287e3e2c1 --- /dev/null +++ b/usrp2/gpmc/single_data_write.txt @@ -0,0 +1,10 @@ +# OMAP writes to FPGA +# initialize the signals +CLK=0,nWE=1,nCS=1,nOE=1,DATA=Z. +CLK=1. +CLK=0,nWE=0,nCS=0,DATA=WR_DATA. +CLK=1. +CLK=0,nWE=1,nCS=1,DATA=Z. +CLK=1. + + |