/* * 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