summaryrefslogtreecommitdiffhomepage
path: root/manufacturer/altera/cyclone10_lp/sim/src/tb.sv
diff options
context:
space:
mode:
Diffstat (limited to 'manufacturer/altera/cyclone10_lp/sim/src/tb.sv')
-rw-r--r--manufacturer/altera/cyclone10_lp/sim/src/tb.sv359
1 files changed, 359 insertions, 0 deletions
diff --git a/manufacturer/altera/cyclone10_lp/sim/src/tb.sv b/manufacturer/altera/cyclone10_lp/sim/src/tb.sv
new file mode 100644
index 0000000..9b6b3a2
--- /dev/null
+++ b/manufacturer/altera/cyclone10_lp/sim/src/tb.sv
@@ -0,0 +1,359 @@
+/*
+ * tb.sv
+ *
+ * Copyright (C) 2025 Private Island Networks Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * function: test bench for Betsy
+ *
+ * Notes:
+ *
+ * RX data is from the TB to the DUT
+ * TX data is from the DUT to the TB
+ *
+ */
+
+`timescale 1ns / 1ps
+
+//`define TEST_ETOE
+`define ML_ENGINE
+//`define TEST_CONTROLLER
+
+`define INCLUDED
+`include "../../../../../src/rgmii_params.v"
+`include "../../../../../src/ethernet_params.v"
+`undef INCLUDED
+
+module tb;
+
+ parameter NUM_PHYS = 3;
+
+ // System clocks
+ parameter PERIOD_CLK_25 = 40; // 25 MHz
+ parameter PERIOD_CLK_125 = 8; // 125 MHz
+ parameter PERIOD_CLK_250 = 4; // 250 MHz to support RGMII DDR
+
+ localparam IDLE_SHIFT = 4; // Used to multiple the specified # of idle clocks
+
+`ifdef ML_ENGINE
+ localparam RX0_CLK_CNT_START = 'd400;
+ localparam RX1_CLK_CNT_START = 'd4000_0000;
+ localparam RX2_CLK_CNT_START = 'd4000_0000;
+`else
+ localparam RX0_CLK_CNT_START = 'd400;
+ localparam RX1_CLK_CNT_START = 'd400;
+ localparam RX2_CLK_CNT_START = 'd400;
+`endif
+
+
+ // FPGA I/O
+ reg rstn;
+ reg clk_125, clk_25, clk_phy, clk_phyx2;
+ wire phy0_rx_clk, phy1_rx_clk, phy2_rx_clk;
+ reg phy0_rx_ctl, phy1_rx_ctl, phy2_rx_ctl;
+ reg [3:0] phy0_rx_d, phy1_rx_d, phy2_rx_d;
+ wire phy0_tx_clk, phy1_tx_clk, phy2_tx_clk;
+ wire phy0_tx_ctl, phy1_tx_ctl, phy2_tx_ctl;
+ wire [3:0] phy0_tx_d, phy1_tx_d, phy2_tx_d;
+ wire phy0_mdc, phy0_mdio, phy0_resetn, phy0_intn;
+ wire phy1_mdc, phy1_mdio, phy1_resetn, phy1_intn;
+ wire phy2_mdc, phy2_mdio, phy2_resetn, phy2_intn;
+ wire [2:0] led;
+
+ // sim only I/O
+ wire pclk;
+ wire pll_lock;
+ wire [2:0] phy_up;
+
+ betsy dut(
+ .rstn(rstn),
+ .clk_i(clk_25),
+ .phy0_clk(clk_25),
+ .phy1_clk(),
+
+ // Sim Only
+ .pll_locked_o(pll_lock),
+ .pclk_o(pclk),
+ .phy_up_o(phy_up),
+
+ .phy0_rstn(phy0_resetn),
+ .phy0_rx_clk(phy0_rx_clk),
+ .phy0_rx_ctl(phy0_rx_ctl),
+ .phy0_rx_d(phy0_rx_d),
+ .phy0_tx_clk(phy0_tx_clk),
+ .phy0_tx_ctl(phy0_tx_ctl),
+ .phy0_tx_d(phy0_tx_d),
+ .phy0_mdc(phy0_mdc),
+ .phy0_mdio(phy0_mdio),
+ .phy0_intn(phy0_intn),
+
+ .phy1_rstn(phy1_resetn),
+ .phy1_rx_clk(phy1_rx_clk),
+ .phy1_rx_ctl(phy1_rx_ctl),
+ .phy1_rx_d(phy1_rx_d),
+ .phy1_tx_clk(phy1_tx_clk),
+ .phy1_tx_ctl(phy1_tx_ctl),
+ .phy1_tx_d(phy1_tx_d),
+ .phy1_mdc(phy1_mdc),
+ .phy1_mdio(phy1_mdio),
+ .phy1_intn(phy1_intn),
+
+ .phy2_rstn(phy2_resetn),
+ .phy2_rx_clk(phy2_rx_clk),
+ .phy2_rx_ctl(phy2_rx_ctl),
+ .phy2_rx_d(phy2_rx_d),
+ .phy2_tx_clk(phy2_tx_clk),
+ .phy2_tx_ctl(phy2_tx_ctl),
+ .phy2_tx_d(phy2_tx_d),
+ .phy2_mdc(phy2_mdc),
+ .phy2_mdio(phy2_mdio),
+ .phy2_intn(phy2_intn),
+
+ .flash_clk(),
+ .flash_dqs(),
+ .flash_seln(),
+ .flash_d(),
+
+ .fpga_led(led)
+
+ );
+
+
+ reg [23:0] rx_clk_cnt;
+ reg [23:0] rx0_clk_cnt_start, rx1_clk_cnt_start, rx2_clk_cnt_start;
+ reg [13:0] rx0_idle_cnt, rx1_idle_cnt, rx2_idle_cnt;
+ reg [13:0] rx0_data_cnt, rx1_data_cnt, rx2_data_cnt;
+ reg rx0_last_byte, rx1_last_byte, rx2_last_byte;
+ reg [8:0] rx0_d[0:16383]; // 2**14
+ reg [8:0] rx1_d[0:16383]; //
+ reg [8:0] rx2_d[0:16383]; //
+
+
+`ifdef ML_ENGINE
+ initial begin
+ $readmemh("../data/cont_mle_w.dat",rx0_d);
+ $display("[%0t ns] ==INFO== Load memory from file for rx0: %0s.", $time, "cont_mle_w.dat");
+ end
+`endif
+
+`ifdef TEST_ETOE
+ initial begin
+ $readmemh("../data/etoe0.dat",rx0_d);
+ $display("[%0t ns] ==INFO== Load memory from file for rx0: %0s.", $time, "etoe0.dat");
+ $readmemh("../data/etoe1.dat",rx1_d);
+ $display("[%0t ns] ==INFO== Load memory from file for rx1: %0s.", $time, "etoe1.dat");
+ $readmemh("../data/etoe2.dat",rx2_d);
+ $display("[%0t ns] ==INFO== Load memory from file for rx2: %0s.", $time, "etoe2.dat");
+ end
+`endif
+
+`ifdef TEST_CONTROLLER
+ initial begin
+ $readmemh("../data/cont_query.dat",rx0_d);
+ $display("[%0t ns] ==INFO== Load memory from file for rx0: %0s.", $time, "cont_query.dat");
+ end
+`endif
+
+
+ initial begin
+ rstn = 1'b0;
+ clk_25 = 1'b0;
+ clk_125 = 1'b0;
+ clk_phy = 0;
+ clk_phyx2 = 0;
+ #25 rstn = 1'b1;
+ end
+
+ // Clocks
+ always
+ #(PERIOD_CLK_125/2) clk_125 = ~clk_125;
+
+ always
+ #(PERIOD_CLK_25/2) clk_25 = ~clk_25;
+
+ always
+ #(PERIOD_CLK_125/2) clk_phy = ~clk_phy;
+
+ always
+ #(PERIOD_CLK_250/2) clk_phyx2 = ~clk_phyx2;
+
+
+ assign #2 phy0_rx_clk = ~clk_phy; // 2.0 ns of delay
+ assign #2 phy1_rx_clk = ~clk_phy;
+ assign #2 phy2_rx_clk = ~clk_phy;
+
+ // DDR count. Use bit 0 to indicate rising edge
+ always @(posedge clk_phyx2, negedge rstn)
+ if (!rstn)
+ rx_clk_cnt <= 24'd0;
+ else
+ rx_clk_cnt <= rx_clk_cnt + 1'b1;
+
+ // PHY0
+ always @(posedge clk_phy, negedge rstn)
+ if (!rstn)
+ rx0_idle_cnt <= 14'd0;
+ else if (rx0_d[rx0_data_cnt][8])
+ rx0_idle_cnt <= rx0_d[rx0_data_cnt+1][7:0] << IDLE_SHIFT;
+
+ always @(posedge clk_phy, negedge rstn)
+ if (!rstn)
+ rx0_clk_cnt_start <= RX0_CLK_CNT_START;
+ else if (rx0_d[rx0_data_cnt][8])
+ rx0_clk_cnt_start <= rx_clk_cnt + (rx0_d[rx0_data_cnt+1][7:0] << IDLE_SHIFT) + 1'b1;
+
+ always @(negedge clk_phyx2, negedge rstn)
+ if (!rstn)
+ rx0_last_byte <= 1'b0;
+ else if (rx0_d[rx0_data_cnt][8] && rx_clk_cnt[0])
+ rx0_last_byte <= 1'b1;
+ else
+ rx0_last_byte <= 1'b0;
+
+ always @(negedge clk_phyx2, negedge rstn)
+ if (!rstn) begin
+ phy0_rx_ctl <= 1'b0;
+ phy0_rx_d <= 4'hD;
+ rx0_data_cnt <= 24'd0;
+ end
+ else if (rx_clk_cnt >= rx0_clk_cnt_start && !rx0_last_byte) begin
+ if (!rx_clk_cnt[0]) begin
+ phy0_rx_ctl <= 1'b1;
+ phy0_rx_d <= rx0_d[rx0_data_cnt][3:0];
+ end
+ else begin
+ phy0_rx_ctl <= 1'b1;
+ phy0_rx_d <= rx0_d[rx0_data_cnt][7:4];
+ rx0_data_cnt <= rx0_data_cnt + 1'b1;
+ end
+ end
+ else if (rx0_last_byte) begin
+ phy0_rx_ctl <= 1'b0;
+ phy0_rx_d <= 4'hD;
+ rx0_data_cnt <= rx0_data_cnt + 1'b1;
+ end
+ else begin
+ phy0_rx_ctl <= 1'b0;
+ phy0_rx_d <= 4'hD;
+ end
+
+
+ // PHY1
+
+ // rx1_idle_cnt: when flag is set, update idle count
+ always @(posedge clk_phy, negedge rstn)
+ if (!rstn)
+ rx1_idle_cnt <= 14'd0;
+ else if (rx1_d[rx1_data_cnt][8])
+ rx1_idle_cnt <= rx1_d[rx1_data_cnt+1][7:0] << IDLE_SHIFT;
+
+ // rx1_clk_cnt_start:
+ always @(posedge clk_phy, negedge rstn)
+ if (!rstn)
+ rx1_clk_cnt_start <= RX1_CLK_CNT_START;
+ else if (rx1_d[rx1_data_cnt][8])
+ rx1_clk_cnt_start <= rx_clk_cnt + (rx1_d[rx1_data_cnt+1][7:0] << IDLE_SHIFT) + 1'b1;
+
+
+ always @(negedge clk_phyx2, negedge rstn)
+ if (!rstn)
+ rx1_last_byte <= 1'b0;
+ else if (rx1_d[rx1_data_cnt][8] && rx_clk_cnt[0])
+ rx1_last_byte <= 1'b1;
+ else
+ rx1_last_byte <= 1'b0;
+
+ always @(negedge clk_phyx2, negedge rstn)
+ if (!rstn) begin
+ phy1_rx_ctl <= 1'b0;
+ phy1_rx_d <= 4'hD;
+ rx1_data_cnt <= 24'd0;
+ end
+ else if (rx_clk_cnt >= rx1_clk_cnt_start && !rx1_last_byte) begin
+ if (!rx_clk_cnt[0]) begin
+ phy1_rx_ctl <= 1'b1;
+ phy1_rx_d <= rx1_d[rx1_data_cnt][3:0];
+ end
+ else begin
+ phy1_rx_ctl <= 1'b1;
+ phy1_rx_d <= rx1_d[rx1_data_cnt][7:4];
+ rx1_data_cnt <= rx1_data_cnt + 1'b1;
+ end
+ end
+ else if (rx1_last_byte) begin
+ phy1_rx_ctl <= 1'b0;
+ phy1_rx_d <= 4'hD;
+ rx1_data_cnt <= rx1_data_cnt + 1'b1;
+ end
+ else begin
+ phy1_rx_ctl <= 1'b0;
+ phy1_rx_d <= 4'hD;
+ end
+
+ // PHY2
+
+ // rx1_idle_cnt: when flag is set, update idle count
+ always @(posedge clk_phy, negedge rstn)
+ if (!rstn)
+ rx2_idle_cnt <= 14'd0;
+ else if (rx2_d[rx2_data_cnt][8])
+ rx2_idle_cnt <= rx2_d[rx2_data_cnt+1][7:0] << IDLE_SHIFT;
+
+ always @(posedge clk_phy, negedge rstn)
+ if (!rstn)
+ rx2_clk_cnt_start <= RX2_CLK_CNT_START;
+ else if (rx2_d[rx2_data_cnt][8])
+ rx2_clk_cnt_start <= rx_clk_cnt + (rx2_d[rx2_data_cnt+1][7:0] << IDLE_SHIFT) + 1'b1;
+
+ //
+ always @(negedge clk_phyx2, negedge rstn)
+ if (!rstn)
+ rx2_last_byte <= 1'b0;
+ else if (rx2_d[rx2_data_cnt][8] && rx_clk_cnt[0])
+ rx2_last_byte <= 1'b1;
+ else
+ rx2_last_byte <= 1'b0;
+
+
+ always @(negedge clk_phyx2, negedge rstn)
+ if (!rstn) begin
+ phy2_rx_ctl <= 1'b0;
+ phy2_rx_d <= 4'hD;
+ rx2_data_cnt <= 24'd0;
+ end
+ else if (rx_clk_cnt >= rx2_clk_cnt_start && !rx2_last_byte) begin
+ if (!rx_clk_cnt[0]) begin
+ phy2_rx_ctl <= 1'b1;
+ phy2_rx_d <= rx2_d[rx2_data_cnt][3:0];
+ end
+ else begin
+ phy2_rx_ctl <= 1'b1;
+ phy2_rx_d <= rx2_d[rx2_data_cnt][7:4];
+ rx2_data_cnt <= rx2_data_cnt + 1'b1;
+ end
+ end
+ else if (rx2_last_byte) begin
+ phy2_rx_ctl <= 1'b0;
+ phy2_rx_d <= 4'hD;
+ rx2_data_cnt <= rx2_data_cnt + 1'b1;
+ end
+ else begin
+ phy2_rx_ctl <= 1'b0;
+ phy2_rx_d <= 4'hD;
+ end
+
+
+endmodule
+
+

Highly Recommended Verilog Books