diff options
Diffstat (limited to 'usrp2/gpmc')
-rw-r--r-- | usrp2/gpmc/dbsm.v | 80 | ||||
-rw-r--r-- | usrp2/gpmc/edge_sync.v | 22 | ||||
-rw-r--r-- | usrp2/gpmc/gpmc.v | 119 |
3 files changed, 221 insertions, 0 deletions
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/gpmc.v b/usrp2/gpmc/gpmc.v new file mode 100644 index 000000000..cf1357232 --- /dev/null +++ b/usrp2/gpmc/gpmc.v @@ -0,0 +1,119 @@ +////////////////////////////////////////////////////////////////////////////////// + +module gpmc + (// GPMC signals + 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, + + // Wishbone signals + 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, + + // RAM Interface signals + input ram_clk, + input read_en, input [8:0] read_addr, output [31:0] read_data, output read_ready, input read_done, + input write_en, input [8:0] write_addr, input [31:0] write_data, output write_ready, input write_done, + output [31:0] debug + ); + + wire EM_output_enable = (~EM_NOE & (~EM_NCS4 | ~EM_NCS6)); + wire [15:0] EM_D_ram; + wire [15:0] EM_D_wb; + + assign EM_D = ~EM_output_enable ? 16'bz : ~EM_NCS4 ? EM_D_ram : EM_D_wb; + + // CS4 is RAM_2PORT for high-speed data + // Writes go into one RAM, reads come from the other + + + // //////////////////////////////////////////// + // Write path + wire read_sel_in, write_sel_in, clear_in; + wire write_done_in; + + edge_sync #(.POSEDGE(0)) + edge_sync_wdi(.clk(wb_clk), .rst(wb_rst), + .sig(~EM_NCS4 & ~EM_NWE & (EM_A == 10'h3FF)), .trig(write_done_in)); + + ram_2port_mixed_width buffer_in + (.clk16(wb_clk), .en16(~EM_NCS4), .we16(~EM_NWE), .addr16({write_sel_in,EM_A}), .di16(EM_D), .do16(), + .clk32(ram_clk), .en32(read_en), .we32(0), .addr32({read_sel_in,read_addr}), .di32(0), .do32(read_data)); + + dbsm dbsm_in(.clk(wb_clk), .reset(wb_rst), .clear(clear_in), + .read_sel(read_sel_in), .read_ready(read_ready), .read_done(read_done), + .write_sel(write_sel_in), .write_ready(tx_have_space), .write_done(write_done_in)); + + + + // //////////////////////////////////////////// + // Read path + wire read_sel_out, write_sel_out, clear_out; + wire read_done_out; + + edge_sync #(.POSEDGE(0)) + edge_sync_rdo(.clk(wb_clk), .rst(wb_rst), + .sig(~EM_NCS4 & ~EM_NOE & (EM_A == 10'h3FF)), .trig(read_done_out)); + + ram_2port_mixed_width buffer_out + (.clk16(wb_clk), .en16(~EM_NCS4), .we16(0), .addr16({read_sel_out,EM_A}), .di16(0), .do16(EM_D_ram), + .clk32(ram_clk), .en32(write_en), .we32(write_en), .addr32({write_sel_out,write_addr}), .di32(write_data), .do32()); + + dbsm dbsm_out(.clk(wb_clk), .reset(wb_rst), .clear(clear_out), + .read_sel(read_sel_out), .read_ready(rx_have_data), .read_done(read_done_out), + .write_sel(write_sel_out), .write_ready(write_ready), .write_done(write_done)); + + + assign debug = { { 2'b00, write_done_in, write_sel_in, read_en, read_sel_in, read_ready, read_done}, + { 2'b00, read_sel_out, write_en, write_sel_out, read_done_out, write_ready, write_done }, + { 8'd0 }, + { 8'd0 } }; + + // CS6 is Control, Wishbone bus bridge (wb master) + // Sync version + 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_NCS6 }; + 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; + wb_sel_o <= ~EM_NBE; + end + + reg [15:0] EM_D_wb_reg; + always @(posedge wb_clk) + if(wb_ack_i) + EM_D_wb_reg <= wb_dat_miso; + + assign EM_D_wb = wb_ack_i ? wb_dat_miso : EM_D_wb_reg; + + 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; + + 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 |