gateware

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 64639a7d709b6d705bb20a247935b1d320b04bdd
parent 112785d363e382214bfff21d6d064884d1781406
Author: Brian Swetland <swetland@frotz.net>
Date:   Thu, 23 Jan 2020 19:45:33 -0800

ethernet: add rgmii tx and a debug mode for rx

Diffstat:
Mhdl/ethernet/eth_rgmii_rx.sv | 40++++++++++++++++++++++++++++++++++++++++
Ahdl/ethernet/eth_rgmii_tx.sv | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahdl/ethernet/eth_rgmii_tx_glue_ecp5.sv | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 267 insertions(+), 0 deletions(-)

diff --git a/hdl/ethernet/eth_rgmii_rx.sv b/hdl/ethernet/eth_rgmii_rx.sv @@ -49,6 +49,45 @@ eth_rgmii_rx_glue glue ( .rx_data(rx_data) ); +// RAWMODE disables all processing and blindly passes packet +// data bytes though. sop will be active for the first byte +// of the preamble and eop will become active for one cycle +// after the last byte of the FCS. crc_ok will always be 0. +// +// `define ETH_RGMII_RX_RAW_MODE + +`ifdef ETH_RGMII_RX_RAW_MODE +reg next_sop; +reg next_eop; +reg next_valid; + +always_comb begin + next_sop = 0; + next_eop = 0; + next_valid = valid; + + if (rx_dv) begin + if (~valid) begin + next_sop = 1; + next_valid = 1; + end + end else begin + if (valid) begin + next_eop = 1; + next_valid = 0; + end + end +end + +always_ff @(posedge rx_clk) begin + sop <= next_sop; + eop <= next_eop; + data <= rx_data; + valid <= next_valid; +end + +`else + wire [31:0]crc; localparam IDLE = 2'd0; @@ -124,5 +163,6 @@ eth_crc32_8 crc32( .din(rx_data), .crc(crc) ); +`endif endmodule diff --git a/hdl/ethernet/eth_rgmii_tx.sv b/hdl/ethernet/eth_rgmii_tx.sv @@ -0,0 +1,145 @@ +// Copyright 2020 Brian Swetland <swetland@frotz.net> +// Licensed under the Apache License, Version 2.0. + +`default_nettype none + +module eth_rgmii_tx ( + input wire tx_clk, + + output wire pin_tx_clk, + output wire pin_tx_en, + output wire [3:0]pin_tx_data, + + // strobe to request start + // data will be accepted 8-20 clocks later + // (depending on how soon after last packet finished) + input wire start, + + // asserted to accept a byte + output reg ready = 0, + + // assert when a byte is ready to transmit + // once data transmission begins, deassertion will end the packet + input wire valid, + + // assert to cease transmitting and ensure packet is invalid + // (do not complete FCS computation) + input wire error, + + // byte to transmit + input wire [7:0]data +); + +localparam IDLE = 3'd0; +localparam PREAMBLE = 3'd1; +localparam PACKET = 3'd2; +localparam CRC1 = 3'd3; +localparam CRC2 = 3'd4; +localparam CRC3 = 3'd5; +localparam CRC4 = 3'd6; +localparam WAIT = 3'd7; + +reg [2:0]state = IDLE; +reg tx_en = 0; +reg tx_err = 0; +reg [7:0]tx_data = 8'd0; +reg [3:0]count = 4'd0; + +reg [2:0]next_state; +reg [3:0]next_count; +reg next_tx_en; +reg next_tx_err; +reg [7:0]next_tx_data; +reg next_ready; + +wire [3:0]count_sub1; +wire count_done; +assign { count_done, count_sub1 } = { 1'b0, count } - 5'd1; + +reg crc_en; +wire [31:0]crc; + +always_comb begin + next_state = state; + next_count = count; + next_tx_data = tx_data; + next_tx_en = tx_en; + next_tx_err = tx_err; + next_ready = 1'b0; + + case (state) + IDLE: if (start) begin + next_state = PREAMBLE; + next_count = 4'd6; + next_tx_data = 8'h55; + next_tx_en = 1'b1; + end + PREAMBLE: if (count_done) begin + next_state = PACKET; + next_tx_data = 8'hD5; + next_ready = 1'b1; + next_count = 4'd11; // preload IPG count + end else begin + next_count = count_sub1; + end + PACKET: if (valid) begin + next_ready = 1'b1; + next_tx_data = data; + end else begin + next_state = CRC1; + next_tx_data = ~crc[7:0]; + end + CRC1: begin + next_state = CRC2; + next_tx_data = ~crc[15:8]; + end + CRC2: begin + next_state = CRC3; + next_tx_data = ~crc[23:16]; + end + CRC3: begin + next_state = CRC4; + next_tx_data = ~crc[31:24]; + end + CRC4: begin + next_state = WAIT; + next_tx_data = 8'd0; + next_tx_en = 1'b0; + end + WAIT: if (count_done) begin + next_state = IDLE; + end else begin + next_count = count_sub1; + end + default: next_state = IDLE; + endcase +end + +always_ff @(posedge tx_clk) begin + state <= next_state; + count <= next_count; + tx_data <= next_tx_data; + tx_en <= next_tx_en; + tx_err <= next_tx_err; + ready <= next_ready; +end + +// hardware-specific io buffers, delats, etc +eth_rgmii_tx_glue glue( + .tx_clk(tx_clk), + .pin_tx_clk(pin_tx_clk), + .pin_tx_en(pin_tx_en), + .pin_tx_data(pin_tx_data), + .tx_en(tx_en), + .tx_err(tx_err), + .tx_data(tx_data) +); + +eth_crc32_8 crc32( + .clk(tx_clk), + .en(valid & ready), + .rst(start), + .din(data), + .crc(crc) +); +endmodule diff --git a/hdl/ethernet/eth_rgmii_tx_glue_ecp5.sv b/hdl/ethernet/eth_rgmii_tx_glue_ecp5.sv @@ -0,0 +1,82 @@ +// Copyright 2020 Brian Swetland <swetland@frotz.net> +// Licensed under the Apache License, Version 2.0. + +`default_nettype none + +module eth_rgmii_tx_glue ( + input wire tx_clk, + output wire pin_tx_clk, + output wire pin_tx_en, + output wire [3:0]pin_tx_data, + input wire tx_en, + input wire tx_err, + input wire [7:0]tx_data +); + +`ifndef verilator +wire delay_tx_clk; +wire delay_tx_en; +wire delay_tx_err; +wire [3:0]delay_tx_data; + +DELAYF #( + .DEL_MODE("SCLK_CENTERED"), + .DEL_VALUE(0) // units of ~25ps + ) clock_delay ( + .LOADN(1), + .MOVE(0), + .DIRECTION(0), + .A(delay_tx_clk), + .Z(pin_tx_clk) +); +ODDRX1F clock_ddr ( + //.Q(delay_tx_clk), + .Q(delay_tx_clk), + .SCLK(tx_clk), + .RST(0), + .D0(1), + .D1(0) +); + +DELAYF #( + .DEL_MODE("SCLK_CENTERED"), + .DEL_VALUE(0) // units of ~25ps + ) ctrl_delay ( + .LOADN(1), + .MOVE(0), + .DIRECTION(0), + .A(delay_tx_en), + .Z(pin_tx_en) +); +ODDRX1F ctrl_ddr ( + .Q(delay_tx_en), + .SCLK(tx_clk), + .RST(0), + .D0(tx_en), + .D1(tx_err ^ tx_en) +); + +genvar i; + +generate for (i = 0; i < 4; i++) begin +DELAYF #( + .DEL_MODE("SCLK_CENTERED"), + .DEL_VALUE(0) // units of ~25ps + ) data_delay ( + .LOADN(1), + .MOVE(0), + .DIRECTION(0), + .A(delay_tx_data[i]), + .Z(pin_tx_data[i]) +); +ODDRX1F data_ddr ( + .Q(delay_tx_data[i]), + .SCLK(tx_clk), + .RST(0), + .D0(tx_data[i]), + .D1(tx_data[i+4]) +); +end endgenerate +`endif + +endmodule