summaryrefslogtreecommitdiffstats
path: root/usrp2/gpmc
diff options
context:
space:
mode:
authorMatt Ettus <matt@ettus.com>2010-11-10 11:29:25 -0800
committerMatt Ettus <matt@ettus.com>2010-11-10 11:29:25 -0800
commitc7be879f6156c219de331df232d1b55ae539f5dd (patch)
treebb2e8012cf7aa54cfc23b4a99e067fd72a5b80e5 /usrp2/gpmc
parent98a4130707cf7cad9597b65504211343138391ad (diff)
parent9cd8652b42b5afcba67ef0475e5681b951fe0bdc (diff)
downloaduhd-c7be879f6156c219de331df232d1b55ae539f5dd.tar.gz
uhd-c7be879f6156c219de331df232d1b55ae539f5dd.tar.bz2
uhd-c7be879f6156c219de331df232d1b55ae539f5dd.zip
Merge branch 'u1e' into merge_u1e
* u1e: (130 commits) invert led signals because they are active low duh allow for CS to rise before, at the same time, or after OE better debug pins watch the ethernet chip select on our debug bus fix timing issue on DAC outputs with rev 2. This puts the whole system on a 90 degree phase shift send all gpmc signals to mictor updated pins to match rev2, removed dip switch, etc. seems to compile ok. pins are different on rev2 fixed makefile to compile with our new system add register to tell host about compatibility level and which image we are using move declaration to make loopback compile no need for protocol headers since we're not doing ethernet match the signal names in this design debug pins cleanup properly integrate the new tx chain catch up with tx_policy attach run_tx and run_rx to leds connect atr delay the q channel to make the channels line up on the AD9862 ... Conflicts: usrp2/control_lib/Makefile.srcs
Diffstat (limited to 'usrp2/gpmc')
-rw-r--r--usrp2/gpmc/.gitignore2
-rw-r--r--usrp2/gpmc/Makefile.srcs20
-rw-r--r--usrp2/gpmc/burst_data_write.txt16
-rw-r--r--usrp2/gpmc/dbsm.v80
-rw-r--r--usrp2/gpmc/edge_sync.v22
-rw-r--r--usrp2/gpmc/fifo_to_gpmc_async.v37
-rw-r--r--usrp2/gpmc/fifo_to_gpmc_sync.v26
-rw-r--r--usrp2/gpmc/fifo_watcher.v56
-rw-r--r--usrp2/gpmc/gpmc_async.v130
-rw-r--r--usrp2/gpmc/gpmc_sync.v108
-rw-r--r--usrp2/gpmc/gpmc_to_fifo_async.v68
-rw-r--r--usrp2/gpmc/gpmc_to_fifo_sync.v57
-rw-r--r--usrp2/gpmc/gpmc_wb.v57
-rwxr-xr-xusrp2/gpmc/make_timing_diag6
-rw-r--r--usrp2/gpmc/ram_to_fifo.v46
-rw-r--r--usrp2/gpmc/single_data_read.txt12
-rw-r--r--usrp2/gpmc/single_data_write.txt10
17 files changed, 753 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/Makefile.srcs b/usrp2/gpmc/Makefile.srcs
new file mode 100644
index 000000000..bff6ae3e0
--- /dev/null
+++ b/usrp2/gpmc/Makefile.srcs
@@ -0,0 +1,20 @@
+#
+# Copyright 2010 Ettus Research LLC
+#
+
+##################################################
+# SERDES Sources
+##################################################
+GPMC_SRCS = $(abspath $(addprefix $(BASE_DIR)/../gpmc/, \
+dbsm.v \
+edge_sync.v \
+fifo_to_gpmc_async.v \
+fifo_to_gpmc_sync.v \
+fifo_watcher.v \
+gpmc_async.v \
+gpmc_sync.v \
+gpmc_to_fifo_async.v \
+gpmc_to_fifo_sync.v \
+gpmc_wb.v \
+ram_to_fifo.v \
+))
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..cf8b6e861
--- /dev/null
+++ b/usrp2/gpmc/fifo_to_gpmc_async.v
@@ -0,0 +1,37 @@
+
+// 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 [2:0] cs_del, oe_del;
+ reg [15:0] counter;
+
+ always @(posedge clk)
+ if(reset)
+ begin
+ cs_del <= 3'b11;
+ oe_del <= 3'b11;
+ end
+ else
+ begin
+ cs_del <= { cs_del[1:0], EM_NCS };
+ oe_del <= { oe_del[1:0], EM_NOE };
+ end
+
+ wire do_read = ( (~cs_del[1] | ~cs_del[2]) & (oe_del[1:0] == 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..fe4e35de3
--- /dev/null
+++ b/usrp2/gpmc/fifo_watcher.v
@@ -0,0 +1,56 @@
+
+
+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,
+ output [31:0] debug);
+
+ 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;
+ assign debug = 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..23bad56ae
--- /dev/null
+++ b/usrp2/gpmc/gpmc_async.v
@@ -0,0 +1,130 @@
+//////////////////////////////////////////////////////////////////////////////////
+
+module gpmc_async
+ #(parameter TXFIFOSIZE = 11, parameter RXFIFOSIZE = 11)
+ (// 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, input clear_tx, input clear_rx,
+ 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 | clear_tx | clear_rx)
+ 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;
+ wire [35:0] tx36_data;
+ wire tx36_src_rdy, tx36_dst_rdy;
+
+ 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), .clear(clear_tx),
+ .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(clear_tx),
+ .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 #(.LE(1)) f19_to_f36 // Little endian because ARM is LE
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_tx),
+ .f19_datain({1'b0,tx18b_data}), .f19_src_rdy_i(tx18b_src_rdy), .f19_dst_rdy_o(tx18b_dst_rdy),
+ .f36_dataout(tx36_data), .f36_src_rdy_o(tx36_src_rdy), .f36_dst_rdy_i(tx36_dst_rdy));
+
+ fifo_cascade #(.WIDTH(36), .SIZE(TXFIFOSIZE)) tx_fifo36
+ (.clk(wb_clk), .reset(wb_rst), .clear(clear_tx),
+ .datain(tx36_data), .src_rdy_i(tx36_src_rdy), .dst_rdy_o(tx36_dst_rdy),
+ .dataout(tx_data_o), .src_rdy_o(tx_src_rdy_o), .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;
+ wire [35:0] rx36_data;
+ wire rx36_src_rdy, rx36_dst_rdy;
+ wire dummy;
+
+ fifo_cascade #(.WIDTH(36), .SIZE(RXFIFOSIZE)) rx_fifo36
+ (.clk(wb_clk), .reset(wb_rst), .clear(clear_rx),
+ .datain(rx_data_i), .src_rdy_i(rx_src_rdy_i), .dst_rdy_o(rx_dst_rdy_o),
+ .dataout(rx36_data), .src_rdy_o(rx36_src_rdy), .dst_rdy_i(rx36_dst_rdy));
+
+ fifo36_to_fifo19 #(.LE(1)) f36_to_f19 // Little endian because ARM is LE
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
+ .f36_datain(rx36_data), .f36_src_rdy_i(rx36_src_rdy), .f36_dst_rdy_o(rx36_dst_rdy),
+ .f19_dataout({dummy,rx18_data}), .f19_src_rdy_o(rx18_src_rdy), .f19_dst_rdy_i(rx18_dst_rdy) );
+
+ fifo_cascade #(.WIDTH(18), .SIZE(12)) rx_fifo
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
+ .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(clear_rx),
+ .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) );
+
+ wire [31:0] pkt_count;
+
+ fifo_watcher fifo_watcher
+ (.clk(fifo_clk), .reset(fifo_rst), .clear(clear_rx),
+ .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),
+ .debug(pkt_count));
+
+ // ////////////////////////////////////////////
+ // 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 = pkt_count;
+
+endmodule // gpmc_async
diff --git a/usrp2/gpmc/gpmc_sync.v b/usrp2/gpmc/gpmc_sync.v
new file mode 100644
index 000000000..61c54a793
--- /dev/null
+++ b/usrp2/gpmc/gpmc_sync.v
@@ -0,0 +1,108 @@
+//////////////////////////////////////////////////////////////////////////////////
+
+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 #(.LE(1)) f19_to_f36 // Little endian because ARM is LE
+ (.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;
+ wire dummy;
+
+ fifo36_to_fifo19 #(.LE(1)) f36_to_f19 // Little endian because ARM is LE
+ (.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),
+ .f19_dataout({dummy,rx18_data}), .f19_src_rdy_o(rx18_src_rdy), .f19_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..55c0cef50
--- /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, input clear,
+ 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 | clear)
+ 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 | clear)
+ counter <= 0;
+ else if(do_write)
+ if(last_write)
+ counter <= 0;
+ else
+ counter <= counter + 1;
+
+ always @(posedge fifo_clk)
+ if(fifo_rst | clear)
+ fifo_ready <= 0;
+ else
+ fifo_ready <= /* first_write & */ (fifo_space > 16'd1023);
+
+ always @(posedge fifo_clk)
+ if(fifo_rst | clear)
+ 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.
+
+