Skip to content

Commit

Permalink
Merge branch 'mailboxed' into 'master'
Browse files Browse the repository at this point in the history
Encapsulated mailbox as verilog module

Capture the MMC pseudo-SPI mailbox functionality into a module for easier deployment/integration/simulation.

See merge request hdl-libraries/bedrock!166
  • Loading branch information
ldoolitt committed Jan 29, 2024
2 parents cc3fa4b + 2a13772 commit b8ea502
Show file tree
Hide file tree
Showing 5 changed files with 408 additions and 58 deletions.
92 changes: 36 additions & 56 deletions board_support/marblemini/marble_base.v
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ module marble_base (
parameter USE_I2CBRIDGE = 1;
parameter MMC_CTRACE = 1;
parameter misc_config_default = 0;
parameter default_enable_rx = 1;

`ifdef VERILATOR
parameter [31:0] ip = {8'd192, 8'd168, 8'd7, 8'd4}; // 192.168.7.4
Expand All @@ -105,72 +106,51 @@ parameter [47:0] mac = 48'h12555500032d;
wire tx_clk = vgmii_tx_clk;
wire rx_clk = vgmii_rx_clk;

// Configuration port
wire config_clk = tx_clk;
wire config_w, config_r;
wire [7:0] config_a;
wire [7:0] config_d;
wire [7:0] spi_return;
wire [3:0] spi_pins_debug;
spi_gate spi(
.MOSI(MOSI), .SCLK(SCLK), .CSB(CSB), .MISO(MISO),
.config_clk(config_clk), .config_w(config_w), .config_r(config_r),
.config_a(config_a), .config_d(config_d), .tx_data(spi_return),
.spi_pins_debug(spi_pins_debug)
);

// Map generic configuration bus to application
// 16-bit SPI word semantics:
// 0 0 0 1 a a a a d d d d d d d d -> set MAC/IP config[a] = D
// 0 0 1 0 0 0 0 0 x x x x x x x V -> set enable_rx to V
// 0 0 1 0 0 0 1 0 x d d d d d d d -> set 7-bit mailbox page selector
// 0 0 1 1 a a a a d d d d d d d d -> set UDP port config[a] = D
// 0 1 0 0 a a a a d d d d d d d d -> mailbox read
// 0 1 0 1 a a a a d d d d d d d d -> mailbox write
parameter default_enable_rx = 1;
reg enable_rx=default_enable_rx; // special case initialization
reg [6:0] mbox_page=0;
always @(posedge config_clk) begin
if (config_w && (config_a == 8'h20)) enable_rx <= config_d[0];
if (config_w && (config_a == 8'h22)) mbox_page <= config_d[6:0];
end
wire config_s = config_w && (config_a[7:4] == 1);
wire config_p = config_w && (config_a[7:4] == 3);
wire config_mr = config_r && (config_a[7:4] == 4);
wire config_mw = config_w && (config_a[7:4] == 5);
wire [10:0] mbox_a = {mbox_page, config_a[3:0]};
wire enable_rx;
wire lb_mbox_sel = lb_addr[23:20] == 2;
wire lb_mbox_wen = lb_mbox_sel & lb_write;
wire lb_control_strobe;
wire [7:0] mbox_out2;
wire config_s, config_p;
wire [7:0] config_a, config_d;

// Forward declarations
wire [1:0] led_user_mode;
wire l1, l2;
// Local bus
assign lb_clk = tx_clk;
//wire [23:0] lb_addr;
wire [31:0] lb_data_muxed;
wire lb_control_strobe, lb_control_rd, lb_control_rd_valid;
assign lb_strobe = lb_control_strobe;
assign lb_rd = lb_control_rd;
assign lb_rd_valid = lb_control_rd_valid;
wire config_clk = tx_clk;
assign lb_write = lb_control_strobe & ~lb_control_rd;
wire [3:0] spi_pins_debug;
wire lb_control_rd, lb_control_rd_valid;
assign lb_rd_valid = lb_control_rd_valid;
assign lb_rd = lb_control_rd;

// Mailbox
wire error;
wire lb_mbox_sel = lb_addr[23:20] == 2;
wire lb_mbox_wen = lb_mbox_sel & lb_write;
// Local bus read-enable is a bit fragile, since we need to
// match the latency configured deep inside Packet Badger's mem_gateway.
reg lb_mbox_ren=0;
always @(posedge lb_clk) begin
lb_mbox_ren <= lb_mbox_sel & lb_control_strobe & lb_control_rd;
end
wire [7:0] mbox_out1, mbox_out2;
fake_dpram #(.aw(11), .dw(8)) xmem (
.clk(lb_clk), // must be the same as config_clk
.addr1(mbox_a), .din1(config_d), .dout1(mbox_out1), .wen1(config_mw), .ren1(config_mr),
.addr2(lb_addr[10:0]), .din2(lb_data_out[7:0]), .dout2(mbox_out2), .wen2(lb_mbox_wen), .ren2(lb_mbox_ren),
.error(error)
mmc_mailbox #(
.DEFAULT_ENABLE_RX(default_enable_rx)
) mailbox_i (
.clk(config_clk), // input
// localbus
.lb_addr(lb_addr[10:0]), // input [10:0]
.lb_din(lb_data_out[7:0]), // input [7:0]
.lb_dout(mbox_out2), // output [7:0]
.lb_write(lb_write), // input
.lb_control_strobe(lb_control_strobe), // input
// SPI PHY
.sck(SCLK), // input
.ncs(CSB), // input
.pico(MOSI), // input
.poci(MISO), // output
// Config pins for badger (rtefi) interface
.config_s(config_s), // output
.config_p(config_p), // output
.config_a(config_a), // output [7:0]
.config_d(config_d), // output [7:0]
// Special pins
.enable_rx(enable_rx), // output
.spi_pins_debug(spi_pins_debug) // {MISO, din, sclk_d1, csb_d1};
);
assign spi_return = mbox_out1; // data sent back to MMC vis SPI

// Debugging hooks
wire ibadge_stb, obadge_stb;
Expand Down
8 changes: 6 additions & 2 deletions projects/test_marble_family/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ CFLAGS_udp-vpi.o = $(VPI_CFLAGS) -D_POSIX_C_SOURCE=200809L
CFLAGS_udp_model.o = $(VPI_CFLAGS)
udp-vpi.vpi: udp_model.o

# =====
# MMC mailbox self-checking testbench
mmc_mailbox_tb: mmc_mailbox.v $(HOMELESS_DIR)/fake_dpram.v $(DSP_DIR)/dpram.v $(BADGER_DIR)/tests/spi_gate.v $(PERIPH_DRIVERS_DIR)/spi_master.v

# =====
# subset that is interesting to test live on network
AD5662_V = ad5662_lock.v pps_lock.v pps_loop_filter.v ad5662.v
Expand All @@ -99,9 +103,9 @@ net_slave_run: lb_marble_slave_tb udp-vpi.vpi
net_slave_check: lb_marble_slave_tb udp-vpi.vpi read_trx.dat
$(VVP) $< +udp_port=8030 2>/dev/null & sleep 1 && $(PYTHON) testcase.py -a localhost -p 0 --sim --ramtest --stop --rlen=34

# =====
# syntax-check only, no actual test bench code
MARBLE_BASE_V = marble_base.v packet_categorize.v data_xdomain.v flag_xdomain.v $(RTEFI_V) activity.v base_rx_mac.v spi_gate.v mac_compat_dpram.v ctrace.v $(LB_MARBLE_SLAVE_V) $(FREQ_DEMO_V)
MARBLE_BASE_V = marble_base.v packet_categorize.v data_xdomain.v flag_xdomain.v $(RTEFI_V) activity.v base_rx_mac.v spi_gate.v mac_compat_dpram.v ctrace.v $(LB_MARBLE_SLAVE_V) $(FREQ_DEMO_V) mmc_mailbox.v

marble_base_tb: $(MARBLE_BASE_V)
VFLAGS_marble_base_tb =

Expand Down
32 changes: 32 additions & 0 deletions projects/test_marble_family/mmc_mailbox.gtkw
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
[timestart] 0
[size] 1000 600
[pos] -1 -1
*-14.720415 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[sst_width] 214
[signals_width] 150
[sst_expanded] 1
[sst_vpaned_height] 152
@28
mmc_mailbox_tb.sck
mmc_mailbox_tb.ncs
mmc_mailbox_tb.pico
mmc_mailbox_tb.poci
@22
mmc_mailbox_tb.spi_addr[7:0]
mmc_mailbox_tb.mac_in[47:0]
@28
mmc_mailbox_tb.mac_valid
@22
mmc_mailbox_tb.mac_out[47:0]
mmc_mailbox_tb.ip_in[31:0]
@28
mmc_mailbox_tb.ip_valid
@22
mmc_mailbox_tb.ip_out[31:0]
mmc_mailbox_tb.gitid_in[31:0]
mmc_mailbox_tb.gitid_out[31:0]
mmc_mailbox_tb.hash_out[31:0]
@28
mmc_mailbox_tb.pass
[pattern_trace] 1
[pattern_trace] 0
109 changes: 109 additions & 0 deletions projects/test_marble_family/mmc_mailbox.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/* An encapsulation of the FPGA (responder) side of the Marble
* pseudo-SPI mailbox interface with the MMC.
*/

module mmc_mailbox #(
parameter [0:0] DEFAULT_ENABLE_RX = 1
)(
input clk,
// localbus
input [10:0] lb_addr, // 2kB total memory space
input [7:0] lb_din, // Data in
output [7:0] lb_dout, // Data out
input lb_write, // Write operation
input lb_control_strobe, // Bus access strobe
// SPI PHY
input sck, // SCK
input ncs, // formerly NSS
input pico, // formerly MOSI
output poci, // formerly MISO
// Config pins for badger (rtefi) interface
output config_s,
output config_p,
output [7:0] config_a,
output [7:0] config_d,
`ifdef SIMULATE
output [3:0] a_hi,
output [3:0] a_lo,
`endif
// Special pins
output enable_rx, // Controlled via special mailbox commands
output [3:0] spi_pins_debug // {MISO, din, sclk_d1, csb_d1};
);

// SPI Naming convention: https://www.sparkfun.com/spi_signal_names

// Mailbox pseudo-SPI protocol
// 16-bit SPI word semantics:
// 0 0 0 1 a a a a d d d d d d d d -> set MAC/IP config[a] = D
// 0 0 1 0 0 0 0 0 x x x x x x x V -> set enable_rx to V
// 0 0 1 0 0 0 1 0 x d d d d d d d -> set 7-bit mailbox page selector
// 0 0 1 1 a a a a d d d d d d d d -> set UDP port config[a] = D
// 0 1 0 0 a a a a d d d d d d d d -> mailbox read
// 0 1 0 1 a a a a d d d d d d d d -> mailbox write

// Configuration port
wire config_w, config_r;
`ifndef SIMULATE
wire [3:0] a_hi;
wire [3:0] a_lo;
`endif
assign a_lo = config_a[3:0];
assign a_hi = config_a[7:4];
wire [7:0] spi_return;
spi_gate spi (
.SCLK(sck),
.CSB(ncs),
.MOSI(pico), // input
.MISO(poci), // output
.config_clk(clk), // input
.config_w(config_w), // output
.config_r(config_r), // output
.config_a(config_a), // output [7:0]
.config_d(config_d), // output [7:0]
.tx_data(spi_return), // input [7:0]
.spi_pins_debug(spi_pins_debug) // output [3:0]
);

reg enable_rx_r=DEFAULT_ENABLE_RX; // special case initialization
assign enable_rx = enable_rx_r;
reg [6:0] mbox_page=0;
always @(posedge clk) begin
// Enable Rx
if (config_w && (config_a == 8'h20)) enable_rx_r <= config_d[0];
// Mailbox page select
if (config_w && (config_a == 8'h22)) begin
//$display("MB: select page %d", config_d[6:0]);
mbox_page <= config_d[6:0];
end
end
wire config_mr = config_r && (a_hi == 4);
wire config_mw = config_w && (a_hi == 5);
assign config_s = config_w && (a_hi == 1);
assign config_p = config_w && (a_hi == 3);
wire [10:0] mbox_a = {mbox_page, a_lo};

wire error; // Reports bus contention. Do I want to do anything with this?
wire lb_mbox_wen = lb_write;
reg lb_mbox_ren=0;
always @(posedge clk) begin
lb_mbox_ren <= lb_control_strobe & ~lb_write;
end
wire [7:0] mbox_out1;
fake_dpram #(.aw(11), .dw(8)) xmem (
.clk(clk), // must be the same as config_clk
.addr1(mbox_a),
.din1(config_d),
.dout1(mbox_out1),
.wen1(config_mw),
.ren1(config_mr),
.addr2(lb_addr),
.din2(lb_din),
.dout2(lb_dout),
.wen2(lb_mbox_wen),
.ren2(lb_mbox_ren),
.error(error)
);
assign spi_return = mbox_out1; // data sent back to MMC vis SPI

endmodule
Loading

0 comments on commit b8ea502

Please sign in to comment.