diff options
Diffstat (limited to 'sim/src/tb.sv')
| -rw-r--r-- | sim/src/tb.sv | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/sim/src/tb.sv b/sim/src/tb.sv new file mode 100644 index 0000000..107df8e --- /dev/null +++ b/sim/src/tb.sv @@ -0,0 +1,188 @@ +/* + * tb.sv + * + * Copyright (C) 2026 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 ML Module Agilex + * + * Notes: + * + * RX data is from the TB to the DUT (ML Module) + * TX data is from the DUT to the TB + * + */ + +`timescale 1ns / 1ps + +module tb; + + // 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 multiply the specified # of idle clocks + + localparam RX_CLK_CNT_START = 'd20; // clocks to wait after PLL Lock + + // FPGA I/O + reg rstn; + reg clk_125, clk_25, clk_250; + wire rgmii_rx_clk; + reg rgmii_rx_ctl; + reg [3:0] rgmii_rx_d; + wire rgmii_tx_clk; + wire rgmii_tx_ctl; + wire [3:0] rgmii_tx_d; + wire rgmii_mdc, rgmii_mdio, rgmii_resetn, rgmii_intn; + wire [2:0] led; + + // sim only I/O + wire pclk; + wire pll_lock; + wire [2:0] phy_up; + + ml_module_agilex dut( + .rstn(rstn), + .clk_i(clk_25), + + // Sim Only + .pll_locked_o(pll_lock), + .pclk(pclk), + + .rgmii_rx_clk(rgmii_rx_clk), + .rgmii_rx_ctl(rgmii_rx_ctl), + .rgmii_rx_d(rgmii_rx_d), + .rgmii_tx_clk(rgmii_tx_clk), + .rgmii_tx_ctl(rgmii_tx_ctl), + .rgmii_tx_d(rgmii_tx_d), + .rgmii_mdc(rgmii_mdc), + .rgmii_mdio(rgmii_mdio), + .rgmii_intn(rgmii_intn), + .rgmii_gpio(), + + .flash_clk(), + .flash_dqs(), + .flash_seln(), + .flash_d(), + + .fpga_led(led) + + ); + + assign #2 rgmii_rx_clk = !clk_125; // Provide 2ns clock skew similar to what an Ethernet PHY supports + + + reg [23:0] rx_clk_cnt; + reg [23:0] rx_clk_cnt_start; + reg [13:0] rx_idle_cnt; + reg [13:0] rx_data_cnt; + reg rx_last_byte; + reg [8:0] rx_d[0:16383]; // 2**14 + reg [8:0] rx_d_byte; + + +initial begin + $readmemh("../data/ml.dat",rx_d); + $display("[%0t ns] ==INFO== Load memory from file for rx: %0s.", $time, "ml.dat"); +end + + initial begin + rstn = 1'b0; + clk_25 = 1'b0; + clk_125 = 1'b0; + clk_250 = 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_250/2) clk_250 = ~clk_250; + + + // DDR clk count. Use bit 0 to indicate rising edge + always @(posedge clk_250, negedge rstn) + if (!rstn) + rx_clk_cnt <= 24'd0; + else if (pll_lock) + rx_clk_cnt <= rx_clk_cnt + 1'b1; + + // Capture the number of idle clocks before next packet (for debugging) + always @(posedge clk_125, negedge rstn) + if (!rstn) + rx_idle_cnt <= 14'd0; + else if (rx_d[rx_data_cnt][8]) + rx_idle_cnt <= rx_d[rx_data_cnt+1][7:0] << IDLE_SHIFT; + + // Counter to determine next packet to transmit into the DUT (receive path) + always @(posedge clk_125, negedge rstn) + if (!rstn) + rx_clk_cnt_start <= RX_CLK_CNT_START; + else if (rx_d[rx_data_cnt][8]) + rx_clk_cnt_start <= rx_clk_cnt + (rx_d[rx_data_cnt+1][7:0] << IDLE_SHIFT) + 1'b1; + + // The MSB bit (9th bit) of the data file denotes the last byte to transmit into the DUT + always @(negedge clk_250, negedge rstn) + if (!rstn) + rx_last_byte <= 1'b0; + else if (rx_d[rx_data_cnt][8] && rx_clk_cnt[0]) + rx_last_byte <= 1'b1; + else + rx_last_byte <= 1'b0; + + // rx_d_byte helps with debugging + always @(negedge clk_250, negedge rstn) + if (!rstn) + rx_d_byte <= 9'd0; + else + rx_d_byte <= rx_d[rx_data_cnt]; + + // RX data logic. Refer to RGMII spec for info on use of CTL bits. + always @(negedge clk_250, negedge rstn) + if (!rstn) begin + rgmii_rx_ctl <= 1'b0; + rgmii_rx_d <= 4'hD; + rx_data_cnt <= 24'd0; + end + else if (rx_clk_cnt >= rx_clk_cnt_start && !rx_last_byte) begin + if (!rx_clk_cnt[0]) begin + rgmii_rx_ctl <= 1'b1; + rgmii_rx_d <= rx_d[rx_data_cnt][3:0]; + end + else begin + rgmii_rx_ctl <= 1'b1; + rgmii_rx_d <= rx_d[rx_data_cnt][7:4]; + rx_data_cnt <= rx_data_cnt + 1'b1; + end + end + else if (rx_last_byte) begin + rgmii_rx_ctl <= 1'b0; + rgmii_rx_d <= 4'hD; + rx_data_cnt <= rx_data_cnt + 1'b1; + end + else begin + rgmii_rx_ctl <= 1'b0; + rgmii_rx_d <= 4'hD; + end + +endmodule + + |



