zynq-sandbox

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

commit 536546cc793b0f8c6bd59acb4ffd1c037ed26cd8
parent bfe5f93a69c066247a6225d3fadbf8775116fdaa
Author: Brian Swetland <swetland@frotz.net>
Date:   Sat, 19 Jul 2014 23:32:23 -0700

ethernet building blocks

Diffstat:
MMakefile | 11+++++++++++
Ahdl/eth_crc32.sv | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahdl/eth_rmii_rx.sv | 141+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahdl/eth_rmii_tx.sv | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahdl/test/eth_crc32_test.sv | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahdl/test/eth_rmii_test.sv | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 529 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -45,6 +45,17 @@ MODULE_SRCS += hdl/axi_sram.sv MODULE_SRCS += hdl/axi_pattern_writer.sv include build/verilator-sim.mk +MODULE_NAME := eth-crc32-test +MODULE_SRCS := hdl/test/eth_crc32_test.sv +MODULE_SRCS += hdl/eth_crc32.sv +include build/verilator-sim.mk + +MODULE_NAME := eth-rmii-test +MODULE_SRCS := hdl/test/eth_rmii_test.sv +MODULE_SRCS += hdl/eth_rmii_tx.sv +MODULE_SRCS += hdl/eth_rmii_rx.sv +include build/verilator-sim.mk + clean:: rm -rf sim synth out diff --git a/hdl/eth_crc32.sv b/hdl/eth_crc32.sv @@ -0,0 +1,66 @@ +`timescale 1ns / 1ps + +module eth_crc32( + input clk, + input en, + input rst, + input [7:0]dat, + output [31:0]crc + ); + +reg [31:0]c = 32'hFFFFFFFF; +reg [31:0]nxt; + +wire [7:0]d = { dat[0],dat[1],dat[2],dat[3],dat[4],dat[5],dat[6],dat[7] }; + +assign crc = { + c[0],c[1],c[2],c[3],c[4],c[5],c[6],c[7], + c[8],c[9],c[10],c[11],c[12],c[13],c[14],c[15], + c[16],c[17],c[18],c[19],c[20],c[21],c[22],c[23], + c[24],c[25],c[26],c[27],c[28],c[29],c[30],c[31] + }; + +always_comb begin + nxt[0] = c[24]^c[30]^d[0]^d[6]; + nxt[1] = c[24]^c[25]^c[30]^c[31]^d[0]^d[1]^d[6]^d[7]; + nxt[2] = c[24]^c[25]^c[26]^c[30]^c[31]^d[0]^d[1]^d[2]^d[6]^d[7]; + nxt[3] = c[25]^c[26]^c[27]^c[31]^d[1]^d[2]^d[3]^d[7]; + nxt[4] = c[24]^c[26]^c[27]^c[28]^c[30]^d[0]^d[2]^d[3]^d[4]^d[6]; + nxt[5] = c[24]^c[25]^c[27]^c[28]^c[29]^c[30]^c[31]^d[0]^d[1]^d[3]^d[4]^d[5]^d[6]^d[7]; + nxt[6] = c[25]^c[26]^c[28]^c[29]^c[30]^c[31]^d[1]^d[2]^d[4]^d[5]^d[6]^d[7]; + nxt[7] = c[24]^c[26]^c[27]^c[29]^c[31]^d[0]^d[2]^d[3]^d[5]^d[7]; + nxt[8] = c[0]^c[24]^c[25]^c[27]^c[28]^d[0]^d[1]^d[3]^d[4]; + nxt[9] = c[1]^c[25]^c[26]^c[28]^c[29]^d[1]^d[2]^d[4]^d[5]; + nxt[10] = c[2]^c[24]^c[26]^c[27]^c[29]^d[0]^d[2]^d[3]^d[5]; + nxt[11] = c[3]^c[24]^c[25]^c[27]^c[28]^d[0]^d[1]^d[3]^d[4]; + nxt[12] = c[4]^c[24]^c[25]^c[26]^c[28]^c[29]^c[30]^d[0]^d[1]^d[2]^d[4]^d[5]^d[6]; + nxt[13] = c[5]^c[25]^c[26]^c[27]^c[29]^c[30]^c[31]^d[1]^d[2]^d[3]^d[5]^d[6]^d[7]; + nxt[14] = c[6]^c[26]^c[27]^c[28]^c[30]^c[31]^d[2]^d[3]^d[4]^d[6]^d[7]; + nxt[15] = c[7]^c[27]^c[28]^c[29]^c[31]^d[3]^d[4]^d[5]^d[7]; + nxt[16] = c[8]^c[24]^c[28]^c[29]^d[0]^d[4]^d[5]; + nxt[17] = c[9]^c[25]^c[29]^c[30]^d[1]^d[5]^d[6]; + nxt[18] = c[10]^c[26]^c[30]^c[31]^d[2]^d[6]^d[7]; + nxt[19] = c[11]^c[27]^c[31]^d[3]^d[7]; + nxt[20] = c[12]^c[28]^d[4]; + nxt[21] = c[13]^c[29]^d[5]; + nxt[22] = c[14]^c[24]^d[0]; + nxt[23] = c[15]^c[24]^c[25]^c[30]^d[0]^d[1]^d[6]; + nxt[24] = c[16]^c[25]^c[26]^c[31]^d[1]^d[2]^d[7]; + nxt[25] = c[17]^c[26]^c[27]^d[2]^d[3]; + nxt[26] = c[18]^c[24]^c[27]^c[28]^c[30]^d[0]^d[3]^d[4]^d[6]; + nxt[27] = c[19]^c[25]^c[28]^c[29]^c[31]^d[1]^d[4]^d[5]^d[7]; + nxt[28] = c[20]^c[26]^c[29]^c[30]^d[2]^d[5]^d[6]; + nxt[29] = c[21]^c[27]^c[30]^c[31]^d[3]^d[6]^d[7]; + nxt[30] = c[22]^c[28]^c[31]^d[4]^d[7]; + nxt[31] = c[23]^c[29]^d[5]; +end + +always @(posedge clk) begin + if (rst) begin + c <= 32'hFFFFFFFF; + end else if (en) begin + c <= nxt; + end +end + +endmodule diff --git a/hdl/eth_rmii_rx.sv b/hdl/eth_rmii_rx.sv @@ -0,0 +1,141 @@ +/* Copyright 2014 Brian Swetland <swetland@frotz.net> + * + * 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. + */ + +`timescale 1ns / 1ps + +// CRS_DV -- multiplexed, CR on first di-bit, DV on second di-bit of each nibble +// +// preamble | packet +// crs_dv ... 1 1 1 1 1 CR DV CR DV CR DV CR ... +// rx0 ... 0 0 0 0 1 b0 b2 b4 b6 b0 b2 b4 ... +// rx1 ... 1 1 1 1 1 b1 b3 b5 b7 b1 b3 b5 ... +// +// CR can go low when carrier lost, while DV remains asserted through end of frame. + +// valid is asserted on each clock where data contains a byte of the frame +// eop is asserted for one clock after the last byte of the frame has arrived +// and before the next frame's first byte arrives + +module eth_rmii_rx( + input clk50, + + input rx0, + input rx1, + input crs_dv, + + output reg [7:0]data = 0, + output reg valid = 0, + output reg eop = 0 + ); + +typedef enum { + IDLE, PRE1, PRE2, PRE3, + DAT0, DAT1, DAT2, DAT3, + ERR0, ERR1, EOP +} state_t; + +state_t state = IDLE; +state_t next_state; + +reg [7:0]next_data; +reg next_valid; +reg next_eop; + +wire [7:0]rxshift = { rx1, rx0, data[7:2] }; + +wire [1:0]rxd = { rx1, rx0 }; + +always_comb begin + next_state = state; + next_data = data; + next_valid = 0; + next_eop = 0; + + case (state) + IDLE: if ((rxd == 2'b01) && (crs_dv == 1)) begin + // crs_dv may go high asynchronously + // only move to preamble on crs_dv AND a preamble di-bit + next_state = PRE1; + end + PRE1: if (rxd == 2'b01) begin + next_state = PRE2; + end else begin + next_state = ERR0; + end + PRE2: if (rxd == 2'b01) begin + next_state = PRE3; + end else begin + next_state = ERR0; + end + PRE3: if (rxd == 2'b11) begin + next_state = DAT0; + end else if (rxd == 2'b01) begin + next_state = PRE3; + end else begin + next_state = ERR0; + end + DAT0: begin + next_data = rxshift; + next_state = DAT1; + end + DAT1: begin + next_data = rxshift; + if (crs_dv) begin + next_state = DAT2; + end else begin + next_state = EOP; + end + end + DAT2: begin + next_data = rxshift; + next_state = DAT3; + end + DAT3: begin + next_data = rxshift; + if (crs_dv) begin + next_state = DAT0; + next_valid = 1; + end else begin + next_state = EOP; + end + end + EOP: begin + next_state = IDLE; + next_data = 0; + next_eop = 1; + end + ERR0: begin + if (crs_dv == 0) begin + next_state = ERR1; + end + end + ERR1: begin + if (crs_dv == 0) begin + next_state = IDLE; + end else begin + next_state = ERR0; + end + end + endcase +end + +always_ff @(posedge clk50) begin + state <= next_state; + valid <= next_valid; + data <= next_data; + eop <= next_eop; +end + +endmodule diff --git a/hdl/eth_rmii_tx.sv b/hdl/eth_rmii_tx.sv @@ -0,0 +1,146 @@ +/* Copyright 2014 Brian Swetland <swetland@frotz.net> + * + * 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. + */ + +`timescale 1ns / 1ps + +// 1. Asserting packet starts tx cycle. +// 2. Deasserting packet will cause tx cycle to complete after current byte +// has completed transmission. +// 3. busy is asserted while a packet is in flight (and will remain asserted after +// packet deasserts, until after inter-packet-gap (IPG) has completed). +// 4. advance is asserted when txdata is consumed + +module eth_rmii_tx( + input clk50, + + output tx0, + output tx1, + output reg txen = 0, + + input [7:0]data, + input packet, + output reg busy = 0, + output reg advance = 0 + ); + +typedef enum { + IDLE, PRE, DAT0, DAT1, DAT2, DAT3, EOP +} state_t; + +state_t state = IDLE; +state_t next_state; + +reg [7:0] txdata = 0; +reg [7:0] next_txdata; + +wire [7:0]txshift = { 2'b0, txdata[7:2] }; + +reg [1:0]txd = 0; +reg [1:0]next_txd; + +assign { tx1, tx0 } = txd; + +reg [5:0] count = 0; +reg [5:0] next_count; + +wire count_is_zero = (count == 0); + +wire [5:0]count_minus_one = (count - 1); + +reg next_txen; +reg next_advance; +reg next_busy; + +always_comb begin + next_state = state; + next_count = count; + next_txdata = txdata; + next_busy = busy; + next_txd = txd; + next_txen = 1; + next_advance = 0; + + case (state) + IDLE: begin + next_txen = 0; + next_txd = 0; + if (packet) begin + next_state = PRE; + next_count = 31; + next_busy = 1; + end + end + PRE: begin + if (count_is_zero) begin + next_state = DAT0; + next_txdata = data; + next_advance = 1; + next_txd = 2'b11; + end else begin + next_txd = 2'b01; + next_count = count_minus_one; + end + end + DAT0: begin + next_state = DAT1; + next_txdata = txshift; + next_txd = txdata[1:0]; + end + DAT1: begin + next_state = DAT2; + next_txdata = txshift; + next_txd = txdata[1:0]; + end + DAT2: begin + next_state = DAT3; + next_txdata = txshift; + next_txd = txdata[1:0]; + end + DAT3: begin + next_txd = txdata[1:0]; + if (~packet) begin + // no more data, wrap it up + next_state = EOP; + next_count = 48; + end else begin + next_state = DAT0; + next_txdata = data; + next_advance = 1; + end + end + EOP: begin + next_txd = 0; + next_txen = 0; + if (count_is_zero) begin + next_state = IDLE; + next_busy = 0; + end else begin + next_count = count_minus_one; + end + end + endcase +end + +always_ff @(posedge clk50) begin + state <= next_state; + count <= next_count; + txdata <= next_txdata; + txen <= next_txen; + txd <= next_txd; + advance <= next_advance; + busy <= next_busy; +end + +endmodule diff --git a/hdl/test/eth_crc32_test.sv b/hdl/test/eth_crc32_test.sv @@ -0,0 +1,54 @@ +`timescale 1ns / 1ps + +module testbench(input clk); + +wire [31:0]val; +wire [7:0]data; + +eth_crc32 crc( + .clk(clk), + .en(1), + .rst(0), + .dat(data), + .crc(val) + ); + +reg [7:0]packet[0:15]; + +reg [7:0]count = 0; + +assign data = packet[count[3:0]]; + +always_ff @(posedge clk) begin + $display("crc %x %x",data, val); + if (count == 16) begin + if (val == 32'hdebb20e3) + $display("PASS"); + else + $display("FAIL"); + $finish(); + end + count <= count + 1; +end + +initial begin + packet[0] = 8'h6e; + packet[1] = 8'hb9; + packet[2] = 8'h34; + packet[3] = 8'h70; + packet[4] = 8'h3b; + packet[5] = 8'h77; + packet[6] = 8'hc7; + packet[7] = 8'hae; + packet[8] = 8'h29; + packet[9] = 8'h52; + packet[10] = 8'h14; + packet[11] = 8'h3e; + packet[12] = 8'h09; + packet[13] = 8'ha6; + packet[14] = 8'h94; + packet[15] = 8'h60; +end + +endmodule + diff --git a/hdl/test/eth_rmii_test.sv b/hdl/test/eth_rmii_test.sv @@ -0,0 +1,111 @@ +/* Copyright 2014 Brian Swetland <swetland@frotz.net> + * + * 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. + */ + +`timescale 1ns / 1ps + +module testbench(input clk); + +// RMII transport between tx and rx +wire eth_d0; +wire eth_d1; +wire eth_en; + + +wire [7:0]txdata; +reg txpacket = 0; +wire txbusy; +wire txadvance; + +eth_rmii_tx tx( + .clk50(clk), + + .tx0(eth_d0), + .tx1(eth_d1), + .txen(eth_en), + + .data(txdata), + .packet(txpacket), + .busy(txbusy), + .advance(txadvance) + ); + +wire [7:0]rxdata; +wire rxvalid; +wire rxeop; + +eth_rmii_rx rx( + .clk50(clk), + .rx0(eth_d0), + .rx1(eth_d1), + .crs_dv(eth_en), + .data(rxdata), + .valid(rxvalid), + .eop(rxeop) + ); + +reg txgo = 0; +reg wait_eop = 0; + +reg [7:0]pdata[0:15]; +reg [3:0]pindex = 0; + +assign txdata = pdata[pindex]; + +reg [7:0]start = 8'b10000000; + +always_ff @(posedge clk) begin + txgo <= start[0]; + start <= { 1'b0, start[7:1] }; +end + + +always_ff @(posedge clk) begin + if (txgo) begin + txpacket <= 1; + end + if (txpacket) begin + if (txadvance) begin + if (pindex == 15) begin + txpacket <= 0; + wait_eop <= 1; + end + pindex <= pindex + 1; + end + end + if (wait_eop & ~txbusy) begin + $finish; + end +end + +initial begin + pdata[0] = 8'hFF; + pdata[1] = 8'h01; + pdata[2] = 8'h77; + pdata[3] = 8'hAA; + pdata[4] = 8'h00; + pdata[5] = 8'h10; + pdata[6] = 8'h20; + pdata[7] = 8'h30; + pdata[8] = 8'h40; + pdata[9] = 8'h50; + pdata[10] = 8'h60; + pdata[11] = 8'h70; + pdata[12] = 8'h80; + pdata[13] = 8'h90; + pdata[14] = 8'hAA; + pdata[15] = 8'h55; +end + +endmodule