├── FYP Project Plan - January.xlsx ├── FYP Project Plan - March.xlsx ├── FYP Project Plan - October.xlsx ├── LICENSE ├── MAC ├── rtl │ ├── mac │ │ ├── crc │ │ │ ├── crc.v │ │ │ └── tb │ │ │ │ ├── crc_tb_ETHERNET_0.v │ │ │ │ ├── crc_tb_ETHERNET_1.v │ │ │ │ ├── crc_tb_ETHERNET_2.v │ │ │ │ ├── crc_tb_USB.v │ │ │ │ ├── dut.v │ │ │ │ ├── out │ │ │ │ ├── packet.hex │ │ │ │ └── packet2.hex │ │ ├── fifo │ │ │ ├── fifo.v │ │ │ └── tb │ │ │ │ ├── dut.v │ │ │ │ ├── fifo_tb.v │ │ │ │ └── out │ │ ├── mac.v │ │ ├── mac_fifo │ │ │ ├── fifo │ │ │ │ └── fifo.v │ │ │ └── mac_fifo.v │ │ ├── mac_loopback.v │ │ ├── rx │ │ │ ├── rx_sm.v │ │ │ └── tb │ │ │ │ ├── dut.v │ │ │ │ ├── mac_tb2.v │ │ │ │ ├── out │ │ │ │ ├── out.txt │ │ │ │ ├── packet.hex │ │ │ │ ├── rx_sm_tb.v │ │ │ │ └── test.vcd │ │ ├── tb │ │ │ ├── dut.v │ │ │ ├── mac_loopback_tb.v │ │ │ ├── out │ │ │ ├── packet.hex │ │ │ └── test.vcd │ │ ├── tx │ │ │ ├── random.v │ │ │ ├── tb │ │ │ │ ├── dut.v │ │ │ │ ├── tx_sm_full_duplex_tb.v │ │ │ │ └── tx_sm_half_duplex_tb.v │ │ │ └── tx_sm.v │ │ └── utilities │ │ │ ├── monitor.v │ │ │ └── utilities.v │ └── tx_sm.v ├── tags └── tb │ └── mac │ ├── mac_fifo │ ├── fifo │ │ └── fifo_tb.v │ ├── mac_fifo_tb.v │ └── mac_fifo_tb2.v │ ├── mac_tb.v │ └── mac_tb2.v ├── MAC_components ├── crc │ ├── crc.v │ ├── tb │ │ ├── crc_tb_ETHERNET_0.v │ │ ├── crc_tb_ETHERNET_1.v │ │ ├── crc_tb_ETHERNET_2.v │ │ ├── crc_tb_USB.v │ │ ├── dut.v │ │ ├── out │ │ ├── packet.hex │ │ └── packet2.hex │ └── utilities │ │ ├── monitor.v │ │ └── utilities.v └── state_machines │ ├── out │ ├── packet.hex │ ├── random.v │ ├── rx.v │ ├── rx_tb.v │ ├── test.vcd │ ├── tx.v │ └── tx_tb.v ├── Open Source Ethernet MAC.pdf ├── README.md ├── Table.xlsx ├── Verilog Open Source Ethernet MAC.pptx ├── arbiter.v ├── arbiter_tb.v ├── backoff.xlsx ├── clock_divider.v ├── crc.v ├── crc.xlsx ├── gmii.v ├── mii.v ├── mii.xlsx ├── out ├── priority_encoder.v ├── random.v ├── rgmii.v ├── rgmii.xlsx ├── rmii.v ├── rmii.xlsx ├── rx.dot ├── rx.v ├── rx.xlsx ├── schematic.pdf ├── sme.xlsx ├── station_management.v ├── station_management_mdo_mdi.v ├── station_management_mdo_mdi_tb.v ├── station_management_tb.v ├── test.vcd ├── tx.v └── tx.xlsx /FYP Project Plan - January.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/FYP Project Plan - January.xlsx -------------------------------------------------------------------------------- /FYP Project Plan - March.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/FYP Project Plan - March.xlsx -------------------------------------------------------------------------------- /FYP Project Plan - October.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/FYP Project Plan - October.xlsx -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jake Mercer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MAC/rtl/mac/crc/crc.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module crc #( 4 | parameter POLYNOMIAL = 5'b00101, 5 | parameter DATA_WIDTH = 8, 6 | parameter CRC_WIDTH = 5, 7 | parameter SEED = 0, 8 | parameter DEBUG = 0, 9 | parameter REVERSE = 1 10 | )( 11 | input [DATA_WIDTH-1:0] data, 12 | input data_enable, 13 | output reg [CRC_WIDTH-1:0] crc_out, 14 | input init, 15 | input clock, 16 | input reset 17 | ); 18 | 19 | function automatic prev; 20 | input integer level; 21 | input integer index; 22 | input [DATA_WIDTH-1:0] data; 23 | input [CRC_WIDTH-1:0] crc; 24 | begin 25 | if (POLYNOMIAL[index]) 26 | begin 27 | if (level) 28 | begin 29 | if (index) 30 | begin 31 | if (DEBUG) 32 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ crc[%0d] ^ data[%0d]", level, index, (index)?index-1:CRC_WIDTH-1, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 33 | prev = prev(level-1, (index)?index-1:CRC_WIDTH-1, data, crc) ^ prev(level-1, CRC_WIDTH-1, data, crc) ^ data[DATA_WIDTH-1-level]; 34 | end 35 | else 36 | begin 37 | if (DEBUG) 38 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ data[%0d]", level, index, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 39 | prev = prev(level-1, CRC_WIDTH-1, data, crc) ^ data[DATA_WIDTH-1-level]; 40 | end 41 | 42 | end 43 | else 44 | begin 45 | if (index) 46 | begin 47 | if (DEBUG) 48 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ crc[%0d] ^ data[%0d] // STOP", level, index, index-1, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 49 | prev = crc[index-1-:1] ^ crc[CRC_WIDTH-1-:1] ^ data[DATA_WIDTH-1-level]; 50 | end 51 | else 52 | begin 53 | if (DEBUG) 54 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ data[%0d] // STOP", level, index, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 55 | prev = crc[CRC_WIDTH-1-:1] ^ data[DATA_WIDTH-1-level]; 56 | end 57 | end 58 | end 59 | else 60 | begin 61 | if (level) 62 | begin 63 | if (index) 64 | begin 65 | if (DEBUG) 66 | $display("LEVEL %0d | crc[%0d] = crc[%0d]", level, index, index - 1); 67 | prev = prev(level-1, index-1, data, crc); 68 | end 69 | else 70 | begin 71 | if (DEBUG) 72 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ data[%0d]", level, index, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 73 | prev = prev(level-1, CRC_WIDTH-1, data, crc) ^ data[DATA_WIDTH-1-level]; 74 | end 75 | end 76 | else 77 | begin 78 | if (index) 79 | begin 80 | if (DEBUG) 81 | $display("LEVEL %0d | crc[%0d] = crc[%0d] // STOP", level, index, index - 1); 82 | prev = crc[index-1-:1]; 83 | end 84 | else 85 | begin 86 | if (DEBUG) 87 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ data[%0d] // STOP", level, index, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 88 | prev = crc[CRC_WIDTH-1-:1] ^ data[DATA_WIDTH-1-level]; 89 | end 90 | end 91 | end 92 | end 93 | endfunction 94 | 95 | wire [DATA_WIDTH-1:0] temp; 96 | 97 | genvar j; 98 | generate 99 | if (REVERSE) 100 | begin 101 | for (j = DATA_WIDTH-1; j >= 0; j = j - 1) 102 | begin : reverse_loop 103 | assign temp[DATA_WIDTH-1-j] = data[j]; 104 | end 105 | end 106 | else 107 | begin 108 | assign temp = data; 109 | end 110 | endgenerate 111 | 112 | genvar i; 113 | generate 114 | for(i = 0; i < CRC_WIDTH; i= i + 1) 115 | begin : loop 116 | always @(posedge clock) 117 | begin 118 | if (reset) 119 | begin 120 | crc_out[i+:1] = SEED[i+:1]; 121 | end 122 | else if (init) 123 | begin 124 | crc_out[i+:1] = SEED[i+:1]; 125 | end 126 | else if (data_enable) 127 | begin 128 | if (DEBUG) 129 | $display("\n\nCRC OUT[%0d]\n***************************************************************************", i); 130 | crc_out[i+:1] <= prev(DATA_WIDTH-1,i,temp,crc_out); 131 | end 132 | end 133 | end 134 | endgenerate 135 | 136 | endmodule 137 | 138 | 139 | -------------------------------------------------------------------------------- /MAC/rtl/mac/crc/tb/crc_tb_ETHERNET_0.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module crc_tb #( 4 | parameter CRC_WIDTH = 32, 5 | parameter DATA_WIDTH = 8, 6 | parameter POLYNOMIAL = 32'h04C11DB7, 7 | parameter SEED = 32'hFFFFFFFF 8 | )(); 9 | 10 | `include "dut.v" 11 | 12 | reg [7:0] packet [0:91]; 13 | integer i; 14 | integer j; 15 | reg [7:0] temp; 16 | reg [31:0] temp2; 17 | reg [31:0] temp3; 18 | 19 | initial 20 | begin 21 | #15 reset = 0; 22 | 23 | $readmemh("packet.hex", packet); 24 | 25 | for(i = 0; i < 92; i = i + 1) 26 | begin 27 | util.sync_write(packet[i]); 28 | end 29 | 30 | util.sync_read(tempdata); 31 | 32 | for (j = 31; j >= 0; j = j - 1) 33 | begin 34 | temp2[31-j] = tempdata[j]; 35 | end 36 | 37 | $display("Normal: %x",tempdata); 38 | $display("Reversed: %x",temp2); 39 | $display("Reversed & Inverted: %x",~temp2); 40 | 41 | tempdata = ~tempdata; 42 | $display("Inverted: %x",tempdata); 43 | 44 | for (j = 4; j > 0; j = j - 1) 45 | begin 46 | temp3[(j*8)-1-:8] = ~temp2[((4-j)*8)+:8]; 47 | end 48 | 49 | $display("Reversed & Inverted & Byte Re-order: %x",temp3); 50 | 51 | util.assert(temp3 == 32'hc0f447ca, "CRC == 0xc0f447ca"); 52 | 53 | $finish; 54 | end 55 | 56 | endmodule 57 | 58 | -------------------------------------------------------------------------------- /MAC/rtl/mac/crc/tb/crc_tb_ETHERNET_1.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module crc_tb #( 4 | parameter CRC_WIDTH = 32, 5 | parameter DATA_WIDTH = 8, 6 | parameter POLYNOMIAL = 32'h04C11DB7, 7 | parameter SEED = 32'h00000000 8 | )(); 9 | 10 | `include "dut.v" 11 | 12 | initial 13 | begin 14 | #15 reset = 0; 15 | 16 | util.sync_write(8'hAA); 17 | util.sync_read(tempdata); 18 | util.assert(tempdata == 32'hdea580d8, "CRC == 0xdea580d8"); 19 | util.sync_write(8'hAA); 20 | util.sync_read(tempdata); 21 | util.assert(tempdata == 32'h5630b33b, "CRC == 0x5630b33b"); 22 | 23 | $finish; 24 | end 25 | 26 | endmodule 27 | 28 | -------------------------------------------------------------------------------- /MAC/rtl/mac/crc/tb/crc_tb_ETHERNET_2.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module crc_tb #( 4 | parameter CRC_WIDTH = 32, 5 | parameter DATA_WIDTH = 8, 6 | parameter POLYNOMIAL = 32'h04C11DB7, 7 | parameter SEED = 32'hFFFFFFFF 8 | )(); 9 | 10 | `include "dut.v" 11 | 12 | reg [7:0] packet [0:95]; 13 | integer i; 14 | integer j; 15 | reg [7:0] temp; 16 | 17 | initial 18 | begin 19 | #15 reset = 0; 20 | 21 | $readmemh("packet.hex", packet); 22 | 23 | for(i = 0; i < 96; i = i + 1) 24 | begin 25 | util.sync_write(packet[i]); 26 | end 27 | 28 | util.sync_read(tempdata); 29 | 30 | util.assert(tempdata == 32'hc704dd7b, "CRC == 0xc704dd7b"); 31 | 32 | $finish; 33 | end 34 | 35 | endmodule 36 | 37 | -------------------------------------------------------------------------------- /MAC/rtl/mac/crc/tb/crc_tb_USB.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module crc_tb #( 4 | parameter CRC_WIDTH = 5, 5 | parameter DATA_WIDTH = 8, 6 | parameter POLYNOMIAL = 5'b00101, 7 | parameter SEED = 0 8 | )(); 9 | 10 | `include "dut.v" 11 | 12 | initial 13 | begin 14 | #15 reset = 0; 15 | 16 | util.sync_write(8'hAA); 17 | util.sync_read(tempdata); 18 | util.assert(tempdata == 5'b11000, 1); 19 | util.sync_write(8'hAA); 20 | util.sync_read(tempdata); 21 | util.assert(tempdata == 5'b10001, 2); 22 | 23 | $finish; 24 | end 25 | 26 | endmodule 27 | 28 | -------------------------------------------------------------------------------- /MAC/rtl/mac/crc/tb/dut.v: -------------------------------------------------------------------------------- 1 | wire [DATA_WIDTH-1:0] data_in; 2 | wire data_in_enable; 3 | wire [CRC_WIDTH-1:0] crc_out; 4 | reg clock; 5 | reg reset; 6 | reg [CRC_WIDTH-1:0] tempdata; 7 | 8 | crc #( .POLYNOMIAL(POLYNOMIAL), 9 | .DATA_WIDTH(DATA_WIDTH), 10 | .CRC_WIDTH(CRC_WIDTH), 11 | .SEED(SEED), 12 | .DEBUG(0)) 13 | U_crc( 14 | .data(data_in), 15 | .data_enable(data_in_enable), 16 | .crc_out(crc_out), 17 | .init(), 18 | .clock(clock), 19 | .reset(reset) 20 | ); 21 | 22 | utilities #(.OUT_WIDTH (DATA_WIDTH), 23 | .IN_WIDTH (CRC_WIDTH), 24 | .DEBUG(1)) 25 | util ( 26 | .data_in(crc_out), 27 | .data_in_enable(), 28 | .data_out(data_in), 29 | .data_out_enable(data_in_enable), 30 | .clock(clock) 31 | ); 32 | 33 | initial 34 | begin 35 | clock = 0; 36 | reset = 1; 37 | end 38 | 39 | always 40 | #5 clock = ~clock; 41 | -------------------------------------------------------------------------------- /MAC/rtl/mac/crc/tb/packet.hex: -------------------------------------------------------------------------------- 1 | ff ff ff ff ff ff d0 50 99 98 96 8c 08 00 45 00 00 4e 22 2d 00 00 80 11 f5 21 a9 fe cf 53 a9 fe ff ff 00 89 00 89 00 3a 7a aa b0 eb 01 10 00 01 00 00 00 00 00 00 20 45 4d 45 4a 46 47 45 46 43 4f 45 45 45 46 45 46 46 4b 45 46 46 43 43 4f 45 44 45 50 45 4e 41 41 00 00 20 00 01 c0 f4 47 ca 2 | -------------------------------------------------------------------------------- /MAC/rtl/mac/crc/tb/packet2.hex: -------------------------------------------------------------------------------- 1 | 00 10 A4 7B EA 80 00 12 34 56 78 90 08 00 45 00 00 2E B3 FE 00 00 80 11 05 40 C0 A8 00 2C C0 A8 00 04 04 00 04 00 00 1A 2D E8 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 2 | -------------------------------------------------------------------------------- /MAC/rtl/mac/fifo/fifo.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module fifo 4 | #( 5 | parameter DATA_WIDTH = 8, 6 | parameter FIFO_DEPTH = 12 7 | ) 8 | ( 9 | input wire reset, 10 | output reg [FIFO_DEPTH:0] count, 11 | output reg full, 12 | 13 | // IN PORT 14 | input wire [DATA_WIDTH-1:0] data_in, 15 | input wire data_in_clock, 16 | input wire data_in_enable, 17 | input wire data_in_start, 18 | input wire data_in_end, 19 | output reg [FIFO_DEPTH-1:0] data_in_address, 20 | input wire data_in_reset, 21 | input wire [FIFO_DEPTH-1:0] data_in_reset_address, 22 | 23 | // OUT PORT 24 | output reg [DATA_WIDTH-1:0] data_out, 25 | input wire data_out_clock, 26 | input wire data_out_enable, 27 | output reg data_out_start, 28 | output reg data_out_end, 29 | output reg [FIFO_DEPTH-1:0] data_out_address, 30 | input wire data_out_reset, 31 | input wire [FIFO_DEPTH-1:0] data_out_reset_address 32 | ); 33 | 34 | reg [DATA_WIDTH + 1:0] mem[(2**FIFO_DEPTH) - 1:0]; // 2 bits added to data to facilitate start and stop bits. 35 | 36 | always @(posedge data_in_clock) 37 | begin 38 | if ( count && (data_in_address == data_out_address - 1 )) 39 | begin 40 | full <= 1; 41 | end 42 | else 43 | begin 44 | full <= 0; 45 | end 46 | end 47 | 48 | always @(posedge data_in_clock) 49 | begin 50 | if( data_in_enable ) 51 | begin 52 | if ( data_out_address != data_in_address || (data_out_address == data_in_address && !count)) 53 | mem[ data_in_address ]<= { data_in, data_in_start, data_in_end }; 54 | end 55 | end 56 | 57 | always @(posedge data_in_clock or posedge reset) 58 | begin 59 | if( reset ) 60 | begin 61 | data_in_address <= 0; 62 | count <= 0; 63 | end 64 | else if (data_in_reset) 65 | begin 66 | count = count - (data_in_address - data_in_reset_address); 67 | data_in_address = data_in_reset_address; 68 | end 69 | else 70 | begin 71 | if( data_in_enable ) 72 | begin 73 | count <= count + 1; 74 | data_in_address <= data_in_address + 1; 75 | end 76 | end 77 | end 78 | 79 | always @(posedge data_out_clock or posedge reset) 80 | begin 81 | if (reset) 82 | begin 83 | data_out <= 0; 84 | data_out_address <= 0; 85 | end 86 | else if (data_out_reset) 87 | begin 88 | data_out_address <= data_out_reset_address; 89 | end 90 | else if (data_out_enable) 91 | begin 92 | { data_out, data_out_start, data_out_end } <= mem[data_out_address]; 93 | data_out_address <= data_out_address + 1; 94 | count <= count - 1; 95 | end 96 | end 97 | 98 | endmodule 99 | -------------------------------------------------------------------------------- /MAC/rtl/mac/fifo/tb/dut.v: -------------------------------------------------------------------------------- 1 | reg reset; 2 | 3 | wire [WIDTH-1:0] data_in_sig; 4 | reg data_in_clock; 5 | wire data_in_enable; 6 | wire data_in_start_sig; 7 | wire data_in_end_sig; 8 | 9 | wire [WIDTH-1:0] data_out_sig; 10 | wire data_out_start_sig; 11 | wire data_out_end_sig; 12 | reg data_out_clock; 13 | wire data_out_enable; 14 | 15 | fifo #( 16 | .DATA_WIDTH (WIDTH), 17 | .FIFO_DEPTH (DEPTH) 18 | ) 19 | ff ( 20 | .reset(reset), 21 | 22 | // IN PORT 23 | .data_in(data_in_sig), 24 | .data_in_clock(data_in_clock), 25 | .data_in_enable(data_in_enable), 26 | .data_in_start(data_in_start_sig), 27 | .data_in_end(data_in_end_sig), 28 | 29 | // OUT PORT 30 | .data_out(data_out_sig), 31 | .data_out_clock(data_out_clock), 32 | .data_out_enable(data_out_enable), 33 | .data_out_start(data_out_start_sig), 34 | .data_out_end(data_out_end_sig) 35 | ); 36 | 37 | utilities #(.OUT_WIDTH (1), 38 | .IN_WIDTH (1)) 39 | util ( 40 | .data_in(), 41 | .data_in_enable(), 42 | .data_out(), 43 | .data_out_enable(), 44 | .clock(clock) 45 | ); 46 | utilities #(.OUT_WIDTH (WIDTH), 47 | .IN_WIDTH (WIDTH), 48 | .DEBUG(1)) 49 | data_in ( 50 | .data_in(), 51 | .data_in_enable(), 52 | .data_out(data_in_sig), 53 | .data_out_enable(data_in_enable), 54 | .clock(data_in_clock) 55 | ); 56 | 57 | utilities #(.OUT_WIDTH (1), 58 | .IN_WIDTH (1)) 59 | data_in_start ( 60 | .data_in(), 61 | .data_in_enable(), 62 | .data_out(data_in_start_sig), 63 | .data_out_enable(), 64 | .clock(data_in_clock) 65 | ); 66 | 67 | utilities #(.OUT_WIDTH (1), 68 | .IN_WIDTH (1)) 69 | data_in_end ( 70 | .data_in(), 71 | .data_in_enable(), 72 | .data_out(data_in_end_sig), 73 | .data_out_enable(), 74 | .clock(data_in_clock) 75 | ); 76 | 77 | utilities #(.OUT_WIDTH (WIDTH), 78 | .IN_WIDTH (WIDTH), 79 | .DEBUG(1)) 80 | data_out ( 81 | .data_in(data_out_sig), 82 | .data_in_enable(data_out_enable), 83 | .data_out(), 84 | .data_out_enable(), 85 | .clock(data_out_clock) 86 | ); 87 | 88 | utilities #(.OUT_WIDTH (1), 89 | .IN_WIDTH (1)) 90 | data_out_start ( 91 | .data_in(data_out_start_sig), 92 | .data_in_enable(), 93 | .data_out(), 94 | .data_out_enable(), 95 | .clock(data_out_clock) 96 | ); 97 | 98 | utilities #(.OUT_WIDTH (1), 99 | .IN_WIDTH (1)) 100 | data_out_end ( 101 | .data_in(data_out_end_sig), 102 | .data_in_enable(), 103 | .data_out(), 104 | .data_out_enable(), 105 | .clock(data_out_clock) 106 | ); 107 | 108 | initial 109 | begin 110 | data_in_clock = 0; 111 | data_out_clock = 0; 112 | reset = 1; 113 | end 114 | 115 | always 116 | #5 data_in_clock = ~data_in_clock; 117 | 118 | always 119 | #5 data_out_clock = ~data_out_clock; 120 | -------------------------------------------------------------------------------- /MAC/rtl/mac/fifo/tb/fifo_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module fifo_test(); 4 | 5 | parameter WIDTH = 8; 6 | parameter DEPTH = 12; 7 | 8 | `include "dut.v" 9 | 10 | integer i; 11 | reg [WIDTH-1:0] tempdata; 12 | reg tempstart; 13 | reg tempend; 14 | 15 | initial 16 | begin 17 | #15 reset = 0; 18 | 19 | fork 20 | data_in.sync_write(8'hAA); 21 | data_in_start.sync_write(1); 22 | join 23 | 24 | for ( i = 1; i < 100; i = i + 1) 25 | begin 26 | data_in.sync_write(i); 27 | end 28 | 29 | fork 30 | data_in.sync_write(8'hAB); 31 | data_in_end.sync_write(1); 32 | join 33 | 34 | fork 35 | data_out.sync_read(tempdata); 36 | data_out_start.sync_read(tempstart); 37 | data_out_end.sync_read(tempend); 38 | join 39 | 40 | util.assert(tempdata == 8'hAA, "Reading FIFO Data"); 41 | util.assert(tempstart == 1, "Reading FIFO Start"); 42 | util.assert(tempend == 0, "Reading FIFO End"); 43 | 44 | for ( i = 1; i < 100; i = i + 1) 45 | begin 46 | fork 47 | data_out.sync_read(tempdata); 48 | data_out_start.sync_read(tempstart); 49 | data_out_end.sync_read(tempend); 50 | join 51 | util.assert(tempdata == i, "Reading FIFO Data"); 52 | util.assert(tempstart == 0, "Reading FIFO Start"); 53 | util.assert(tempend == 0, "Reading FIFO End"); 54 | end 55 | 56 | fork 57 | data_out.sync_read(tempdata); 58 | data_out_start.sync_read(tempstart); 59 | data_out_end.sync_read(tempend); 60 | join 61 | 62 | util.assert(tempdata == 8'hAB, "Reading FIFO Data"); 63 | util.assert(tempstart == 0, "Reading FIFO Start"); 64 | util.assert(tempend == 1, "Reading FIFO End"); 65 | 66 | $finish; 67 | end 68 | 69 | endmodule 70 | -------------------------------------------------------------------------------- /MAC/rtl/mac/mac.v: -------------------------------------------------------------------------------- 1 | module mac( 2 | input wire reset, 3 | 4 | // IN PORT 5 | input wire [31:0] data_in, 6 | input wire data_in_clock, 7 | input wire data_in_enable, 8 | input wire data_in_start, 9 | input wire data_in_end, 10 | 11 | // OUT PORT 12 | output wire [31:0] data_out, 13 | input wire data_out_clock, 14 | input wire data_out_enable, 15 | output wire data_out_start, 16 | output wire data_out_end, 17 | output wire [6:0] frame_count, 18 | 19 | input wire tx_clock, 20 | input wire rx_clock, 21 | 22 | input wire carrier_sense, 23 | input wire collision, 24 | 25 | output wire tx_enable, 26 | output wire [7:0] tx_data, 27 | 28 | input wire rx_data_valid, 29 | input wire [7:0] rx_data, 30 | input wire rx_error 31 | ); 32 | 33 | wire [7:0] tx_fifo_data; 34 | wire tx_fifo_data_read; 35 | wire tx_fifo_data_start; 36 | wire tx_fifo_data_end; 37 | wire [6:0] tx_fifo_count; 38 | wire tx_fifo_retry; 39 | 40 | wire [7:0] rx_fifo_data; 41 | wire rx_fifo_data_write; 42 | wire rx_fifo_data_start; 43 | wire rx_fifo_data_end; 44 | wire rx_fifo_full; 45 | wire rx_fifo_error; 46 | 47 | tx_sm U_tx_sm( 48 | .reset(reset), 49 | .clock(tx_clock), 50 | 51 | .fifo_data(tx_fifo_data), 52 | .fifo_data_read(tx_fifo_data_read), 53 | .fifo_data_start(tx_fifo_data_start), 54 | .fifo_data_end(tx_fifo_data_end), 55 | .fifo_count(tx_fifo_count), 56 | .fifo_retry(tx_fifo_retry), 57 | 58 | .mode(1'b1), 59 | 60 | .carrier_sense(carrier_sense), 61 | .collision(collision), 62 | 63 | .tx_enable(tx_enable), 64 | .tx_data(tx_data) 65 | ); 66 | 67 | mac_fifo #( 68 | .DATA_IN_WIDTH(32), 69 | .DATA_OUT_WIDTH(8), 70 | .FIFO_DEPTH(12) 71 | ) U_mac_fifo_tx ( 72 | .reset(reset), 73 | 74 | .data_in(data_in), 75 | .data_in_clock(data_in_clock), 76 | .data_in_enable(data_in_enable), 77 | .data_in_start(data_in_start), 78 | .data_in_end(data_in_end), 79 | 80 | .data_out(tx_fifo_data), 81 | .data_out_clock(tx_clock), 82 | .data_out_enable(tx_fifo_data_read), 83 | .data_out_start(tx_fifo_data_start), 84 | .data_out_end(tx_fifo_data_end), 85 | 86 | .retry(tx_fifo_retry), 87 | .error(1'b0), 88 | .frame_count(tx_fifo_count) 89 | ); 90 | 91 | rx_sm U_rx_sm( 92 | .reset(reset), 93 | .clock(rx_clock), 94 | 95 | .fifo_data(rx_fifo_data), 96 | .fifo_data_write(rx_fifo_data_write), 97 | .fifo_data_start(rx_fifo_data_start), 98 | .fifo_data_end(rx_fifo_data_end), 99 | .fifo_full(rx_fifo_full), 100 | .fifo_error(rx_fifo_error), 101 | 102 | .rx_data_valid(rx_data_valid), 103 | .rx_error(rx_error), 104 | 105 | .rx_data(rx_data) 106 | ); 107 | 108 | mac_fifo #( 109 | .DATA_IN_WIDTH(8), 110 | .DATA_OUT_WIDTH(32), 111 | .FIFO_DEPTH(12) 112 | ) U_mac_fifo_rx ( 113 | .reset(reset), 114 | 115 | .data_in(rx_fifo_data), 116 | .data_in_clock(rx_clock), 117 | .data_in_enable(rx_fifo_data_write), 118 | .data_in_start(rx_fifo_data_start), 119 | .data_in_end(rx_fifo_data_end), 120 | 121 | .data_out(data_out), 122 | .data_out_clock(data_out_clock), 123 | .data_out_enable(data_out_enable), 124 | .data_out_start(data_out_start), 125 | .data_out_end(data_out_end), 126 | 127 | .retry(1'b0), 128 | .error(rx_fifo_error), 129 | .frame_count(frame_count) 130 | ); 131 | 132 | endmodule 133 | -------------------------------------------------------------------------------- /MAC/rtl/mac/mac_fifo/fifo/fifo.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module fifo 4 | #( 5 | parameter DATA_IN_WIDTH = 8, 6 | parameter DATA_OUT_WIDTH = 8, 7 | parameter FIFO_DEPTH = 12 8 | ) 9 | ( 10 | input wire reset, 11 | output reg count, 12 | 13 | // IN PORT 14 | input wire [DATA_IN_WIDTH-1:0] data_in, 15 | input wire data_in_clock, 16 | input wire data_in_enable, 17 | output reg [FIFO_DEPTH-1:0] data_in_address, 18 | input wire data_in_reset, 19 | input wire [FIFO_DEPTH-1:0] data_in_reset_address, 20 | 21 | // OUT PORT 22 | output reg [DATA_OUT_WIDTH-1:0] data_out, 23 | input wire data_out_clock, 24 | input wire data_out_enable, 25 | output reg [FIFO_DEPTH-1:0] data_out_address, 26 | input wire data_out_reset, 27 | input wire [FIFO_DEPTH-1:0] data_out_reset_address 28 | ); 29 | 30 | integer index; 31 | 32 | generate 33 | if (DATA_IN_WIDTH > DATA_OUT_WIDTH && DATA_IN_WIDTH % DATA_OUT_WIDTH != 0) 34 | begin 35 | initial 36 | begin 37 | $display("ERROR: invalid width."); 38 | end 39 | end 40 | else if (DATA_OUT_WIDTH > DATA_IN_WIDTH && DATA_OUT_WIDTH % DATA_IN_WIDTH != 0) 41 | begin 42 | initial 43 | begin 44 | $display("ERROR: invalid width."); 45 | end 46 | end 47 | else if (DATA_OUT_WIDTH > DATA_IN_WIDTH) 48 | begin 49 | initial 50 | begin 51 | $display("OUT > IN"); 52 | end 53 | 54 | reg [DATA_OUT_WIDTH-1:0] mem[(2**FIFO_DEPTH)-1:0]; 55 | 56 | always @(posedge data_in_clock) 57 | begin 58 | if( data_in_enable ) 59 | begin 60 | mem[ data_in_address ][index-:DATA_IN_WIDTH]<= data_in; 61 | end 62 | end 63 | 64 | always @(posedge data_in_clock or posedge reset) 65 | begin 66 | if( reset ) 67 | begin 68 | data_in_address <= 0; 69 | count <= 0; 70 | index <= DATA_OUT_WIDTH - 1; 71 | end 72 | else if (data_in_reset) 73 | begin 74 | data_in_address <= data_in_reset_address; 75 | index <= DATA_OUT_WIDTH - 1; 76 | end 77 | else 78 | begin 79 | if( data_in_enable ) 80 | begin 81 | count <= count + 1; 82 | index <= index - DATA_IN_WIDTH; 83 | if (index <= DATA_IN_WIDTH) 84 | begin 85 | data_in_address <= data_in_address + 1; 86 | index <= DATA_OUT_WIDTH - 1; 87 | end 88 | end 89 | end 90 | end 91 | 92 | always @(posedge data_out_clock or posedge reset) 93 | begin 94 | if (reset) 95 | begin 96 | data_out <= 0; 97 | data_out_address <= 0; 98 | end 99 | else if (data_out_reset) 100 | begin 101 | data_out_address <= data_out_reset_address; 102 | end 103 | else if (data_out_enable) 104 | begin 105 | data_out <= mem[data_out_address]; 106 | data_out_address <= data_out_address + 1; 107 | end 108 | end 109 | end 110 | else 111 | begin 112 | initial 113 | begin 114 | $display("OUT <= IN"); 115 | end 116 | 117 | reg [DATA_IN_WIDTH-1:0] mem[(2**FIFO_DEPTH)-1:0]; 118 | 119 | always @(posedge data_in_clock) 120 | begin 121 | if( data_in_enable ) 122 | begin 123 | mem[ data_in_address ] <= data_in; 124 | end 125 | end 126 | 127 | always @(posedge data_in_clock or posedge reset) 128 | begin 129 | if( reset ) 130 | begin 131 | data_in_address <= 0; 132 | count <= 0; 133 | end 134 | else if (data_in_reset) 135 | begin 136 | data_in_address <= data_in_reset_address; 137 | end 138 | else 139 | begin 140 | if( data_in_enable ) 141 | begin 142 | data_in_address <= data_in_address + 1; 143 | count <= count + 1; 144 | end 145 | end 146 | end 147 | 148 | always @(posedge data_out_clock or posedge reset) 149 | begin 150 | if (reset) 151 | begin 152 | data_out <= 0; 153 | data_out_address <= 0; 154 | index <= DATA_IN_WIDTH - 1; 155 | end 156 | else if (data_out_reset) 157 | begin 158 | data_out_address <= data_out_reset_address; 159 | index <= DATA_IN_WIDTH - 1; 160 | end 161 | else if (data_out_enable) 162 | begin 163 | data_out <= mem[data_out_address][index-:DATA_OUT_WIDTH]; 164 | index <= index - DATA_OUT_WIDTH; 165 | if (index <= DATA_OUT_WIDTH) 166 | begin 167 | index <= DATA_IN_WIDTH - 1; 168 | data_out_address <= data_out_address + 1; 169 | end 170 | end 171 | end 172 | end 173 | endgenerate 174 | 175 | endmodule 176 | -------------------------------------------------------------------------------- /MAC/rtl/mac/mac_fifo/mac_fifo.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module mac_fifo #( 4 | parameter DATA_IN_WIDTH = 32, 5 | parameter DATA_OUT_WIDTH = 8, 6 | parameter FIFO_DEPTH = 12 7 | )( 8 | input wire reset, 9 | 10 | // IN PORT 11 | input wire [DATA_IN_WIDTH-1:0] data_in, 12 | input wire data_in_clock, 13 | input wire data_in_enable, 14 | input wire data_in_start, 15 | input wire data_in_end, 16 | 17 | // OUT PORT 18 | output wire [DATA_OUT_WIDTH-1:0] data_out, 19 | input wire data_out_clock, 20 | input wire data_out_enable, 21 | output wire data_out_start, 22 | output wire data_out_end, 23 | 24 | input wire retry, 25 | input wire error, 26 | output reg [FIFO_DEPTH-6:0] frame_count 27 | ); 28 | 29 | always @(posedge data_in_end or posedge data_out_end or posedge reset) 30 | begin 31 | if (reset) 32 | begin 33 | frame_count <= 0; 34 | end 35 | else if (data_in_end) 36 | begin 37 | frame_count <= frame_count + 1; 38 | end 39 | else if (data_out_end) 40 | begin 41 | frame_count <= frame_count - 1; 42 | end 43 | 44 | end 45 | 46 | generate if (DATA_IN_WIDTH > DATA_OUT_WIDTH) 47 | begin 48 | genvar i; 49 | wire [(DATA_IN_WIDTH-1)+(2*(DATA_IN_WIDTH/DATA_OUT_WIDTH)):0] fifo_data_in; 50 | wire [DATA_OUT_WIDTH + 1:0] fifo_data_out; 51 | 52 | wire [FIFO_DEPTH-1:0] data_in_address; 53 | reg [FIFO_DEPTH-1:0] data_in_address_tmp; 54 | wire [FIFO_DEPTH-1:0] data_out_address; 55 | reg [FIFO_DEPTH-1:0] data_out_address_tmp; 56 | 57 | always @(posedge data_out_start or posedge reset) 58 | begin 59 | if (reset) 60 | begin 61 | data_out_address_tmp <= 0; 62 | end 63 | else if (data_out_start) 64 | begin 65 | data_out_address_tmp <= data_out_address; 66 | end 67 | end 68 | 69 | always @(posedge data_in_start or posedge reset) 70 | begin 71 | if (reset) 72 | begin 73 | data_in_address_tmp <= 0; 74 | end 75 | else if (data_in_start) 76 | begin 77 | data_in_address_tmp <= data_in_address; 78 | end 79 | end 80 | 81 | for (i = 0; i < DATA_IN_WIDTH/DATA_OUT_WIDTH; i = i + 1) 82 | begin 83 | assign fifo_data_in [(DATA_IN_WIDTH-1)+(2*(DATA_IN_WIDTH/DATA_OUT_WIDTH)-(i*(DATA_OUT_WIDTH+2)))-:DATA_OUT_WIDTH] = data_in [((DATA_IN_WIDTH-1)-(i*DATA_OUT_WIDTH))-:DATA_OUT_WIDTH]; 84 | if ( i == 0 ) 85 | begin 86 | assign fifo_data_in [(DATA_IN_WIDTH-1)+(2*(DATA_IN_WIDTH/DATA_OUT_WIDTH)-(i*(DATA_OUT_WIDTH+2)))-DATA_OUT_WIDTH-:2] = { data_in_start, 1'b0 }; 87 | end 88 | else if ( i == DATA_IN_WIDTH/DATA_OUT_WIDTH - 1) 89 | begin 90 | assign fifo_data_in [(DATA_IN_WIDTH-1)+(2*(DATA_IN_WIDTH/DATA_OUT_WIDTH)-(i*(DATA_OUT_WIDTH+2)))-DATA_OUT_WIDTH-:2] = { 1'b0, data_in_end }; 91 | end 92 | else 93 | begin 94 | assign fifo_data_in [(DATA_IN_WIDTH-1)+(2*(DATA_IN_WIDTH/DATA_OUT_WIDTH)-(i*(DATA_OUT_WIDTH+2)))-DATA_OUT_WIDTH-:2] = { 1'b0, 1'b0 }; 95 | end 96 | end 97 | 98 | assign {data_out, data_out_start, data_out_end} = fifo_data_out; 99 | 100 | fifo #( 101 | .DATA_IN_WIDTH ((DATA_IN_WIDTH)+(2*(DATA_IN_WIDTH/DATA_OUT_WIDTH))), 102 | .DATA_OUT_WIDTH (DATA_OUT_WIDTH + 2), 103 | .FIFO_DEPTH (12) 104 | ) 105 | U_fifo ( 106 | .reset(reset), 107 | .count(), 108 | // IN PORT 109 | .data_in(fifo_data_in), 110 | .data_in_clock(data_in_clock), 111 | .data_in_enable(data_in_enable), 112 | .data_in_address(data_in_address), 113 | .data_in_reset(error), 114 | .data_in_reset_address(data_in_address_tmp), 115 | // OUT PORT 116 | .data_out(fifo_data_out), 117 | .data_out_clock(data_out_clock), 118 | .data_out_enable(data_out_enable), 119 | .data_out_address(data_out_address), 120 | .data_out_reset(retry), 121 | .data_out_reset_address(data_out_address_tmp) 122 | 123 | ); 124 | 125 | end 126 | else 127 | begin 128 | genvar i; 129 | localparam FIFO_DATA_OUT_WIDTH = (DATA_OUT_WIDTH + (2 * (DATA_OUT_WIDTH/DATA_IN_WIDTH))); 130 | localparam FIFO_DATA_OUT_MAX_INDEX = (FIFO_DATA_OUT_WIDTH - 1); 131 | localparam FIFO_DATA_IN_WIDTH = (DATA_IN_WIDTH + 2); 132 | localparam START_OFFSET = (DATA_IN_WIDTH); 133 | localparam END_OFFSET = (DATA_IN_WIDTH + 1); 134 | 135 | wire [(DATA_OUT_WIDTH-1)+(2*(DATA_OUT_WIDTH/DATA_IN_WIDTH)):0] fifo_data_out; 136 | wire [DATA_IN_WIDTH + 1:0] fifo_data_in; 137 | wire [(DATA_OUT_WIDTH/DATA_IN_WIDTH)-1:0] data_out_start_tmp; 138 | wire [(DATA_OUT_WIDTH/DATA_IN_WIDTH)-1:0] data_out_end_tmp; 139 | 140 | wire [FIFO_DEPTH-1:0] data_in_address; 141 | reg [FIFO_DEPTH-1:0] data_in_address_tmp; 142 | wire [FIFO_DEPTH-1:0] data_out_address; 143 | reg [FIFO_DEPTH-1:0] data_out_address_tmp; 144 | 145 | always @(posedge data_out_start or posedge reset) 146 | begin 147 | if (reset) 148 | begin 149 | data_out_address_tmp <= 0; 150 | end 151 | else if (data_out_start) 152 | begin 153 | data_out_address_tmp <= data_out_address; 154 | end 155 | end 156 | 157 | always @(posedge data_in_start or posedge reset) 158 | begin 159 | if (reset) 160 | begin 161 | data_in_address_tmp <= 0; 162 | end 163 | else if (data_in_start) 164 | begin 165 | data_in_address_tmp <= data_in_address; 166 | end 167 | end 168 | 169 | for (i = 0; i < DATA_OUT_WIDTH/DATA_IN_WIDTH; i = i + 1) 170 | begin 171 | assign data_out [(DATA_OUT_WIDTH-1)-(i*DATA_IN_WIDTH)-:DATA_IN_WIDTH] = fifo_data_out [(DATA_OUT_WIDTH-1)+(2*(DATA_OUT_WIDTH/DATA_IN_WIDTH)-(i*(DATA_IN_WIDTH+2)))-:DATA_IN_WIDTH]; 172 | assign data_out_start_tmp[i-:1] = fifo_data_out [FIFO_DATA_OUT_MAX_INDEX-START_OFFSET-i*FIFO_DATA_IN_WIDTH-:1]; 173 | assign data_out_end_tmp[i-:1] = fifo_data_out [FIFO_DATA_OUT_MAX_INDEX-END_OFFSET-i*FIFO_DATA_IN_WIDTH-:1]; 174 | 175 | assign data_out_start = | data_out_start_tmp; 176 | assign data_out_end = | data_out_end_tmp; 177 | end 178 | 179 | assign fifo_data_in = {data_in, data_in_start, data_in_end}; 180 | 181 | fifo #( 182 | .DATA_IN_WIDTH ((DATA_IN_WIDTH)+2), 183 | .DATA_OUT_WIDTH (DATA_OUT_WIDTH + 2*(DATA_OUT_WIDTH/DATA_IN_WIDTH)), 184 | .FIFO_DEPTH (12) 185 | ) 186 | U_fifo ( 187 | .reset(reset), 188 | .count(), 189 | 190 | // IN PORT 191 | .data_in(fifo_data_in), 192 | .data_in_clock(data_in_clock), 193 | .data_in_enable(data_in_enable), 194 | .data_in_address(data_in_address), 195 | .data_in_reset(error), 196 | .data_in_reset_address(data_in_address_tmp), 197 | // OUT PORT 198 | .data_out(fifo_data_out), 199 | .data_out_clock(data_out_clock), 200 | .data_out_enable(data_out_enable), 201 | .data_out_address(data_out_address), 202 | .data_out_reset(retry), 203 | .data_out_reset_address(data_out_address_tmp) 204 | 205 | ); 206 | end 207 | endgenerate 208 | 209 | endmodule 210 | 211 | -------------------------------------------------------------------------------- /MAC/rtl/mac/mac_loopback.v: -------------------------------------------------------------------------------- 1 | module mac_loopback( 2 | input wire reset, 3 | 4 | input wire tx_clock, 5 | input wire rx_clock, 6 | 7 | input wire carrier_sense, 8 | input wire collision, 9 | 10 | output wire tx_enable, 11 | output wire [7:0] tx_data, 12 | 13 | input wire rx_data_valid, 14 | input wire [7:0] rx_data, 15 | input wire rx_error 16 | ); 17 | 18 | wire [7:0] data_out; 19 | wire data_out_start; 20 | wire data_out_end; 21 | reg data_out_clock; 22 | wire data_out_enable; 23 | wire data_available; 24 | 25 | tx_sm U_tx_sm( 26 | .reset(reset), 27 | .clock(tx_clock), 28 | 29 | .fifo_data(data_out), 30 | .fifo_data_read(data_out_enable), 31 | .fifo_data_start(data_out_start), 32 | .fifo_data_end(data_out_end), 33 | .fifo_data_available(data_available), 34 | 35 | .mode(1'b1), 36 | 37 | .carrier_sense(carrier_sense), 38 | .collision(collision), 39 | 40 | .tx_enable(tx_enable), 41 | .tx_data(tx_data) 42 | ); 43 | 44 | rx_sm #(.FIFO_DEPTH(10)) U_rx_sm( 45 | .reset(reset), 46 | .clock(rx_clock), 47 | 48 | .data_out(data_out), 49 | .data_out_clock(tx_clock), 50 | .data_out_enable(data_out_enable), 51 | .data_out_start(data_out_start), 52 | .data_out_end(data_out_end), 53 | .data_available(data_available), 54 | 55 | .rx_data_valid(rx_data_valid), 56 | .rx_data(rx_data), 57 | .rx_error(rx_error) 58 | ); 59 | endmodule 60 | -------------------------------------------------------------------------------- /MAC/rtl/mac/rx/rx_sm.v: -------------------------------------------------------------------------------- 1 | module rx_sm #( 2 | parameter STATE_IDLE = 3'h0, 3 | parameter STATE_PREAMBLE = 3'h1, 4 | parameter STATE_DATA = 3'h2, 5 | parameter STATE_OK = 3'h3, 6 | parameter STATE_DROP = 3'h4, 7 | parameter STATE_ERROR = 3'h5, 8 | parameter FIFO_DEPTH = 12 9 | )( 10 | input reset, 11 | input clock, 12 | 13 | input rx_data_valid, 14 | input [7:0] rx_data, 15 | input rx_error, 16 | 17 | // OUT PORT 18 | output wire [7:0] data_out, 19 | input wire data_out_clock, 20 | input wire data_out_enable, 21 | output wire data_out_start, 22 | output wire data_out_end, 23 | output wire [FIFO_DEPTH-1:0] data_out_address, 24 | input wire data_out_reset, 25 | input wire [FIFO_DEPTH-1:0] data_out_reset_address, 26 | output reg data_available, 27 | output wire fifo_full 28 | ); 29 | 30 | localparam CRC_RESIDUE = 32'hC704DD7B; 31 | localparam CRC_POLYNOMIAL = 32'h04C11DB7; 32 | localparam CRC_SEED = 32'hFFFFFFFF; 33 | localparam MAX_SIZE = 1518; 34 | localparam MIN_SIZE = 64; 35 | 36 | wire [FIFO_DEPTH:0] fifo_count; 37 | wire [FIFO_DEPTH-1:0] data_in_address; 38 | reg [FIFO_DEPTH-1:0] data_in_reset_address; 39 | reg start_of_frame; 40 | reg end_of_frame; 41 | reg error; 42 | 43 | reg [2:0] state; 44 | reg [2:0] next_state; 45 | reg [15:0] frame_length_counter; 46 | reg [15:0] data_counter; 47 | reg data_write_enable; 48 | reg too_long; 49 | reg too_short; 50 | 51 | reg crc_init; 52 | reg data_enable; 53 | wire [31:0] crc_out; 54 | 55 | reg [39:0] data; 56 | 57 | // RX State Machine 58 | always @ (posedge reset or posedge clock) 59 | if (reset) 60 | state <= STATE_IDLE; 61 | else 62 | state <= next_state; 63 | 64 | always @ (*) 65 | case (state) 66 | STATE_IDLE: 67 | if (rx_data_valid && rx_data == 8'h55) 68 | next_state = STATE_PREAMBLE; 69 | else 70 | next_state = STATE_IDLE; 71 | STATE_PREAMBLE: 72 | if (!rx_data_valid) 73 | next_state = STATE_ERROR; 74 | else if (rx_error) 75 | next_state = STATE_DROP; 76 | else if (rx_data == 8'hd5) 77 | next_state = STATE_DATA; 78 | else if (rx_data == 8'h55) 79 | next_state = STATE_PREAMBLE; 80 | else 81 | next_state = STATE_DROP; 82 | STATE_DATA: 83 | if (!rx_data_valid && !too_short && !too_long && crc_out == CRC_RESIDUE) 84 | next_state = STATE_OK; 85 | else if ((!rx_data_valid && (too_short || too_long)) || (!rx_data_valid && crc_out != CRC_RESIDUE)) 86 | next_state = STATE_ERROR; 87 | else if (fifo_full) 88 | next_state = STATE_DROP; 89 | else if (rx_error || too_long) 90 | next_state = STATE_DROP; 91 | else 92 | next_state = STATE_DATA; 93 | STATE_DROP: 94 | if (!rx_data_valid) 95 | next_state = STATE_ERROR; 96 | else 97 | next_state = STATE_DROP; 98 | STATE_OK: 99 | next_state = STATE_IDLE; 100 | STATE_ERROR: 101 | next_state = STATE_IDLE; 102 | default: 103 | next_state = STATE_IDLE; 104 | endcase 105 | 106 | 107 | always @(posedge clock or posedge reset) 108 | begin 109 | if (reset) 110 | begin 111 | data <= 32'h00000000; 112 | end 113 | else if (state == STATE_IDLE) 114 | begin 115 | data <= 32'h00000000; 116 | end 117 | else 118 | begin 119 | data[39-:8] <= data[31-:8]; 120 | data[31-:8] <= data[23-:8]; 121 | data[23-:8] <= data[15-:8]; 122 | data[15-:8] <= data[7-:8]; 123 | data[7-:8] <= rx_data; 124 | end 125 | end 126 | 127 | always @ ( state or fifo_count ) 128 | begin 129 | if (fifo_count && state == STATE_OK) 130 | begin 131 | data_available <= 1; 132 | end 133 | else if (!fifo_count) 134 | begin 135 | data_available <= 0; 136 | end 137 | end 138 | 139 | always @ (posedge clock or posedge reset) 140 | if (reset) 141 | data_counter <= 0; 142 | else if (state == STATE_DATA) 143 | data_counter = data_counter + 1; 144 | else 145 | data_counter = 0; 146 | 147 | always @ (data_counter or state) 148 | if (data_counter > 4 && state == STATE_DATA && next_state == STATE_DATA) 149 | data_write_enable = 1; 150 | else 151 | data_write_enable = 0; 152 | 153 | always @(data_counter) 154 | if (data_counter == 5) 155 | start_of_frame = 1; 156 | else 157 | start_of_frame = 0; 158 | 159 | always @(state or next_state) 160 | if (state == STATE_DATA && next_state != STATE_DATA) 161 | end_of_frame = 1; 162 | else 163 | end_of_frame = 0; 164 | 165 | always @(state) 166 | if (state == STATE_ERROR) 167 | error = 1; 168 | else 169 | error = 0; 170 | 171 | // CRC Interface 172 | always @(state) 173 | if (state == STATE_DATA) 174 | data_enable = 1; 175 | else 176 | data_enable = 0; 177 | 178 | always @(state or next_state) 179 | if (state == STATE_PREAMBLE && next_state == STATE_DATA) 180 | begin 181 | crc_init <= 1; 182 | data_in_reset_address <= data_in_address; 183 | end 184 | else 185 | crc_init = 0; 186 | 187 | always @ (posedge clock or posedge reset) 188 | if (reset) 189 | frame_length_counter <= 0; 190 | else if (state == STATE_DATA) 191 | frame_length_counter = frame_length_counter + 1; 192 | else 193 | frame_length_counter = 0; 194 | 195 | always @ (frame_length_counter) 196 | if (frame_length_counter < MIN_SIZE) 197 | too_short = 1; 198 | else 199 | too_short = 0; 200 | 201 | always @ (frame_length_counter) 202 | if (frame_length_counter > MAX_SIZE) 203 | too_long = 1; 204 | else 205 | too_long = 0; 206 | 207 | // CRC 208 | crc #( .POLYNOMIAL(CRC_POLYNOMIAL), 209 | .DATA_WIDTH(8), 210 | .CRC_WIDTH(32), 211 | .SEED(CRC_SEED)) 212 | U_crc( 213 | .reset(reset), 214 | .clock(clock), 215 | .init(crc_init), 216 | .data(rx_data), 217 | .data_enable(data_enable), 218 | .crc_out(crc_out) 219 | ); 220 | 221 | // FIFO 222 | fifo #( 223 | .DATA_WIDTH (8), 224 | .FIFO_DEPTH (FIFO_DEPTH) 225 | ) 226 | U_fifo ( 227 | .reset(reset), 228 | .count(fifo_count), 229 | .full(fifo_full), 230 | 231 | // IN PORT 232 | .data_in(data[39-:8]), 233 | .data_in_start(start_of_frame), 234 | .data_in_end(end_of_frame), 235 | .data_in_clock(clock), 236 | .data_in_enable(data_write_enable), 237 | .data_in_address(data_in_address), 238 | .data_in_reset(error), 239 | .data_in_reset_address(data_in_reset_address), 240 | // OUT PORT 241 | .data_out(data_out), 242 | .data_out_start(data_out_start), 243 | .data_out_end(data_out_end), 244 | .data_out_clock(data_out_clock), 245 | .data_out_enable(data_out_enable), 246 | .data_out_address(data_out_address), 247 | .data_out_reset(data_out_reset), 248 | .data_out_reset_address(data_out_reset_address) 249 | ); 250 | 251 | endmodule 252 | -------------------------------------------------------------------------------- /MAC/rtl/mac/rx/tb/dut.v: -------------------------------------------------------------------------------- 1 | reg reset; 2 | reg clock; 3 | 4 | wire [7:0] rx_data; 5 | wire rx_data_valid; 6 | reg rx_error; 7 | 8 | wire [7:0] data_out_sig; 9 | wire data_out_start_sig; 10 | wire data_out_end_sig; 11 | reg data_out_clock; 12 | wire data_out_enable; 13 | wire data_available; 14 | wire fifo_full; 15 | 16 | rx_sm #(.FIFO_DEPTH(10)) U_rx_sm( 17 | .reset(reset), 18 | .clock(clock), 19 | 20 | // OUT PORT 21 | .data_out(data_out_sig), 22 | .data_out_clock(data_out_clock), 23 | .data_out_enable(data_out_enable), 24 | .data_out_start(data_out_start_sig), 25 | .data_out_end(data_out_end_sig), 26 | .data_available(data_available), 27 | .fifo_full(fifo_full), 28 | 29 | .rx_data_valid(rx_data_valid), 30 | .rx_data(rx_data), 31 | .rx_error(rx_error) 32 | ); 33 | 34 | utilities #(.OUT_WIDTH (1), 35 | .IN_WIDTH (1)) 36 | util ( 37 | .data_in(1'b0), 38 | .data_in_enable(), 39 | .data_out(), 40 | .data_out_enable(), 41 | .clock(clock) 42 | ); 43 | 44 | utilities #(.OUT_WIDTH (8), 45 | .IN_WIDTH (8)) 46 | data ( 47 | .data_in(), 48 | .data_in_enable(), 49 | .data_out(rx_data), 50 | .data_out_enable(rx_data_valid), 51 | .clock(clock) 52 | ); 53 | 54 | utilities #(.OUT_WIDTH (8), 55 | .IN_WIDTH (8), 56 | .DEBUG(1)) 57 | data_out ( 58 | .data_in(data_out_sig), 59 | .data_in_enable(data_out_enable), 60 | .data_out(), 61 | .data_out_enable(), 62 | .clock(data_out_clock) 63 | ); 64 | 65 | utilities #(.OUT_WIDTH (1), 66 | .IN_WIDTH (1)) 67 | data_out_start ( 68 | .data_in(data_out_start_sig), 69 | .data_in_enable(), 70 | .data_out(), 71 | .data_out_enable(), 72 | .clock(data_out_clock) 73 | ); 74 | 75 | utilities #(.OUT_WIDTH (1), 76 | .IN_WIDTH (1)) 77 | data_out_end ( 78 | .data_in(data_out_end_sig), 79 | .data_in_enable(), 80 | .data_out(), 81 | .data_out_enable(), 82 | .clock(data_out_clock) 83 | ); 84 | 85 | initial 86 | begin 87 | clock = 0; 88 | reset = 1; 89 | rx_error = 0; 90 | data_out_clock = 0; 91 | end 92 | 93 | always 94 | #5 clock = ~clock; 95 | 96 | always 97 | #5 data_out_clock = ~data_out_clock; 98 | -------------------------------------------------------------------------------- /MAC/rtl/mac/rx/tb/mac_tb2.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module mac_test(); 4 | 5 | reg reset; 6 | 7 | wire [31:0] data_out; 8 | reg data_out_clock; 9 | reg data_out_enable; 10 | wire data_out_start; 11 | wire data_out_end; 12 | wire [6:0] frame_count; 13 | 14 | reg rx_clock; 15 | reg rx_data_valid; 16 | reg rx_error; 17 | reg [7:0] rx_data; 18 | reg [7:0] packet [0:1518]; 19 | reg [31:0] tempdata; 20 | 21 | integer i; 22 | wire [31:0] crc; 23 | 24 | mac U_mac ( 25 | .reset(reset), 26 | 27 | // OUT PORT 28 | .data_out(data_out), 29 | .data_out_clock(data_out_clock), 30 | .data_out_enable(data_out_enable), 31 | .data_out_start(data_out_start), 32 | .data_out_end(data_out_end), 33 | .frame_count(frame_count), 34 | 35 | .rx_clock(rx_clock), 36 | 37 | .rx_data_valid(rx_data_valid), 38 | .rx_error(rx_error), 39 | 40 | .rx_data(rx_data) 41 | ); 42 | 43 | initial 44 | begin 45 | $dumpfile("test.vcd"); 46 | $dumpvars(0, mac_test, U_mac, U_mac.U_rx_sm, U_mac.U_rx_sm.U_crc); 47 | end 48 | 49 | initial 50 | begin 51 | reset = 1; 52 | data_out_clock = 0; 53 | data_out_enable = 0; 54 | rx_clock = 0; 55 | rx_data = 0; 56 | $readmemh("rx.hex", packet); 57 | 58 | 59 | $monitor("STATE :%0d FRAME_LENGTH: %0d CRC: %0x", U_mac.U_rx_sm.state, U_mac.U_rx_sm.frame_length_counter, U_mac.U_rx_sm.crc_out); 60 | 61 | #15 reset = 0; 62 | 63 | // Send a packet 64 | for(i = 0; i < 72; i = i + 1) 65 | begin 66 | push(packet[i], 1, 0); 67 | end 68 | 69 | for(i = 72; i < 80; i = i + 1) 70 | begin 71 | push(packet[i], 0, 0); 72 | end 73 | 74 | pop(tempdata); 75 | pop(tempdata); 76 | pop(tempdata); 77 | pop(tempdata); 78 | pop(tempdata); 79 | pop(tempdata); 80 | pop(tempdata); 81 | pop(tempdata); 82 | pop(tempdata); 83 | pop(tempdata); 84 | pop(tempdata); 85 | pop(tempdata); 86 | pop(tempdata); 87 | pop(tempdata); 88 | pop(tempdata); 89 | pop(tempdata); 90 | 91 | $finish; 92 | end 93 | 94 | always 95 | #20 data_out_clock = ~data_out_clock; 96 | 97 | always 98 | #1 rx_clock = ~rx_clock; 99 | 100 | task push; 101 | input [7:0] data; 102 | input data_valid; 103 | input data_error; 104 | begin 105 | rx_data = data; 106 | rx_data_valid = data_valid; 107 | rx_error = data_error; 108 | @(posedge rx_clock); 109 | #1 rx_data_valid = 0; 110 | rx_error = 0; 111 | $display("Pushed: %x Valid: %b Error: %b",data, data_valid, data_error ); 112 | end 113 | endtask 114 | 115 | task pop; 116 | output [31:0] data; 117 | begin 118 | data_out_enable = 1; 119 | @(posedge data_out_clock); 120 | #1 data_out_enable = 0; 121 | data = data_out; 122 | $display("Popped %x Start: %b End: %b ", data, data_out_start, data_out_end); 123 | end 124 | endtask 125 | 126 | endmodule 127 | 128 | -------------------------------------------------------------------------------- /MAC/rtl/mac/rx/tb/packet.hex: -------------------------------------------------------------------------------- 1 | 55 55 55 55 55 55 55 D5 ff ff ff ff ff ff d0 50 99 98 96 8c 08 00 45 00 00 4e 22 2d 00 00 80 11 f5 21 a9 fe cf 53 a9 fe ff ff 00 89 00 89 00 3a 7a aa b0 eb 01 10 00 01 00 00 00 00 00 00 20 45 4d 45 4a 46 47 45 46 43 4f 45 45 45 46 45 46 46 4b 45 46 46 43 43 4f 45 44 45 50 45 4e 41 41 00 00 20 00 01 c0 f4 47 ca 2 | -------------------------------------------------------------------------------- /MAC/rtl/mac/rx/tb/rx_sm_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module rx_sm_tb (); 4 | 5 | `include "dut.v" 6 | 7 | integer i; 8 | integer j; 9 | 10 | reg [7:0] packet [0:1518]; 11 | reg [7:0] tempdata; 12 | reg tempstart; 13 | reg tempend; 14 | 15 | initial 16 | begin 17 | $dumpfile("test.vcd"); 18 | $dumpvars(0,rx_sm_tb,U_rx_sm); 19 | end 20 | 21 | initial 22 | begin 23 | #15 reset = 0; 24 | 25 | $readmemh("packet.hex", packet); 26 | 27 | util.assert(data_available == 0, "Data available not set"); 28 | 29 | // Send a packet 30 | for(i = 0; i < 104; i = i + 1) 31 | begin 32 | data.sync_write(packet[i]); 33 | end 34 | 35 | #1000 36 | 37 | util.assert(data_available == 1, "Data available set"); 38 | 39 | // Read the packet out 40 | fork 41 | data_out.sync_read(tempdata); 42 | data_out_start.sync_read(tempstart); 43 | data_out_end.sync_read(tempend); 44 | join 45 | 46 | util.assert(tempdata == packet[8], "Reading FIFO Data"); 47 | util.assert(tempstart == 1, "Reading FIFO Start"); 48 | util.assert(tempend == 0, "Reading FIFO End"); 49 | 50 | for ( i = 9; i < 99; i = i + 1) 51 | begin 52 | fork 53 | data_out.sync_read(tempdata); 54 | data_out_start.sync_read(tempstart); 55 | data_out_end.sync_read(tempend); 56 | join 57 | util.assert(tempdata == packet[i], "Reading FIFO Data"); 58 | util.assert(tempstart == 0, "Reading FIFO Start"); 59 | util.assert(tempend == 0, "Reading FIFO End"); 60 | end 61 | 62 | fork 63 | data_out.sync_read(tempdata); 64 | data_out_start.sync_read(tempstart); 65 | data_out_end.sync_read(tempend); 66 | join 67 | 68 | util.assert(tempdata == packet[99], "Reading FIFO Data"); 69 | util.assert(tempstart == 0, "Reading FIFO Start"); 70 | util.assert(tempend == 1, "Reading FIFO End"); 71 | 72 | util.assert(data_available == 0, "Data available not set"); 73 | 74 | /* 75 | // Send a packet 76 | for(i = 0; i < 104; i = i + 1) 77 | begin 78 | data.sync_write(packet[i]); 79 | end 80 | 81 | #1000 82 | 83 | util.assert(data_available == 1, "Data available set"); 84 | 85 | // Read the packet out 86 | fork 87 | data_out.sync_read(tempdata); 88 | data_out_start.sync_read(tempstart); 89 | data_out_end.sync_read(tempend); 90 | join 91 | 92 | util.assert(tempdata == packet[8], "Reading FIFO Data"); 93 | util.assert(tempstart == 1, "Reading FIFO Start"); 94 | util.assert(tempend == 0, "Reading FIFO End"); 95 | 96 | for ( i = 9; i < 99; i = i + 1) 97 | begin 98 | fork 99 | data_out.sync_read(tempdata); 100 | data_out_start.sync_read(tempstart); 101 | data_out_end.sync_read(tempend); 102 | join 103 | util.assert(tempdata == packet[i], "Reading FIFO Data"); 104 | util.assert(tempstart == 0, "Reading FIFO Start"); 105 | util.assert(tempend == 0, "Reading FIFO End"); 106 | end 107 | 108 | fork 109 | data_out.sync_read(tempdata); 110 | data_out_start.sync_read(tempstart); 111 | data_out_end.sync_read(tempend); 112 | join 113 | 114 | util.assert(tempdata == packet[99], "Reading FIFO Data"); 115 | util.assert(tempstart == 0, "Reading FIFO Start"); 116 | util.assert(tempend == 1, "Reading FIFO End"); 117 | 118 | util.assert(data_available == 0, "Data available not set"); 119 | 120 | // Send a packet with error 121 | for(i = 0; i < 103; i = i + 1) 122 | begin 123 | data.sync_write(packet[i]); 124 | end 125 | 126 | data.sync_write(8'hFF); 127 | 128 | #1000 129 | 130 | util.assert(data_available == 0, "Data available not set"); 131 | 132 | // Send a packet 133 | for(i = 0; i < 104; i = i + 1) 134 | begin 135 | data.sync_write(packet[i]); 136 | end 137 | 138 | #1000 139 | 140 | util.assert(data_available == 1, "Data available set"); 141 | 142 | // Send a packet 143 | for(i = 0; i < 104; i = i + 1) 144 | begin 145 | data.sync_write(packet[i]); 146 | end 147 | 148 | #1000 149 | 150 | util.assert(data_available == 1, "Data available set"); 151 | 152 | // Read the packets out 153 | fork 154 | data_out.sync_read(tempdata); 155 | data_out_start.sync_read(tempstart); 156 | data_out_end.sync_read(tempend); 157 | join 158 | 159 | util.assert(tempdata == packet[8], "Reading FIFO Data"); 160 | util.assert(tempstart == 1, "Reading FIFO Start"); 161 | util.assert(tempend == 0, "Reading FIFO End"); 162 | 163 | for ( i = 9; i < 99; i = i + 1) 164 | begin 165 | fork 166 | data_out.sync_read(tempdata); 167 | data_out_start.sync_read(tempstart); 168 | data_out_end.sync_read(tempend); 169 | join 170 | util.assert(tempdata == packet[i], "Reading FIFO Data"); 171 | util.assert(tempstart == 0, "Reading FIFO Start"); 172 | util.assert(tempend == 0, "Reading FIFO End"); 173 | end 174 | 175 | fork 176 | data_out.sync_read(tempdata); 177 | data_out_start.sync_read(tempstart); 178 | data_out_end.sync_read(tempend); 179 | join 180 | 181 | util.assert(tempdata == packet[99], "Reading FIFO Data"); 182 | util.assert(tempstart == 0, "Reading FIFO Start"); 183 | util.assert(tempend == 1, "Reading FIFO End"); 184 | 185 | util.assert(data_available == 1, "Data available set"); 186 | 187 | // Read the packets out 188 | fork 189 | data_out.sync_read(tempdata); 190 | data_out_start.sync_read(tempstart); 191 | data_out_end.sync_read(tempend); 192 | join 193 | 194 | util.assert(tempdata == packet[8], "Reading FIFO Data"); 195 | util.assert(tempstart == 1, "Reading FIFO Start"); 196 | util.assert(tempend == 0, "Reading FIFO End"); 197 | 198 | for ( i = 9; i < 99; i = i + 1) 199 | begin 200 | fork 201 | data_out.sync_read(tempdata); 202 | data_out_start.sync_read(tempstart); 203 | data_out_end.sync_read(tempend); 204 | join 205 | util.assert(tempdata == packet[i], "Reading FIFO Data"); 206 | util.assert(tempstart == 0, "Reading FIFO Start"); 207 | util.assert(tempend == 0, "Reading FIFO End"); 208 | end 209 | 210 | fork 211 | data_out.sync_read(tempdata); 212 | data_out_start.sync_read(tempstart); 213 | data_out_end.sync_read(tempend); 214 | join 215 | 216 | util.assert(tempdata == packet[99], "Reading FIFO Data"); 217 | util.assert(tempstart == 0, "Reading FIFO Start"); 218 | util.assert(tempend == 1, "Reading FIFO End"); 219 | 220 | util.assert(data_available == 0, "Data available not set"); 221 | 222 | // Send lots of packets to fill the FIFO 223 | for(j = 0; j <= 11; j = j + 1) 224 | begin 225 | #1000 for(i = 0; i < 104; i = i + 1) 226 | begin 227 | data.sync_write(packet[i]); 228 | end 229 | end 230 | 231 | for(j = 0; j <= 10; j = j + 1) 232 | begin 233 | util.assert(data_available == 1, "Data available set"); 234 | // Read the packets out 235 | fork 236 | data_out.sync_read(tempdata); 237 | data_out_start.sync_read(tempstart); 238 | data_out_end.sync_read(tempend); 239 | join 240 | 241 | util.assert(tempdata == packet[8], "Reading FIFO Data"); 242 | util.assert(tempstart == 1, "Reading FIFO Start"); 243 | util.assert(tempend == 0, "Reading FIFO End"); 244 | 245 | for ( i = 9; i < 99; i = i + 1) 246 | begin 247 | fork 248 | data_out.sync_read(tempdata); 249 | data_out_start.sync_read(tempstart); 250 | data_out_end.sync_read(tempend); 251 | join 252 | util.assert(tempdata == packet[i], "Reading FIFO Data"); 253 | util.assert(tempstart == 0, "Reading FIFO Start"); 254 | util.assert(tempend == 0, "Reading FIFO End"); 255 | end 256 | 257 | fork 258 | data_out.sync_read(tempdata); 259 | data_out_start.sync_read(tempstart); 260 | data_out_end.sync_read(tempend); 261 | join 262 | 263 | util.assert(tempdata == packet[99], "Reading FIFO Data"); 264 | util.assert(tempstart == 0, "Reading FIFO Start"); 265 | util.assert(tempend == 1, "Reading FIFO End"); 266 | end 267 | 268 | util.assert(data_available == 0, "Data available not set"); 269 | */ 270 | util.display(); 271 | 272 | $finish; 273 | end 274 | 275 | endmodule 276 | 277 | -------------------------------------------------------------------------------- /MAC/rtl/mac/tb/dut.v: -------------------------------------------------------------------------------- 1 | reg reset; 2 | reg tx_clock; 3 | reg rx_clock; 4 | reg carrier_sense; 5 | reg collision; 6 | wire tx_enable; 7 | wire [7:0] tx_data; 8 | wire rx_data_valid; 9 | wire [7:0] rx_data; 10 | wire rx_error; 11 | reg expected_tx_enable; 12 | 13 | mac_loopback U_mac_loopback( 14 | .reset(reset), 15 | 16 | .tx_clock(tx_clock), 17 | .rx_clock(rx_clock), 18 | 19 | .carrier_sense(carrier_sense), 20 | .collision(collision), 21 | 22 | .tx_enable(tx_enable), 23 | .tx_data(tx_data), 24 | 25 | .rx_data_valid(rx_data_valid), 26 | .rx_data(rx_data), 27 | .rx_error(rx_error) 28 | ); 29 | 30 | utilities #(.OUT_WIDTH (1), 31 | .IN_WIDTH (1)) 32 | util ( 33 | .data_in(1'b0), 34 | .data_in_enable(), 35 | .data_out(), 36 | .data_out_enable(), 37 | .clock() 38 | ); 39 | 40 | utilities #(.OUT_WIDTH (8), 41 | .IN_WIDTH (8)) 42 | data_in ( 43 | .data_in(), 44 | .data_in_enable(), 45 | .data_out(rx_data), 46 | .data_out_enable(rx_data_valid), 47 | .clock(rx_clock) 48 | ); 49 | 50 | utilities #(.OUT_WIDTH (8), 51 | .IN_WIDTH (8)) 52 | data_out ( 53 | .data_in(tx_data), 54 | .data_in_enable(), 55 | .data_out(), 56 | .data_out_enable(), 57 | .clock(tx_clock) 58 | ); 59 | 60 | monitor #(.WIDTH(1)) 61 | tx_enable_monitor( 62 | .data(tx_enable), 63 | .expected(expected_tx_enable), 64 | .clock(tx_clock)); 65 | 66 | initial 67 | begin 68 | rx_clock = 0; 69 | tx_clock = 0; 70 | reset = 1; 71 | collision = 0; 72 | carrier_sense = 0; 73 | expected_tx_enable = 0; 74 | end 75 | 76 | always 77 | #5 rx_clock = ~rx_clock; 78 | 79 | always 80 | #5 81 | tx_clock = ~tx_clock; 82 | -------------------------------------------------------------------------------- /MAC/rtl/mac/tb/mac_loopback_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module mac_loopback_tb (); 4 | 5 | `include "dut.v" 6 | 7 | integer i; 8 | integer j; 9 | 10 | reg [7:0] packet [0:1518]; 11 | reg [7:0] tempdata; 12 | reg tempstart; 13 | reg tempend; 14 | 15 | initial 16 | begin 17 | $dumpfile("test.vcd"); 18 | $dumpvars(0,mac_loopback_tb); 19 | end 20 | 21 | initial 22 | begin 23 | #15 reset = 0; 24 | 25 | $readmemh("packet.hex", packet); 26 | 27 | // Send a packet 28 | for(i = 0; i < 104; i = i + 1) 29 | begin 30 | data_in.sync_write(packet[i]); 31 | end 32 | 33 | #20 34 | 35 | expected_tx_enable = 1; 36 | 37 | data_out.sync_read(tempdata); 38 | 39 | // MAC should then start transmitting 40 | for (i = 0; i < 104; i = i + 1) 41 | begin 42 | data_out.sync_read(tempdata); 43 | util.assert(tempdata == packet[i], "Tx Data"); 44 | expected_tx_enable = 1; 45 | $display("TX: %x", tempdata); 46 | end 47 | expected_tx_enable = 0; 48 | 49 | util.display(); 50 | 51 | $finish; 52 | end 53 | 54 | endmodule 55 | 56 | -------------------------------------------------------------------------------- /MAC/rtl/mac/tb/packet.hex: -------------------------------------------------------------------------------- 1 | 55 55 55 55 55 55 55 D5 ff ff ff ff ff ff d0 50 99 98 96 8c 08 00 45 00 00 4e 22 2d 00 00 80 11 f5 21 a9 fe cf 53 a9 fe ff ff 00 89 00 89 00 3a 7a aa b0 eb 01 10 00 01 00 00 00 00 00 00 20 45 4d 45 4a 46 47 45 46 43 4f 45 45 45 46 45 46 46 4b 45 46 46 43 43 4f 45 44 45 50 45 4e 41 41 00 00 20 00 01 c0 f4 47 ca 2 | -------------------------------------------------------------------------------- /MAC/rtl/mac/tx/random.v: -------------------------------------------------------------------------------- 1 | module random_gen( 2 | input reset, 3 | input clock, 4 | input init, 5 | input [3:0] retry_count, 6 | output reg trigger 7 | ); 8 | 9 | reg [9:0] random_sequence; 10 | reg [9:0] random; 11 | reg [9:0] random_counter; 12 | reg [7:0] slot_time_counter; //256*2=512bit=1 slot time 13 | 14 | always @ (posedge clock or posedge reset) 15 | if (reset) 16 | random_sequence <= 0; 17 | else 18 | random_sequence <= {random_sequence[8:0],~(random_sequence[2]^random_sequence[9])}; 19 | 20 | always @ (retry_count or random_sequence) 21 | case (retry_count) 22 | 4'h0 : random = {9'b0, random_sequence[0]}; 23 | 4'h1 : random = {8'b0, random_sequence[1:0]}; 24 | 4'h2 : random = {7'b0, random_sequence[2:0]}; 25 | 4'h3 : random = {6'b0, random_sequence[3:0]}; 26 | 4'h4 : random = {5'b0, random_sequence[4:0]}; 27 | 4'h5 : random = {4'b0, random_sequence[5:0]}; 28 | 4'h6 : random = {3'b0, random_sequence[6:0]}; 29 | 4'h7 : random = {2'b0, random_sequence[7:0]}; 30 | 4'h8 : random = {1'b0, random_sequence[8:0]}; 31 | 4'h9 : random = { random_sequence[9:0]}; 32 | default : random = { random_sequence[9:0]}; 33 | endcase 34 | 35 | always @ (posedge clock or posedge reset) 36 | if (reset) 37 | slot_time_counter <= 0; 38 | else if(init) 39 | slot_time_counter <= 0; 40 | else if(!trigger) 41 | slot_time_counter <= slot_time_counter + 1; 42 | 43 | always @ (posedge clock or posedge reset) 44 | if (reset) 45 | random_counter <= 0; 46 | else if (init) 47 | random_counter <= random; 48 | else if (random_counter != 0 && slot_time_counter == 255) 49 | random_counter <= random_counter - 1; 50 | 51 | always @ (posedge clock or posedge reset) 52 | if (reset) 53 | trigger <= 1; 54 | else if (init) 55 | trigger <= 0; 56 | else if (random_counter == 0) 57 | trigger <= 1; 58 | 59 | endmodule 60 | 61 | 62 | -------------------------------------------------------------------------------- /MAC/rtl/mac/tx/tb/dut.v: -------------------------------------------------------------------------------- 1 | reg reset; 2 | reg clock; 3 | 4 | wire [7:0] fifo_data; 5 | wire fifo_data_read; 6 | wire fifo_data_start; 7 | wire fifo_data_end; 8 | reg fifo_data_available; 9 | wire fifo_retry; 10 | 11 | reg mode; 12 | 13 | reg carrier_sense; 14 | reg collision; 15 | 16 | wire tx_enable; 17 | wire [7:0] tx_data; 18 | 19 | reg [7:0] tempdata; 20 | reg expected_tx_enable; 21 | 22 | tx_sm U_tx_sm( 23 | .reset(reset), 24 | .clock(clock), 25 | 26 | .fifo_data(fifo_data), 27 | .fifo_data_read(fifo_data_read), 28 | .fifo_data_start(fifo_data_start), 29 | .fifo_data_end(fifo_data_end), 30 | .fifo_data_available(fifo_data_available), 31 | .fifo_retry(fifo_retry), 32 | 33 | .mode(mode), 34 | 35 | .carrier_sense(carrier_sense), 36 | .collision(collision), 37 | 38 | .tx_enable(tx_enable), 39 | .tx_data(tx_data) 40 | ); 41 | 42 | utilities #(.OUT_WIDTH (1), 43 | .IN_WIDTH (1)) 44 | util ( 45 | .data_in(1'b0), 46 | .data_in_enable(), 47 | .data_out(), 48 | .data_out_enable(), 49 | .clock(clock) 50 | ); 51 | 52 | utilities #(.OUT_WIDTH (8), 53 | .IN_WIDTH (8)) 54 | data ( 55 | .data_in(tx_data), 56 | .data_in_enable(), 57 | .data_out(fifo_data), 58 | .data_out_enable(), 59 | .clock(clock) 60 | ); 61 | 62 | utilities #(.OUT_WIDTH (1), 63 | .IN_WIDTH (1)) 64 | data_start ( 65 | .data_in(), 66 | .data_in_enable(), 67 | .data_out(fifo_data_start), 68 | .data_out_enable(), 69 | .clock(clock) 70 | ); 71 | 72 | utilities #(.OUT_WIDTH (1), 73 | .IN_WIDTH (1)) 74 | data_end ( 75 | .data_in(), 76 | .data_in_enable(), 77 | .data_out(fifo_data_end), 78 | .data_out_enable(), 79 | .clock(clock) 80 | ); 81 | 82 | monitor #(.WIDTH(1)) 83 | tx_enable_monitor( 84 | .data(tx_enable), 85 | .expected(expected_tx_enable), 86 | .clock(clock)); 87 | initial 88 | begin 89 | clock = 0; 90 | reset = 1; 91 | mode = 1; 92 | collision = 0; 93 | carrier_sense = 0; 94 | fifo_count = 0; 95 | expected_tx_enable = 0; 96 | end 97 | 98 | always 99 | #5 clock = ~clock; 100 | -------------------------------------------------------------------------------- /MAC/rtl/mac/tx/tb/tx_sm_full_duplex_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module tx_sm_tb (); 4 | 5 | `include "dut.v" 6 | 7 | integer i; 8 | 9 | initial 10 | begin 11 | //$dumpfile("test.vcd"); 12 | //$dumpvars(0,tx_sm_tb,U_tx_sm); 13 | end 14 | 15 | initial 16 | begin 17 | #15 reset = 0; 18 | 19 | // Will initially wait IFG before making any transmissions 20 | // Set fifo_count to 1 and check IFG delay before tx_enable is asserted 21 | // Clock flips every 5ns -> 10ns period 22 | // tx_enable_monitor will take care of these checks 23 | 24 | fifo_count = 1; 25 | 26 | #110 27 | 28 | expected_tx_enable = 1; 29 | 30 | // MAC should then start transmitting the preamble 31 | // 7 bytes 32 | for (i = 0; i < 7; i = i + 1) 33 | begin 34 | data.sync_read(tempdata); 35 | data.assert(tempdata == 8'h55, "Preamble"); 36 | expected_tx_enable = 1; 37 | end 38 | 39 | // Followed by the SFD 40 | // 1 byte 41 | data.sync_read(tempdata); 42 | data.assert(tempdata == 8'hD5, "SFD"); 43 | 44 | // Followed by the frame data we supply 45 | // 10 Bytes 46 | fork 47 | // Data Start 48 | data.sync_write(8'h00); 49 | data_start.sync_write(1); 50 | join 51 | data.assert(tx_data == 0, "DATA START"); 52 | 53 | for (i = 1; i < 9; i = i + 1) 54 | begin 55 | data.sync_write(i); 56 | data.assert(tx_data == i, "DATA"); 57 | end 58 | 59 | fork 60 | // Data End 61 | data.sync_write(8'h09); 62 | data_end.sync_write(1); 63 | join 64 | data.assert(tx_data == 8'h09, "DATA END"); 65 | 66 | // Followed by padding 67 | // 50 bytes 68 | for (i = 0; i < 50; i = i + 1) 69 | begin 70 | data.sync_read(tempdata); 71 | data.assert(tempdata == 0, "PADDING"); 72 | end 73 | 74 | // Followed by CRC 75 | // 4 bytes 76 | data.sync_read(tempdata); 77 | data.assert(tempdata == 8'hAA, "CRC"); 78 | 79 | data.sync_read(tempdata); 80 | data.assert(tempdata == 8'hAA, "CRC"); 81 | 82 | data.sync_read(tempdata); 83 | data.assert(tempdata == 8'h91, "CRC"); 84 | 85 | data.sync_read(tempdata); 86 | data.assert(tempdata == 8'h91, "CRC"); 87 | 88 | expected_tx_enable = 0; 89 | 90 | // Wait IFG and send the same packet again 91 | #120 92 | 93 | // Assert Carrier Sense - Should have no effect in Full Duplex 94 | carrier_sense = 1; 95 | 96 | expected_tx_enable = 1; 97 | 98 | // MAC should start transmitting the preamble 99 | // 7 bytes 100 | for (i = 0; i < 7; i = i + 1) 101 | begin 102 | data.sync_read(tempdata); 103 | data.assert(tempdata == 8'h55, "Preamble"); 104 | expected_tx_enable = 1; 105 | end 106 | 107 | // Followed by the SFD 108 | // 1 byte 109 | data.sync_read(tempdata); 110 | data.assert(tempdata == 8'hD5, "SFD"); 111 | 112 | // Followed by the frame data we supply 113 | // 10 Bytes 114 | fork 115 | // Data Start 116 | data.sync_write(8'h00); 117 | data_start.sync_write(1); 118 | join 119 | data.assert(tx_data == 0, "DATA START"); 120 | 121 | for (i = 1; i < 9; i = i + 1) 122 | begin 123 | data.sync_write(i); 124 | data.assert(tx_data == i, "DATA"); 125 | end 126 | 127 | fork 128 | // Data End 129 | data.sync_write(8'h09); 130 | data_end.sync_write(1); 131 | join 132 | data.assert(tx_data == 8'h09, "DATA END"); 133 | 134 | // Followed by padding 135 | // 50 bytes 136 | for (i = 0; i < 50; i = i + 1) 137 | begin 138 | data.sync_read(tempdata); 139 | data.assert(tempdata == 0, "PADDING"); 140 | end 141 | 142 | // Followed by CRC 143 | // 4 bytes 144 | data.sync_read(tempdata); 145 | data.assert(tempdata == 8'hAA, "CRC"); 146 | 147 | data.sync_read(tempdata); 148 | data.assert(tempdata == 8'hAA, "CRC"); 149 | 150 | data.sync_read(tempdata); 151 | data.assert(tempdata == 8'h91, "CRC"); 152 | 153 | data.sync_read(tempdata); 154 | data.assert(tempdata == 8'h91, "CRC"); 155 | 156 | expected_tx_enable = 0; 157 | 158 | // Wait IFG and send the same packet again 159 | #120 160 | 161 | expected_tx_enable = 1; 162 | 163 | // MAC should start transmitting the preamble 164 | // 7 bytes 165 | for (i = 0; i < 7; i = i + 1) 166 | begin 167 | data.sync_read(tempdata); 168 | data.assert(tempdata == 8'h55, "Preamble"); 169 | expected_tx_enable = 1; 170 | end 171 | 172 | // Followed by the SFD 173 | // 1 byte 174 | data.sync_read(tempdata); 175 | data.assert(tempdata == 8'hD5, "SFD"); 176 | 177 | // Assert a collision - Should have no effect in Full Duplex 178 | collision = 1; 179 | 180 | // Followed by the frame data we supply 181 | // 10 Bytes 182 | fork 183 | // Data Start 184 | data.sync_write(8'h00); 185 | data_start.sync_write(1); 186 | join 187 | data.assert(tx_data == 0, "DATA START"); 188 | 189 | for (i = 1; i < 9; i = i + 1) 190 | begin 191 | data.sync_write(i); 192 | data.assert(tx_data == i, "DATA"); 193 | end 194 | 195 | fork 196 | // Data End 197 | data.sync_write(8'h09); 198 | data_end.sync_write(1); 199 | join 200 | data.assert(tx_data == 8'h09, "DATA END"); 201 | 202 | // Followed by padding 203 | // 50 bytes 204 | for (i = 0; i < 50; i = i + 1) 205 | begin 206 | data.sync_read(tempdata); 207 | data.assert(tempdata == 0, "PADDING"); 208 | end 209 | 210 | // Followed by CRC 211 | // 4 bytes 212 | data.sync_read(tempdata); 213 | data.assert(tempdata == 8'hAA, "CRC"); 214 | 215 | data.sync_read(tempdata); 216 | data.assert(tempdata == 8'hAA, "CRC"); 217 | 218 | data.sync_read(tempdata); 219 | data.assert(tempdata == 8'h91, "CRC"); 220 | 221 | data.sync_read(tempdata); 222 | data.assert(tempdata == 8'h91, "CRC"); 223 | 224 | expected_tx_enable = 0; 225 | 226 | $finish; 227 | end 228 | 229 | endmodule 230 | 231 | -------------------------------------------------------------------------------- /MAC/rtl/mac/tx/tb/tx_sm_half_duplex_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module tx_sm_tb (); 4 | 5 | `include "dut.v" 6 | 7 | integer i; 8 | 9 | initial 10 | begin 11 | //$dumpfile("test.vcd"); 12 | //$dumpvars(0,tx_sm_tb,U_tx_sm); 13 | end 14 | 15 | initial 16 | begin 17 | #15 reset = 0; 18 | mode = 0; 19 | 20 | // Will initially wait IFG before making any transmissions 21 | // Set fifo_count to 1 and check IFG delay before tx_enable is asserted 22 | // Clock flips every 5ns -> 10ns period 23 | // tx_enable_monitor will take care of these checks 24 | 25 | fifo_count = 1; 26 | 27 | #110 28 | 29 | expected_tx_enable = 1; 30 | 31 | // MAC should then start transmitting the preamble 32 | // 7 bytes 33 | for (i = 0; i < 7; i = i + 1) 34 | begin 35 | data.sync_read(tempdata); 36 | data.assert(tempdata == 8'h55, "Preamble"); 37 | expected_tx_enable = 1; 38 | end 39 | 40 | // Followed by the SFD 41 | // 1 byte 42 | data.sync_read(tempdata); 43 | data.assert(tempdata == 8'hD5, "SFD"); 44 | 45 | // Followed by the frame data we supply 46 | // 10 Bytes 47 | fork 48 | // Data Start 49 | data.sync_write(8'h00); 50 | data_start.sync_write(1); 51 | join 52 | data.assert(tx_data == 0, "DATA START"); 53 | 54 | for (i = 1; i < 9; i = i + 1) 55 | begin 56 | data.sync_write(i); 57 | data.assert(tx_data == i, "DATA"); 58 | end 59 | 60 | fork 61 | // Data End 62 | data.sync_write(8'h09); 63 | data_end.sync_write(1); 64 | join 65 | data.assert(tx_data == 8'h09, "DATA END"); 66 | 67 | // Followed by padding 68 | // 50 bytes 69 | for (i = 0; i < 50; i = i + 1) 70 | begin 71 | data.sync_read(tempdata); 72 | data.assert(tempdata == 0, "PADDING"); 73 | end 74 | 75 | // Followed by CRC 76 | // 4 bytes 77 | data.sync_read(tempdata); 78 | data.assert(tempdata == 8'hAA, "CRC"); 79 | 80 | data.sync_read(tempdata); 81 | data.assert(tempdata == 8'hAA, "CRC"); 82 | 83 | data.sync_read(tempdata); 84 | data.assert(tempdata == 8'h91, "CRC"); 85 | 86 | data.sync_read(tempdata); 87 | data.assert(tempdata == 8'h91, "CRC"); 88 | 89 | expected_tx_enable = 0; 90 | 91 | // Wait IFG and send the same packet again 92 | #120 93 | 94 | expected_tx_enable = 1; 95 | 96 | // MAC should start transmitting the preamble 97 | // 7 bytes 98 | for (i = 0; i < 7; i = i + 1) 99 | begin 100 | data.sync_read(tempdata); 101 | data.assert(tempdata == 8'h55, "Preamble"); 102 | expected_tx_enable = 1; 103 | end 104 | 105 | // Followed by the SFD 106 | // 1 byte 107 | data.sync_read(tempdata); 108 | data.assert(tempdata == 8'hD5, "SFD"); 109 | 110 | // Followed by the frame data we supply 111 | // 10 Bytes 112 | fork 113 | // Data Start 114 | data.sync_write(8'h00); 115 | data_start.sync_write(1); 116 | join 117 | data.assert(tx_data == 0, "DATA START"); 118 | 119 | for (i = 1; i < 9; i = i + 1) 120 | begin 121 | data.sync_write(i); 122 | data.assert(tx_data == i, "DATA"); 123 | end 124 | 125 | fork 126 | // Data End 127 | data.sync_write(8'h09); 128 | data_end.sync_write(1); 129 | join 130 | data.assert(tx_data == 8'h09, "DATA END"); 131 | 132 | // Followed by padding 133 | // 50 bytes 134 | for (i = 0; i < 50; i = i + 1) 135 | begin 136 | data.sync_read(tempdata); 137 | data.assert(tempdata == 0, "PADDING"); 138 | end 139 | 140 | // Followed by CRC 141 | // 4 bytes 142 | data.sync_read(tempdata); 143 | data.assert(tempdata == 8'hAA, "CRC"); 144 | 145 | data.sync_read(tempdata); 146 | data.assert(tempdata == 8'hAA, "CRC"); 147 | 148 | data.sync_read(tempdata); 149 | data.assert(tempdata == 8'h91, "CRC"); 150 | 151 | data.sync_read(tempdata); 152 | data.assert(tempdata == 8'h91, "CRC"); 153 | 154 | expected_tx_enable = 0; 155 | 156 | // Wait IFG 157 | #110 158 | 159 | // Assert Carrier Sense - Should defer 160 | carrier_sense = 1; 161 | 162 | // Delay to simulate reception of a packet 163 | #1000 164 | 165 | // Deassert Carrier Sense 166 | carrier_sense = 0; 167 | 168 | // Wait IFG 169 | #110 170 | 171 | expected_tx_enable = 1; 172 | 173 | // MAC should start transmitting the preamble 174 | // 7 bytes 175 | for (i = 0; i < 7; i = i + 1) 176 | begin 177 | data.sync_read(tempdata); 178 | data.assert(tempdata == 8'h55, "Preamble"); 179 | expected_tx_enable = 1; 180 | end 181 | 182 | // Followed by the SFD 183 | // 1 byte 184 | // Insert a collision 185 | collision = 1; 186 | data.sync_read(tempdata); 187 | data.assert(tempdata == 8'hD5, "SFD"); 188 | 189 | // Should transmit a 16 byte jamming signal 190 | for (i = 0; i < 16; i = i + 1) 191 | begin 192 | data.sync_read(tempdata); 193 | data.assert(tempdata == 8'h01, "COLLISION DETECTED- JAMMING"); 194 | end 195 | 196 | // Then stop transmitting 197 | expected_tx_enable = 0; 198 | // And deassert collision detect signal 199 | collision = 0; 200 | 201 | // Should go to a back off state and wait a random amount of time before reattempting transmission 202 | // TODO: Test BACKOFF 203 | 204 | $finish; 205 | end 206 | 207 | endmodule 208 | 209 | -------------------------------------------------------------------------------- /MAC/rtl/mac/tx/tx_sm.v: -------------------------------------------------------------------------------- 1 | module tx_sm #( 2 | parameter STATE_DEFER = 4'h0, 3 | parameter STATE_IFG = 4'h1, 4 | parameter STATE_IDLE = 4'h2, 5 | parameter STATE_PREAMBLE = 4'h3, 6 | parameter STATE_SFD = 4'h4, 7 | parameter STATE_DATA = 4'h5, 8 | parameter STATE_PAD = 4'h6, 9 | parameter STATE_JAM = 4'h7, 10 | parameter STATE_BACKOFF = 4'h8, 11 | parameter STATE_FCS = 4'h9, 12 | parameter STATE_JAM_DROP = 4'hA, 13 | parameter STATE_NEXT = 4'hB 14 | )( 15 | input wire reset, 16 | input wire clock, 17 | 18 | input wire [7:0] fifo_data, 19 | output reg fifo_data_read, 20 | input wire fifo_data_start, 21 | input wire fifo_data_end, 22 | input wire fifo_data_available, 23 | output reg fifo_retry, 24 | 25 | input wire mode, 26 | 27 | input wire carrier_sense, 28 | input wire collision, 29 | 30 | output reg tx_enable, 31 | output reg [7:0] tx_data 32 | ); 33 | 34 | localparam HALF_DUPLEX = 0; 35 | localparam FULL_DUPLEX = 1; 36 | localparam CRC_POLYNOMIAL = 32'h04C11DB7; 37 | localparam CRC_SEED = 32'hFFFFFFFF; 38 | localparam MAX_SIZE = 1518; 39 | localparam MIN_SIZE = 64; 40 | 41 | reg [3:0] state; 42 | reg [3:0] prev_state; 43 | reg [3:0] next_state; 44 | reg [7:0] frame_length_count; 45 | reg [5:0] padding_length_count; 46 | reg [4:0] jam_length_count; 47 | reg [3:0] inter_frame_gap_count; 48 | reg [3:0] preamble_count; 49 | reg [3:0] retry_count; 50 | 51 | reg crc_init; 52 | reg crc_enable; 53 | wire [31:0] crc_out; 54 | wire [31:0] crc_rev; 55 | integer crc_index; 56 | 57 | reg random_init; 58 | wire random_trigger; 59 | 60 | // State update 61 | always @(posedge clock or posedge reset) 62 | if (reset) 63 | state <= STATE_DEFER; 64 | else 65 | begin 66 | prev_state = state; 67 | state = next_state; 68 | end 69 | 70 | // State Machine 71 | always @ (*) 72 | case (state) 73 | STATE_DEFER: 74 | if ((mode == FULL_DUPLEX) || (mode == HALF_DUPLEX && !carrier_sense)) 75 | next_state = STATE_IFG; 76 | else 77 | next_state = STATE_DEFER; 78 | STATE_IFG: 79 | if (mode == HALF_DUPLEX && carrier_sense) 80 | next_state = STATE_DEFER; 81 | else if ((mode == FULL_DUPLEX && inter_frame_gap_count == 12 - 4) || (mode == HALF_DUPLEX && !carrier_sense && inter_frame_gap_count == 12 - 4)) // Drop IFG by four to account for state transitions 82 | next_state = STATE_IDLE; 83 | else 84 | next_state = STATE_IFG; 85 | STATE_IDLE: 86 | if (mode == HALF_DUPLEX && carrier_sense) 87 | next_state = STATE_DEFER; 88 | else if ((mode == FULL_DUPLEX && fifo_data_available) || (mode == HALF_DUPLEX && !carrier_sense && fifo_data_available)) 89 | next_state = STATE_PREAMBLE; 90 | else 91 | next_state = STATE_IDLE; 92 | STATE_PREAMBLE: 93 | if (mode == HALF_DUPLEX && collision) 94 | next_state = STATE_JAM; 95 | else if ((mode == FULL_DUPLEX && preamble_count == 7) || (mode == HALF_DUPLEX && !collision && preamble_count == 7)) 96 | next_state = STATE_SFD; 97 | else 98 | next_state = STATE_PREAMBLE; 99 | STATE_SFD: 100 | if (mode == HALF_DUPLEX && collision) 101 | next_state = STATE_JAM; 102 | else 103 | next_state = STATE_DATA; 104 | STATE_DATA: 105 | if (mode == HALF_DUPLEX && collision) 106 | next_state = STATE_JAM; 107 | else if (fifo_data_end && frame_length_count >= 59 ) 108 | next_state = STATE_FCS; 109 | else if (fifo_data_end) 110 | next_state = STATE_PAD; 111 | else 112 | next_state = STATE_DATA; 113 | STATE_PAD: 114 | if (mode == HALF_DUPLEX && collision) 115 | next_state = STATE_JAM; 116 | else if (frame_length_count >= 59) 117 | next_state = STATE_FCS; 118 | else 119 | next_state = STATE_PAD; 120 | STATE_JAM: 121 | if (retry_count <= 2 && jam_length_count == 16) 122 | next_state = STATE_BACKOFF; 123 | else if (retry_count > 2) 124 | next_state = STATE_JAM_DROP; 125 | else 126 | next_state = STATE_JAM; 127 | STATE_BACKOFF: 128 | if (random_trigger) 129 | next_state = STATE_DEFER; 130 | else 131 | next_state = STATE_BACKOFF; 132 | STATE_FCS: 133 | if (mode == HALF_DUPLEX && collision) 134 | next_state = STATE_JAM; 135 | else if (crc_index > 24) 136 | next_state = STATE_NEXT; 137 | else 138 | next_state = STATE_FCS; 139 | STATE_JAM_DROP: 140 | if (fifo_data_end) 141 | next_state = STATE_NEXT; 142 | else 143 | next_state = STATE_JAM_DROP; 144 | STATE_NEXT: 145 | next_state = STATE_DEFER; 146 | default: 147 | next_state = STATE_DEFER; 148 | endcase 149 | 150 | genvar j; 151 | generate 152 | for (j = 31; j >= 0; j = j - 1) 153 | begin : crc_reverse 154 | assign crc_rev[31-j] = crc_out[j]; 155 | end 156 | endgenerate 157 | 158 | // Counts 159 | 160 | // Frame Length 161 | always @(posedge clock or posedge reset) 162 | if (reset) 163 | frame_length_count <= 0; 164 | else if (state == STATE_DEFER) 165 | frame_length_count <= 0; 166 | else if (state == STATE_DATA || state == STATE_PAD) 167 | frame_length_count <= frame_length_count+1; 168 | 169 | // Padding Length 170 | always @(posedge clock or posedge reset) 171 | if (reset) 172 | padding_length_count <=0; 173 | else if (state != STATE_PAD) 174 | padding_length_count <= 0; 175 | else 176 | padding_length_count <= padding_length_count + 1; 177 | 178 | // Jam Length 179 | always @ (posedge clock or posedge reset) 180 | if (reset) 181 | jam_length_count <= 0; 182 | else if (state == STATE_JAM || next_state == STATE_JAM) 183 | jam_length_count <= jam_length_count + 1; 184 | else 185 | jam_length_count <= 0; 186 | 187 | // Inter-Frame Gap 188 | always @ (posedge clock or posedge reset) 189 | if (reset) 190 | inter_frame_gap_count <= 0; 191 | else if (state != STATE_IFG) 192 | inter_frame_gap_count <= 0; 193 | else 194 | inter_frame_gap_count <= inter_frame_gap_count + 1; 195 | 196 | // Preamble 197 | always @ (posedge clock or posedge reset) 198 | if (reset) 199 | preamble_count <= 0; 200 | else if (state != STATE_PREAMBLE) 201 | preamble_count <= 0; 202 | else 203 | preamble_count <= preamble_count + 1; 204 | 205 | // Retry Counter 206 | always @ (posedge clock or posedge reset) 207 | if (reset) 208 | retry_count <= 0; 209 | else if (state == STATE_NEXT) 210 | retry_count <= 0; 211 | else if (state == STATE_JAM && next_state == STATE_BACKOFF) 212 | retry_count <= retry_count + 1; 213 | 214 | // State Output Actions 215 | 216 | // FIFO 217 | always @ (*) 218 | if ((state == STATE_DATA || 219 | state == STATE_SFD || 220 | state == STATE_JAM_DROP ) && 221 | next_state != STATE_FCS) 222 | fifo_data_read = 1; 223 | else 224 | fifo_data_read = 0; 225 | 226 | always @ (state) 227 | if (state == STATE_JAM) 228 | fifo_retry = 1; 229 | else 230 | fifo_retry = 0; 231 | 232 | // Transmit Enable 233 | always @(prev_state) 234 | if (prev_state == STATE_PREAMBLE || 235 | prev_state == STATE_SFD || 236 | prev_state == STATE_DATA || 237 | prev_state == STATE_FCS || 238 | prev_state == STATE_PAD || 239 | prev_state == STATE_JAM ) 240 | tx_enable <= 1; 241 | else 242 | tx_enable <= 0; 243 | 244 | reg [7:0] tx_data_tmp; 245 | 246 | // Transmit Data 247 | always @(posedge clock) 248 | case (state) 249 | STATE_PREAMBLE: 250 | tx_data_tmp <= 8'h55; 251 | STATE_SFD: 252 | tx_data_tmp <= 8'hD5; 253 | STATE_DATA: 254 | tx_data_tmp <= fifo_data; 255 | STATE_PAD: 256 | tx_data_tmp <= 8'h00; 257 | STATE_JAM: 258 | tx_data_tmp <= 8'h01; 259 | STATE_FCS: 260 | $display("CRC: %x", ~crc_rev); 261 | //tx_data <= ~crc_rev[crc_index+:8]; 262 | default: 263 | tx_data_tmp <= 8'b00; 264 | endcase 265 | 266 | always @(posedge clock) 267 | if (prev_state == STATE_FCS) 268 | tx_data <= ~crc_rev[crc_index+:8]; 269 | else 270 | tx_data <= tx_data_tmp; 271 | 272 | always @(posedge clock) 273 | if(prev_state == STATE_FCS) 274 | crc_index <= crc_index + 8; 275 | else 276 | crc_index <= 0; 277 | 278 | // CRC 279 | always @(state) 280 | if (state == STATE_SFD) 281 | crc_init = 1; 282 | else 283 | crc_init = 0; 284 | 285 | reg crc_enable_tmp; 286 | 287 | always @(state) 288 | if (state == STATE_DATA || state == STATE_PAD) 289 | crc_enable_tmp = 1; 290 | else 291 | crc_enable_tmp = 0; 292 | 293 | always @ (posedge clock) 294 | crc_enable <= crc_enable_tmp; 295 | 296 | // Random Calculation for Backoff 297 | always @(state or next_state) 298 | if (state == STATE_JAM && next_state == STATE_BACKOFF) 299 | random_init = 1; 300 | else 301 | random_init = 0; 302 | 303 | // Submodule Initialisation 304 | 305 | // CRC 306 | crc #( .POLYNOMIAL(CRC_POLYNOMIAL), 307 | .DATA_WIDTH(8), 308 | .CRC_WIDTH(32), 309 | .SEED(CRC_SEED)) 310 | U_crc( 311 | .reset(reset), 312 | .clock(clock), 313 | .init(crc_init), 314 | .data(tx_data_tmp), 315 | .data_enable(crc_enable), 316 | .crc_out(crc_out) 317 | ); 318 | 319 | random_gen U_random_gen( 320 | .reset(reset), 321 | .clock(clock), 322 | .init(random_init), 323 | .retry_count(retry_count), 324 | .trigger(random_trigger) 325 | ); 326 | 327 | endmodule 328 | -------------------------------------------------------------------------------- /MAC/rtl/mac/utilities/monitor.v: -------------------------------------------------------------------------------- 1 | module monitor #( 2 | parameter WIDTH = 8 3 | )( 4 | input wire [WIDTH-1:0] data, 5 | input wire expected, 6 | input wire clock 7 | ); 8 | 9 | always @(posedge clock) 10 | begin 11 | if (data != expected) 12 | begin 13 | $display("MONITOR FAILED"); 14 | end 15 | end 16 | 17 | endmodule 18 | -------------------------------------------------------------------------------- /MAC/rtl/mac/utilities/utilities.v: -------------------------------------------------------------------------------- 1 | module utilities #( 2 | parameter IN_WIDTH = 8, 3 | parameter OUT_WIDTH = 8, 4 | parameter DEBUG = 0 5 | )( 6 | output reg [OUT_WIDTH-1:0] data_out, 7 | output reg data_out_enable, 8 | input wire [IN_WIDTH-1:0] data_in, 9 | output reg data_in_enable, 10 | input wire clock 11 | ); 12 | 13 | integer passes; 14 | integer fails; 15 | initial 16 | begin 17 | data_out = 0; 18 | data_out_enable = 0; 19 | data_in_enable = 0; 20 | passes = 0; 21 | fails = 0; 22 | end 23 | task display; 24 | begin 25 | $display("PASSES:%d FAILS:%d", passes, fails); 26 | end 27 | endtask 28 | 29 | task sync_assert; 30 | input condition; 31 | input [100*8:0] message; 32 | begin 33 | @(posedge clock) 34 | if (condition) 35 | begin 36 | $display("ASSERTION PASSED | %0s", message); 37 | passes = passes + 1; 38 | end 39 | else 40 | begin 41 | $display("ASSERTION FAILED | %0s", message); 42 | fails = fails + 1; 43 | end 44 | end 45 | endtask 46 | 47 | task assert; 48 | input condition; 49 | input [100*8:0] message; 50 | begin 51 | if (condition) 52 | begin 53 | $display("ASSERTION PASSED | %0s", message); 54 | passes = passes + 1; 55 | end 56 | else 57 | begin 58 | $display("ASSERTION FAILED | %0s", message); 59 | fails = fails + 1; 60 | end 61 | end 62 | endtask 63 | 64 | task sync_write; 65 | input [OUT_WIDTH-1:0] data; 66 | begin 67 | data_out = data; 68 | data_out_enable = 1; 69 | @(posedge clock); 70 | #1 data_out_enable = 0; 71 | data_out = 0; 72 | if (DEBUG) 73 | $display("Wrote: 0x%0x | 0b%0b | %0d",data, data, data); 74 | end 75 | endtask 76 | 77 | task sync_read; 78 | output [IN_WIDTH-1:0] data; 79 | begin 80 | data_in_enable = 1; 81 | @(posedge clock); 82 | #1 data = data_in; 83 | data_in_enable = 0; 84 | if (DEBUG) 85 | $display("Read: 0x%0x | 0b%0b | %0d", data, data, data); 86 | end 87 | endtask 88 | 89 | endmodule 90 | 91 | 92 | -------------------------------------------------------------------------------- /MAC/rtl/tx_sm.v: -------------------------------------------------------------------------------- 1 | module tx_sm #( 2 | parameter STATE_DEFER = 4'h0, 3 | parameter STATE_IFG = 4'h1, 4 | parameter STATE_IDLE = 4'h2, 5 | parameter STATE_PREAMBLE = 4'h3, 6 | parameter STATE_SFD = 4'h4, 7 | parameter STATE_DATA = 4'h5, 8 | parameter STATE_PAD = 4'h6, 9 | parameter STATE_JAM = 4'h7, 10 | parameter STATE_BACKOFF = 4'h8, 11 | parameter STATE_FCS = 4'h9, 12 | parameter STATE_JAM_DROP = 4'hA, 13 | parameter STATE_NEXT = 4'hB 14 | )( 15 | input wire reset, 16 | input wire clock, 17 | 18 | input wire [7:0] fifo_data, 19 | output reg fifo_data_read, 20 | input wire fifo_data_start, 21 | input wire fifo_data_end, 22 | input wire [6:0] fifo_count, 23 | output reg fifo_retry, 24 | 25 | input wire mode, 26 | 27 | input wire carrier_sense, 28 | input wire collision, 29 | 30 | output reg tx_enable, 31 | output reg [7:0] tx_data 32 | ); 33 | 34 | localparam HALF_DUPLEX = 0; 35 | localparam FULL_DUPLEX = 1; 36 | 37 | reg [3:0] state; 38 | reg [3:0] next_state; 39 | reg [7:0] frame_length_count; 40 | reg [5:0] padding_length_count; 41 | reg [4:0] jam_length_count; 42 | reg [3:0] inter_frame_gap_count; 43 | reg [3:0] preamble_count; 44 | reg [3:0] retry_count; 45 | 46 | reg crc_init; 47 | reg crc_enable; 48 | reg crc_read; 49 | wire [7:0] crc_out; 50 | wire crc_end; 51 | wire crc_error; 52 | 53 | reg random_init; 54 | wire random_trigger; 55 | 56 | // State update 57 | always @(posedge clock or posedge reset) 58 | if (reset) 59 | state <= STATE_DEFER; 60 | else 61 | state <= next_state; 62 | 63 | // State Machine 64 | always @ (*) 65 | case (state) 66 | STATE_DEFER: 67 | if ((mode == FULL_DUPLEX) || (mode == HALF_DUPLEX && !carrier_sense)) 68 | next_state = STATE_IFG; 69 | STATE_IFG: 70 | if (mode == HALF_DUPLEX && carrier_sense) 71 | next_state = STATE_DEFER; 72 | else if ((mode == FULL_DUPLEX && inter_frame_gap_count == 12-4) || (mode == HALF_DUPLEX && !carrier_sense && inter_frame_gap_count==12-4)) 73 | next_state = STATE_IDLE; 74 | STATE_IDLE: 75 | if (mode == HALF_DUPLEX && carrier_sense) 76 | next_state = STATE_DEFER; 77 | else if ((mode == FULL_DUPLEX && fifo_count) || (mode == HALF_DUPLEX && !carrier_sense && fifo_count)) 78 | next_state = STATE_PREAMBLE; 79 | STATE_PREAMBLE: 80 | if (mode == HALF_DUPLEX && collision) 81 | next_state = STATE_JAM; 82 | else if ((mode == FULL_DUPLEX && preamble_count == 6) || (mode == HALF_DUPLEX && !collision && preamble_count == 6)) 83 | next_state = STATE_SFD; 84 | STATE_SFD: 85 | if (mode == HALF_DUPLEX && collision) 86 | next_state = STATE_JAM; 87 | else 88 | next_state = STATE_DATA; 89 | STATE_DATA: 90 | if (mode == HALF_DUPLEX && collision) 91 | next_state = STATE_JAM; 92 | else if (fifo_data_end && frame_length_count >= 59 ) 93 | next_state = STATE_FCS; 94 | else if (fifo_data_end) 95 | next_state = STATE_PAD; 96 | STATE_PAD: 97 | if (mode == HALF_DUPLEX && collision) 98 | next_state = STATE_JAM; 99 | else if (frame_length_count >= 59) 100 | next_state = STATE_FCS; 101 | STATE_JAM: 102 | if (retry_count <= 2 && jam_length_count == 16) 103 | next_state = STATE_BACKOFF; 104 | else if (retry_count > 2) 105 | next_state = STATE_JAM_DROP; 106 | STATE_BACKOFF: 107 | if (random_trigger) 108 | next_state = STATE_DEFER; 109 | STATE_FCS: 110 | if (mode == HALF_DUPLEX && collision) 111 | next_state = STATE_JAM; 112 | else if (crc_end) 113 | next_state = STATE_NEXT; 114 | STATE_JAM_DROP: 115 | if (fifo_data_end) 116 | next_state = STATE_NEXT; 117 | STATE_NEXT: 118 | next_state = STATE_DEFER; 119 | default: 120 | next_state = STATE_DEFER; 121 | endcase 122 | 123 | // Counts 124 | 125 | // Frame Length 126 | always @(posedge clock or posedge reset) 127 | if (reset) 128 | frame_length_count <= 0; 129 | else if (state == STATE_DEFER) 130 | frame_length_count <= 0; 131 | else if (state == STATE_DATA || state == STATE_PAD) 132 | frame_length_count <= frame_length_count+1; 133 | 134 | // Padding Length 135 | always @(posedge clock or posedge reset) 136 | if (reset) 137 | padding_length_count <=0; 138 | else if (state != STATE_PAD) 139 | padding_length_count <= 0; 140 | else 141 | padding_length_count <= padding_length_count + 1; 142 | 143 | // Jam Length 144 | always @ (posedge clock or posedge reset) 145 | if (reset) 146 | jam_length_count <= 0; 147 | else if (state != STATE_JAM) 148 | jam_length_count <= 0; 149 | else 150 | jam_length_count <= jam_length_count + 1; 151 | 152 | // Inter-Frame Gap 153 | always @ (posedge clock or posedge reset) 154 | if (reset) 155 | inter_frame_gap_count <= 0; 156 | else if (state != STATE_IFG) 157 | inter_frame_gap_count <= 0; 158 | else 159 | inter_frame_gap_count <= inter_frame_gap_count + 1; 160 | 161 | // Preamble 162 | always @ (posedge clock or posedge reset) 163 | if (reset) 164 | preamble_count <= 0; 165 | else if (state != STATE_PREAMBLE) 166 | preamble_count <= 0; 167 | else 168 | preamble_count <= preamble_count + 1; 169 | 170 | // Retry Counter 171 | always @ (posedge clock or posedge reset) 172 | if (reset) 173 | retry_count <= 0; 174 | else if (state == STATE_NEXT) 175 | retry_count <= 0; 176 | else if (state == STATE_JAM && next_state == STATE_BACKOFF) 177 | retry_count <= retry_count + 1; 178 | 179 | // State Output Actions 180 | 181 | // FIFO 182 | always @ (*) 183 | if (state == STATE_DATA || 184 | state == STATE_SFD || 185 | state == STATE_JAM_DROP) 186 | fifo_data_read = 1; 187 | else 188 | fifo_data_read = 0; 189 | 190 | always @ (state) 191 | if (state == STATE_JAM) 192 | fifo_retry = 1; 193 | else 194 | fifo_retry = 0; 195 | 196 | // Transmit Enable 197 | always @(state) 198 | if (state == STATE_PREAMBLE || 199 | state == STATE_SFD || 200 | state == STATE_DATA || 201 | state == STATE_FCS || 202 | state == STATE_PAD || 203 | state == STATE_JAM ) 204 | tx_enable <= 1; 205 | else 206 | tx_enable <= 0; 207 | 208 | // Transmit Data 209 | always @(*) 210 | case (state) 211 | STATE_PREAMBLE: 212 | tx_data = 8'h55; 213 | STATE_SFD: 214 | tx_data = 8'hD5; 215 | STATE_DATA: 216 | tx_data = fifo_data; 217 | STATE_PAD: 218 | tx_data = 8'h00; 219 | STATE_JAM: 220 | tx_data = 8'h01; 221 | STATE_FCS: 222 | tx_data = crc_out; 223 | default: 224 | tx_data = 8'b00; 225 | endcase 226 | 227 | // CRC 228 | always @(state) 229 | if (state == STATE_SFD) 230 | crc_init = 1; 231 | else 232 | crc_init = 0; 233 | 234 | always @(state) 235 | if (state == STATE_DATA || state == STATE_PAD) 236 | crc_enable = 1; 237 | else 238 | crc_enable = 0; 239 | 240 | always @(state) 241 | if (state == STATE_FCS) 242 | crc_read = 1; 243 | else 244 | crc_read = 0; 245 | 246 | // Random Calculation for Backoff 247 | always @(state or next_state) 248 | if (state == STATE_JAM && next_state == STATE_BACKOFF) 249 | random_init = 1; 250 | else 251 | random_init = 0; 252 | 253 | // Submodule Initialisation 254 | 255 | // CRC 256 | crc U_crc( 257 | .reset(reset), 258 | .clock(clock), 259 | .init(crc_init), 260 | .data(tx_data), 261 | .data_enable(crc_enable), 262 | .read(crc_read), 263 | .crc_out(crc_out), 264 | .crc_end(crc_end), 265 | .error(crc_error) 266 | ); 267 | 268 | random_gen U_random_gen( 269 | .reset(reset), 270 | .clock(clock), 271 | .init(random_init), 272 | .retry_count(retry_count), 273 | .trigger(random_trigger) 274 | ); 275 | 276 | endmodule 277 | -------------------------------------------------------------------------------- /MAC/tb/mac/mac_fifo/fifo/fifo_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module fifo_test(); 4 | 5 | parameter IN_WIDTH = 32; 6 | parameter OUT_WIDTH = 4; 7 | 8 | reg reset; 9 | 10 | reg [IN_WIDTH-1:0] data_in; 11 | reg data_in_clock; 12 | reg data_in_enable; 13 | 14 | wire [OUT_WIDTH-1:0] data_out; 15 | reg data_out_clock; 16 | reg data_out_enable; 17 | 18 | reg [OUT_WIDTH-1:0] tempdata; 19 | 20 | integer i; 21 | 22 | fifo #( 23 | .DATA_IN_WIDTH (IN_WIDTH), 24 | .DATA_OUT_WIDTH (OUT_WIDTH), 25 | .FIFO_DEPTH (12) 26 | ) 27 | ff ( 28 | .reset(reset), 29 | 30 | // IN PORT 31 | .data_in(data_in), 32 | .data_in_clock(data_in_clock), 33 | .data_in_enable(data_in_enable), 34 | 35 | // OUT PORT 36 | .data_out(data_out), 37 | .data_out_clock(data_out_clock), 38 | .data_out_enable(data_out_enable) 39 | ); 40 | 41 | initial 42 | begin 43 | reset = 1; 44 | data_in = 0; 45 | data_in_clock = 0; 46 | data_in_enable = 0; 47 | data_out_clock = 0; 48 | data_out_enable = 0; 49 | tempdata = 0; 50 | 51 | #15 reset = 0; 52 | 53 | if (OUT_WIDTH > IN_WIDTH) 54 | begin 55 | for ( i = 0; i < (OUT_WIDTH/IN_WIDTH); i = i + 1) 56 | begin 57 | push(i); 58 | end 59 | 60 | pop(tempdata); 61 | end 62 | else 63 | begin 64 | push(1); 65 | 66 | for ( i = 0; i < (IN_WIDTH/OUT_WIDTH); i = i + 1) 67 | begin 68 | pop(tempdata); 69 | end 70 | end 71 | 72 | $finish; 73 | end 74 | 75 | always 76 | #5 data_in_clock = ~data_in_clock; 77 | 78 | always 79 | #40 data_out_clock = ~data_out_clock; 80 | 81 | task push; 82 | input[IN_WIDTH-1:0] data; 83 | begin 84 | data_in = data; 85 | data_in_enable = 1; 86 | @(posedge data_in_clock); 87 | #1 data_in_enable = 0; 88 | $display("Pushed %x",data ); 89 | end 90 | endtask 91 | 92 | task pop; 93 | output [OUT_WIDTH-1:0] data; 94 | begin 95 | data_out_enable = 1; 96 | @(posedge data_out_clock); 97 | #1 data_out_enable = 0; 98 | data = data_out; 99 | $display("Popped %x", data); 100 | end 101 | endtask 102 | 103 | endmodule 104 | 105 | -------------------------------------------------------------------------------- /MAC/tb/mac/mac_fifo/mac_fifo_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module mac_fifo_test(); 4 | 5 | parameter IN_WIDTH = 32; 6 | parameter OUT_WIDTH = 8; 7 | 8 | reg reset; 9 | 10 | reg [IN_WIDTH-1:0] data_in; 11 | reg data_in_clock; 12 | reg data_in_enable; 13 | reg data_in_start; 14 | reg data_in_end; 15 | 16 | wire [OUT_WIDTH-1:0] data_out; 17 | reg data_out_clock; 18 | reg data_out_enable; 19 | 20 | wire data_out_start; 21 | wire data_out_end; 22 | reg retry; 23 | 24 | reg [OUT_WIDTH-1:0] tempdata; 25 | 26 | integer i; 27 | 28 | mac_fifo #( 29 | .DATA_IN_WIDTH (IN_WIDTH), 30 | .DATA_OUT_WIDTH (OUT_WIDTH), 31 | .FIFO_DEPTH (12) 32 | ) 33 | ff ( 34 | .reset(reset), 35 | 36 | // IN PORT 37 | .data_in(data_in), 38 | .data_in_clock(data_in_clock), 39 | .data_in_enable(data_in_enable), 40 | .data_in_start(data_in_start), 41 | .data_in_end(data_in_end), 42 | 43 | // OUT PORT 44 | .data_out(data_out), 45 | .data_out_clock(data_out_clock), 46 | .data_out_enable(data_out_enable), 47 | .data_out_start(data_out_start), 48 | .data_out_end(data_out_end), 49 | .retry(retry) 50 | ); 51 | 52 | initial 53 | begin 54 | reset = 1; 55 | data_in = 0; 56 | data_in_clock = 0; 57 | data_in_enable = 0; 58 | data_out_clock = 0; 59 | data_out_enable = 0; 60 | data_in_start = 0; 61 | data_in_end = 0; 62 | retry = 0; 63 | tempdata = 0; 64 | 65 | #15 reset = 0; 66 | /* 67 | if (OUT_WIDTH > IN_WIDTH) 68 | begin 69 | for ( i = 0; i < (OUT_WIDTH/IN_WIDTH); i = i + 1) 70 | begin 71 | push(i,0,1); 72 | end 73 | 74 | pop(tempdata,0); 75 | end 76 | else 77 | begin 78 | push(1,1,1); 79 | 80 | for ( i = 0; i < (IN_WIDTH/OUT_WIDTH); i = i + 1) 81 | begin 82 | pop(tempdata,0); 83 | end 84 | end 85 | */ 86 | 87 | push(1,1,0); 88 | push(2,0,0); 89 | push(3,0,1); 90 | 91 | pop(tempdata, 0); 92 | pop(tempdata, 0); 93 | pop(tempdata, 0); 94 | pop(tempdata, 0); 95 | pop(tempdata, 0); 96 | pop(tempdata, 0); 97 | pop(tempdata, 0); 98 | pop(tempdata, 0); 99 | 100 | pop(tempdata, 1); 101 | pop(tempdata, 0); 102 | pop(tempdata, 0); 103 | pop(tempdata, 0); 104 | pop(tempdata, 0); 105 | pop(tempdata, 0); 106 | pop(tempdata, 0); 107 | pop(tempdata, 0); 108 | pop(tempdata, 0); 109 | pop(tempdata, 0); 110 | pop(tempdata, 0); 111 | pop(tempdata, 0); 112 | pop(tempdata, 0); 113 | $finish; 114 | end 115 | 116 | always 117 | #5 data_in_clock = ~data_in_clock; 118 | 119 | always 120 | #40 data_out_clock = ~data_out_clock; 121 | 122 | task push; 123 | input[IN_WIDTH-1:0] data; 124 | input data_start; 125 | input data_end; 126 | begin 127 | data_in = data; 128 | data_in_enable = 1; 129 | data_in_start = data_start; 130 | data_in_end = data_end; 131 | @(posedge data_in_clock); 132 | #1 data_in_enable = 0; 133 | data_in_start = 0; 134 | data_in_end = 0; 135 | $display("Pushed: %x Start: %b End: %b",data, data_start, data_end ); 136 | end 137 | endtask 138 | 139 | task pop; 140 | output [OUT_WIDTH-1:0] data; 141 | input frame_retry; 142 | begin 143 | data_out_enable = 1; 144 | retry = frame_retry; 145 | @(posedge data_out_clock); 146 | #1 data_out_enable = 0; 147 | retry = 0; 148 | data = data_out; 149 | $display("Popped %x Start: %b End: %b Retry:%b", data, data_out_start, data_out_end, frame_retry); 150 | end 151 | endtask 152 | 153 | endmodule 154 | 155 | -------------------------------------------------------------------------------- /MAC/tb/mac/mac_fifo/mac_fifo_tb2.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module mac_fifo_test(); 4 | 5 | parameter IN_WIDTH = 8; 6 | parameter OUT_WIDTH = 32; 7 | 8 | reg reset; 9 | 10 | reg [IN_WIDTH-1:0] data_in; 11 | reg data_in_clock; 12 | reg data_in_enable; 13 | reg data_in_start; 14 | reg data_in_end; 15 | 16 | wire [OUT_WIDTH-1:0] data_out; 17 | reg data_out_clock; 18 | reg data_out_enable; 19 | 20 | wire data_out_start; 21 | wire data_out_end; 22 | 23 | reg error; 24 | reg retry; 25 | reg [OUT_WIDTH-1:0] tempdata; 26 | 27 | integer i; 28 | 29 | mac_fifo #( 30 | .DATA_IN_WIDTH (IN_WIDTH), 31 | .DATA_OUT_WIDTH (OUT_WIDTH), 32 | .FIFO_DEPTH (12) 33 | ) 34 | ff ( 35 | .reset(reset), 36 | 37 | // IN PORT 38 | .data_in(data_in), 39 | .data_in_clock(data_in_clock), 40 | .data_in_enable(data_in_enable), 41 | .data_in_start(data_in_start), 42 | .data_in_end(data_in_end), 43 | 44 | // OUT PORT 45 | .data_out(data_out), 46 | .data_out_clock(data_out_clock), 47 | .data_out_enable(data_out_enable), 48 | .data_out_start(data_out_start), 49 | .data_out_end(data_out_end), 50 | 51 | .retry(retry), 52 | .error(error) 53 | ); 54 | 55 | initial 56 | begin 57 | reset = 1; 58 | data_in = 0; 59 | data_in_clock = 0; 60 | data_in_enable = 0; 61 | data_out_clock = 0; 62 | data_out_enable = 0; 63 | data_in_start = 0; 64 | data_in_end = 0; 65 | error = 0; 66 | retry = 0; 67 | tempdata = 0; 68 | 69 | #15 reset = 0; 70 | 71 | push(8'h01,1,0,0); 72 | push(8'h02,0,0,0); 73 | push(8'h03,0,0,0); 74 | push(8'h04,0,0,0); 75 | push(8'h05,0,0,0); 76 | push(8'h06,0,0,0); 77 | push(8'h07,0,0,0); 78 | push(8'h08,0,0,0); 79 | push(8'h09,0,0,0); 80 | push(8'h0A,0,0,0); 81 | push(8'h0B,0,0,0); 82 | push(8'h0C,0,0,0); 83 | push(8'h0D,0,0,0); 84 | push(8'h0E,0,0,0); 85 | push(8'h0F,0,0,0); 86 | push(8'h10,0,0,0); 87 | push(8'h11,0,0,0); 88 | push(8'h12,0,0,0); 89 | push(8'h13,0,0,0); 90 | push(8'h14,0,1,0); 91 | 92 | push(8'h11,1,0,0); 93 | push(8'h22,0,0,0); 94 | push(8'h33,0,0,0); 95 | push(8'h44,0,0,1); 96 | 97 | push(8'h55,1,0,0); 98 | push(8'h66,0,0,0); 99 | push(8'h77,0,0,0); 100 | push(8'h88,0,0,0); 101 | push(8'h99,0,0,0); 102 | push(8'hAA,0,0,0); 103 | push(8'hBB,0,0,0); 104 | push(8'hCC,0,0,0); 105 | push(8'hDD,0,0,0); 106 | push(8'hEE,0,0,0); 107 | push(8'hFF,0,1,0); 108 | 109 | pop(tempdata); 110 | pop(tempdata); 111 | pop(tempdata); 112 | pop(tempdata); 113 | pop(tempdata); 114 | pop(tempdata); 115 | pop(tempdata); 116 | pop(tempdata); 117 | pop(tempdata); 118 | 119 | $finish; 120 | end 121 | 122 | always 123 | #5 data_in_clock = ~data_in_clock; 124 | 125 | always 126 | #40 data_out_clock = ~data_out_clock; 127 | 128 | task push; 129 | input[IN_WIDTH-1:0] data; 130 | input data_start; 131 | input data_end; 132 | input frame_error; 133 | begin 134 | data_in = data; 135 | data_in_enable = 1; 136 | data_in_start = data_start; 137 | data_in_end = data_end; 138 | error = frame_error; 139 | @(posedge data_in_clock); 140 | #1 data_in_enable = 0; 141 | data_in_start = 0; 142 | data_in_end = 0; 143 | error = 0; 144 | $display("Pushed: %x Start: %b End: %b",data, data_start, data_end ); 145 | end 146 | endtask 147 | 148 | task pop; 149 | output [OUT_WIDTH-1:0] data; 150 | begin 151 | data_out_enable = 1; 152 | @(posedge data_out_clock); 153 | #1 data_out_enable = 0; 154 | data = data_out; 155 | $display("Popped %x Start: %b End: %b", data, data_out_start, data_out_end); 156 | end 157 | endtask 158 | 159 | endmodule 160 | 161 | -------------------------------------------------------------------------------- /MAC/tb/mac/mac_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module mac_test(); 4 | 5 | reg reset; 6 | 7 | reg [31:0] data_in; 8 | reg data_in_clock; 9 | reg data_in_enable; 10 | reg data_in_start; 11 | reg data_in_end; 12 | 13 | reg tx_clock; 14 | reg carrier_sense; 15 | reg collision; 16 | wire tx_enable; 17 | wire [7:0] tx_data; 18 | 19 | reg [31:0] packet [0:380]; 20 | integer i; 21 | mac U_mac ( 22 | .reset(reset), 23 | 24 | // IN PORT 25 | .data_in(data_in), 26 | .data_in_clock(data_in_clock), 27 | .data_in_enable(data_in_enable), 28 | .data_in_start(data_in_start), 29 | .data_in_end(data_in_end), 30 | 31 | .tx_clock(tx_clock), 32 | 33 | .carrier_sense(carrier_sense), 34 | .collision(collision), 35 | 36 | .tx_enable(tx_enable), 37 | .tx_data(tx_data) 38 | ); 39 | 40 | initial 41 | begin 42 | $dumpfile("test.vcd"); 43 | $dumpvars(0,mac_test,U_mac,U_mac.U_tx_sm,U_mac.U_tx_sm.U_crc); 44 | end 45 | 46 | initial 47 | begin 48 | $monitor("TX ENABLE: %b, TX DATA: %x", tx_enable, tx_data); 49 | reset = 1; 50 | data_in = 0; 51 | data_in_clock = 0; 52 | data_in_enable = 0; 53 | tx_clock = 0; 54 | data_in_start = 0; 55 | 56 | $readmemh("tx.hex", packet); 57 | 58 | #15 reset = 0; 59 | 60 | 61 | // Send a packet 62 | 63 | push(packet[0], 1, 0); 64 | for(i = 1; i < 14; i = i + 1) 65 | begin 66 | push(packet[i], 0, 0); 67 | end 68 | push(packet[14], 0, 1); 69 | 70 | #120 $finish; 71 | end 72 | 73 | always 74 | #20 data_in_clock = ~data_in_clock; 75 | 76 | always 77 | #1 tx_clock = ~tx_clock; 78 | 79 | task push; 80 | input[31:0] data; 81 | input data_start; 82 | input data_end; 83 | begin 84 | data_in = data; 85 | data_in_enable = 1; 86 | data_in_start = data_start; 87 | data_in_end = data_end; 88 | @(posedge data_in_clock); 89 | #1 data_in_enable = 0; 90 | data_in_start = 0; 91 | data_in_end = 0; 92 | $display("Pushed: %x Start: %b End: %b",data, data_start, data_end ); 93 | end 94 | endtask 95 | 96 | endmodule 97 | 98 | -------------------------------------------------------------------------------- /MAC/tb/mac/mac_tb2.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module mac_test(); 4 | 5 | reg reset; 6 | 7 | wire [31:0] data_out; 8 | reg data_out_clock; 9 | reg data_out_enable; 10 | wire data_out_start; 11 | wire data_out_end; 12 | wire [6:0] frame_count; 13 | 14 | reg rx_clock; 15 | reg rx_data_valid; 16 | reg rx_error; 17 | reg [7:0] rx_data; 18 | reg [7:0] packet [0:1518]; 19 | reg [31:0] tempdata; 20 | 21 | integer i; 22 | wire [31:0] crc; 23 | 24 | mac U_mac ( 25 | .reset(reset), 26 | 27 | // OUT PORT 28 | .data_out(data_out), 29 | .data_out_clock(data_out_clock), 30 | .data_out_enable(data_out_enable), 31 | .data_out_start(data_out_start), 32 | .data_out_end(data_out_end), 33 | .frame_count(frame_count), 34 | 35 | .rx_clock(rx_clock), 36 | 37 | .rx_data_valid(rx_data_valid), 38 | .rx_error(rx_error), 39 | 40 | .rx_data(rx_data) 41 | ); 42 | 43 | initial 44 | begin 45 | $dumpfile("test.vcd"); 46 | $dumpvars(0, mac_test, U_mac, U_mac.U_rx_sm, U_mac.U_rx_sm.U_crc); 47 | end 48 | 49 | initial 50 | begin 51 | reset = 1; 52 | data_out_clock = 0; 53 | data_out_enable = 0; 54 | rx_clock = 0; 55 | rx_data = 0; 56 | $readmemh("rx.hex", packet); 57 | 58 | 59 | $monitor("STATE :%0d FRAME_LENGTH: %0d CRC: %0x", U_mac.U_rx_sm.state, U_mac.U_rx_sm.frame_length_counter, U_mac.U_rx_sm.crc_out); 60 | 61 | #15 reset = 0; 62 | 63 | // Send a packet 64 | for(i = 0; i < 72; i = i + 1) 65 | begin 66 | push(packet[i], 1, 0); 67 | end 68 | 69 | for(i = 72; i < 80; i = i + 1) 70 | begin 71 | push(packet[i], 0, 0); 72 | end 73 | 74 | pop(tempdata); 75 | pop(tempdata); 76 | pop(tempdata); 77 | pop(tempdata); 78 | pop(tempdata); 79 | pop(tempdata); 80 | pop(tempdata); 81 | pop(tempdata); 82 | pop(tempdata); 83 | pop(tempdata); 84 | pop(tempdata); 85 | pop(tempdata); 86 | pop(tempdata); 87 | pop(tempdata); 88 | pop(tempdata); 89 | pop(tempdata); 90 | 91 | $finish; 92 | end 93 | 94 | always 95 | #20 data_out_clock = ~data_out_clock; 96 | 97 | always 98 | #1 rx_clock = ~rx_clock; 99 | 100 | task push; 101 | input [7:0] data; 102 | input data_valid; 103 | input data_error; 104 | begin 105 | rx_data = data; 106 | rx_data_valid = data_valid; 107 | rx_error = data_error; 108 | @(posedge rx_clock); 109 | #1 rx_data_valid = 0; 110 | rx_error = 0; 111 | $display("Pushed: %x Valid: %b Error: %b",data, data_valid, data_error ); 112 | end 113 | endtask 114 | 115 | task pop; 116 | output [31:0] data; 117 | begin 118 | data_out_enable = 1; 119 | @(posedge data_out_clock); 120 | #1 data_out_enable = 0; 121 | data = data_out; 122 | $display("Popped %x Start: %b End: %b ", data, data_out_start, data_out_end); 123 | end 124 | endtask 125 | 126 | endmodule 127 | 128 | -------------------------------------------------------------------------------- /MAC_components/crc/crc.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module crc #( 4 | parameter POLYNOMIAL = 5'b00101, 5 | parameter DATA_WIDTH = 8, 6 | parameter CRC_WIDTH = 5, 7 | parameter SEED = 0, 8 | parameter DEBUG = 0, 9 | parameter REVERSE = 1 10 | )( 11 | input [DATA_WIDTH-1:0] data, 12 | input data_enable, 13 | output reg [CRC_WIDTH-1:0] crc_out, 14 | input init, 15 | input clock, 16 | input reset 17 | ); 18 | 19 | function automatic prev; 20 | input integer level; 21 | input integer index; 22 | input [DATA_WIDTH-1:0] data; 23 | input [CRC_WIDTH-1:0] crc; 24 | begin 25 | if (POLYNOMIAL[index]) 26 | begin 27 | if (level) 28 | begin 29 | if (index) 30 | begin 31 | if (DEBUG) 32 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ crc[%0d] ^ data[%0d]", level, index, (index)?index-1:CRC_WIDTH-1, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 33 | prev = prev(level-1, (index)?index-1:CRC_WIDTH-1, data, crc) ^ prev(level-1, CRC_WIDTH-1, data, crc) ^ data[DATA_WIDTH-1-level]; 34 | end 35 | else 36 | begin 37 | if (DEBUG) 38 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ data[%0d]", level, index, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 39 | prev = prev(level-1, CRC_WIDTH-1, data, crc) ^ data[DATA_WIDTH-1-level]; 40 | end 41 | 42 | end 43 | else 44 | begin 45 | if (index) 46 | begin 47 | if (DEBUG) 48 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ crc[%0d] ^ data[%0d] // STOP", level, index, index-1, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 49 | prev = crc[index-1-:1] ^ crc[CRC_WIDTH-1-:1] ^ data[DATA_WIDTH-1-level]; 50 | end 51 | else 52 | begin 53 | if (DEBUG) 54 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ data[%0d] // STOP", level, index, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 55 | prev = crc[CRC_WIDTH-1-:1] ^ data[DATA_WIDTH-1-level]; 56 | end 57 | end 58 | end 59 | else 60 | begin 61 | if (level) 62 | begin 63 | if (index) 64 | begin 65 | if (DEBUG) 66 | $display("LEVEL %0d | crc[%0d] = crc[%0d]", level, index, index - 1); 67 | prev = prev(level-1, index-1, data, crc); 68 | end 69 | else 70 | begin 71 | if (DEBUG) 72 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ data[%0d]", level, index, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 73 | prev = prev(level-1, CRC_WIDTH-1, data, crc) ^ data[DATA_WIDTH-1-level]; 74 | end 75 | end 76 | else 77 | begin 78 | if (index) 79 | begin 80 | if (DEBUG) 81 | $display("LEVEL %0d | crc[%0d] = crc[%0d] // STOP", level, index, index - 1); 82 | prev = crc[index-1-:1]; 83 | end 84 | else 85 | begin 86 | if (DEBUG) 87 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ data[%0d] // STOP", level, index, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 88 | prev = crc[CRC_WIDTH-1-:1] ^ data[DATA_WIDTH-1-level]; 89 | end 90 | end 91 | end 92 | end 93 | endfunction 94 | 95 | wire [DATA_WIDTH-1:0] temp; 96 | 97 | genvar j; 98 | generate 99 | if (REVERSE) 100 | begin 101 | for (j = DATA_WIDTH-1; j >= 0; j = j - 1) 102 | begin : reverse_loop 103 | assign temp[DATA_WIDTH-1-j] = data[j]; 104 | end 105 | end 106 | else 107 | begin 108 | assign temp = data; 109 | end 110 | endgenerate 111 | 112 | genvar i; 113 | generate 114 | for(i = 0; i < CRC_WIDTH; i= i + 1) 115 | begin : loop 116 | always @(posedge clock) 117 | begin 118 | if (reset) 119 | begin 120 | crc_out[i+:1] = SEED[i+:1]; 121 | end 122 | else if (init) 123 | begin 124 | crc_out[i+:1] = SEED[i+:1]; 125 | end 126 | else if (data_enable) 127 | begin 128 | if (DEBUG) 129 | $display("\n\nCRC OUT[%0d]\n***************************************************************************", i); 130 | crc_out[i+:1] <= prev(DATA_WIDTH-1,i,temp,crc_out); 131 | end 132 | end 133 | end 134 | endgenerate 135 | 136 | endmodule 137 | 138 | 139 | -------------------------------------------------------------------------------- /MAC_components/crc/tb/crc_tb_ETHERNET_0.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module crc_tb #( 4 | parameter CRC_WIDTH = 32, 5 | parameter DATA_WIDTH = 8, 6 | parameter POLYNOMIAL = 32'h04C11DB7, 7 | parameter SEED = 32'hFFFFFFFF 8 | )(); 9 | 10 | `include "dut.v" 11 | 12 | reg [7:0] packet [0:91]; 13 | integer i; 14 | integer j; 15 | reg [7:0] temp; 16 | reg [31:0] temp2; 17 | reg [31:0] temp3; 18 | 19 | initial 20 | begin 21 | #15 reset = 0; 22 | 23 | $readmemh("packet.hex", packet); 24 | 25 | for(i = 0; i < 92; i = i + 1) 26 | begin 27 | util.sync_write(packet[i]); 28 | end 29 | 30 | util.sync_read(tempdata); 31 | 32 | for (j = 31; j >= 0; j = j - 1) 33 | begin 34 | temp2[31-j] = tempdata[j]; 35 | end 36 | 37 | $display("Normal: %x",tempdata); 38 | $display("Reversed: %x",temp2); 39 | $display("Reversed & Inverted: %x",~temp2); 40 | 41 | tempdata = ~tempdata; 42 | $display("Inverted: %x",tempdata); 43 | 44 | for (j = 4; j > 0; j = j - 1) 45 | begin 46 | temp3[(j*8)-1-:8] = ~temp2[((4-j)*8)+:8]; 47 | end 48 | 49 | $display("Reversed & Inverted & Byte Re-order: %x",temp3); 50 | 51 | util.assert(temp3 == 32'hc0f447ca, "CRC == 0xc0f447ca"); 52 | 53 | $finish; 54 | end 55 | 56 | endmodule 57 | 58 | -------------------------------------------------------------------------------- /MAC_components/crc/tb/crc_tb_ETHERNET_1.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module crc_tb #( 4 | parameter CRC_WIDTH = 32, 5 | parameter DATA_WIDTH = 8, 6 | parameter POLYNOMIAL = 32'h04C11DB7, 7 | parameter SEED = 32'h00000000 8 | )(); 9 | 10 | `include "dut.v" 11 | 12 | initial 13 | begin 14 | #15 reset = 0; 15 | 16 | util.sync_write(8'hAA); 17 | util.sync_read(tempdata); 18 | util.assert(tempdata == 32'hdea580d8, "CRC == 0xdea580d8"); 19 | util.sync_write(8'hAA); 20 | util.sync_read(tempdata); 21 | util.assert(tempdata == 32'h5630b33b, "CRC == 0x5630b33b"); 22 | 23 | $finish; 24 | end 25 | 26 | endmodule 27 | 28 | -------------------------------------------------------------------------------- /MAC_components/crc/tb/crc_tb_ETHERNET_2.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module crc_tb #( 4 | parameter CRC_WIDTH = 32, 5 | parameter DATA_WIDTH = 8, 6 | parameter POLYNOMIAL = 32'h04C11DB7, 7 | parameter SEED = 32'hFFFFFFFF 8 | )(); 9 | 10 | `include "dut.v" 11 | 12 | reg [7:0] packet [0:95]; 13 | integer i; 14 | integer j; 15 | reg [7:0] temp; 16 | 17 | initial 18 | begin 19 | #15 reset = 0; 20 | 21 | $readmemh("packet.hex", packet); 22 | 23 | for(i = 0; i < 96; i = i + 1) 24 | begin 25 | util.sync_write(packet[i]); 26 | end 27 | 28 | util.sync_read(tempdata); 29 | 30 | util.assert(tempdata == 32'hc704dd7b, "CRC == 0xc704dd7b"); 31 | 32 | $finish; 33 | end 34 | 35 | endmodule 36 | 37 | -------------------------------------------------------------------------------- /MAC_components/crc/tb/crc_tb_USB.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module crc_tb #( 4 | parameter CRC_WIDTH = 5, 5 | parameter DATA_WIDTH = 8, 6 | parameter POLYNOMIAL = 5'b00101, 7 | parameter SEED = 0 8 | )(); 9 | 10 | `include "dut.v" 11 | 12 | initial 13 | begin 14 | #15 reset = 0; 15 | 16 | util.sync_write(8'hAA); 17 | util.sync_read(tempdata); 18 | util.assert(tempdata == 5'b11000, 1); 19 | util.sync_write(8'hAA); 20 | util.sync_read(tempdata); 21 | util.assert(tempdata == 5'b10001, 2); 22 | 23 | $finish; 24 | end 25 | 26 | endmodule 27 | 28 | -------------------------------------------------------------------------------- /MAC_components/crc/tb/dut.v: -------------------------------------------------------------------------------- 1 | wire [DATA_WIDTH-1:0] data_in; 2 | wire data_in_enable; 3 | wire [CRC_WIDTH-1:0] crc_out; 4 | reg clock; 5 | reg reset; 6 | reg [CRC_WIDTH-1:0] tempdata; 7 | 8 | crc #( .POLYNOMIAL(POLYNOMIAL), 9 | .DATA_WIDTH(DATA_WIDTH), 10 | .CRC_WIDTH(CRC_WIDTH), 11 | .SEED(SEED), 12 | .DEBUG(0)) 13 | U_crc( 14 | .data(data_in), 15 | .data_enable(data_in_enable), 16 | .crc_out(crc_out), 17 | .init(), 18 | .clock(clock), 19 | .reset(reset) 20 | ); 21 | 22 | utilities #(.OUT_WIDTH (DATA_WIDTH), 23 | .IN_WIDTH (CRC_WIDTH), 24 | .DEBUG(1)) 25 | util ( 26 | .data_in(crc_out), 27 | .data_in_enable(), 28 | .data_out(data_in), 29 | .data_out_enable(data_in_enable), 30 | .clock(clock) 31 | ); 32 | 33 | initial 34 | begin 35 | clock = 0; 36 | reset = 1; 37 | end 38 | 39 | always 40 | #5 clock = ~clock; 41 | -------------------------------------------------------------------------------- /MAC_components/crc/tb/packet.hex: -------------------------------------------------------------------------------- 1 | ff ff ff ff ff ff d0 50 99 98 96 8c 08 00 45 00 00 4e 22 2d 00 00 80 11 f5 21 a9 fe cf 53 a9 fe ff ff 00 89 00 89 00 3a 7a aa b0 eb 01 10 00 01 00 00 00 00 00 00 20 45 4d 45 4a 46 47 45 46 43 4f 45 45 45 46 45 46 46 4b 45 46 46 43 43 4f 45 44 45 50 45 4e 41 41 00 00 20 00 01 c0 f4 47 ca 2 | -------------------------------------------------------------------------------- /MAC_components/crc/tb/packet2.hex: -------------------------------------------------------------------------------- 1 | 00 10 A4 7B EA 80 00 12 34 56 78 90 08 00 45 00 00 2E B3 FE 00 00 80 11 05 40 C0 A8 00 2C C0 A8 00 04 04 00 04 00 00 1A 2D E8 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 2 | -------------------------------------------------------------------------------- /MAC_components/crc/utilities/monitor.v: -------------------------------------------------------------------------------- 1 | module monitor #( 2 | parameter WIDTH = 8 3 | )( 4 | input wire [WIDTH-1:0] data, 5 | input wire expected, 6 | input wire clock 7 | ); 8 | 9 | always @(posedge clock) 10 | begin 11 | if (data != expected) 12 | begin 13 | $display("MONITOR FAILED"); 14 | end 15 | end 16 | 17 | endmodule 18 | -------------------------------------------------------------------------------- /MAC_components/crc/utilities/utilities.v: -------------------------------------------------------------------------------- 1 | module utilities #( 2 | parameter IN_WIDTH = 8, 3 | parameter OUT_WIDTH = 8, 4 | parameter DEBUG = 0 5 | )( 6 | output reg [OUT_WIDTH-1:0] data_out, 7 | output reg data_out_enable, 8 | input wire [IN_WIDTH-1:0] data_in, 9 | output reg data_in_enable, 10 | input wire clock 11 | ); 12 | 13 | integer passes; 14 | integer fails; 15 | initial 16 | begin 17 | data_out = 0; 18 | data_out_enable = 0; 19 | data_in_enable = 0; 20 | passes = 0; 21 | fails = 0; 22 | end 23 | task display; 24 | begin 25 | $display("PASSES:%d FAILS:%d", passes, fails); 26 | end 27 | endtask 28 | 29 | task sync_assert; 30 | input condition; 31 | input [100*8:0] message; 32 | begin 33 | @(posedge clock) 34 | if (condition) 35 | begin 36 | $display("ASSERTION PASSED | %0s", message); 37 | passes = passes + 1; 38 | end 39 | else 40 | begin 41 | $display("ASSERTION FAILED | %0s", message); 42 | fails = fails + 1; 43 | end 44 | end 45 | endtask 46 | 47 | task assert; 48 | input condition; 49 | input [100*8:0] message; 50 | begin 51 | if (condition) 52 | begin 53 | $display("ASSERTION PASSED | %0s", message); 54 | passes = passes + 1; 55 | end 56 | else 57 | begin 58 | $display("ASSERTION FAILED | %0s", message); 59 | fails = fails + 1; 60 | end 61 | end 62 | endtask 63 | 64 | task sync_write; 65 | input [OUT_WIDTH-1:0] data; 66 | begin 67 | data_out = data; 68 | data_out_enable = 1; 69 | @(posedge clock); 70 | #1 data_out_enable = 0; 71 | data_out = 0; 72 | if (DEBUG) 73 | $display("Wrote: 0x%0x | 0b%0b | %0d",data, data, data); 74 | end 75 | endtask 76 | 77 | task sync_read; 78 | output [IN_WIDTH-1:0] data; 79 | begin 80 | data_in_enable = 1; 81 | @(posedge clock); 82 | #1 data = data_in; 83 | data_in_enable = 0; 84 | if (DEBUG) 85 | $display("Read: 0x%0x | 0b%0b | %0d", data, data, data); 86 | end 87 | endtask 88 | 89 | endmodule 90 | 91 | 92 | -------------------------------------------------------------------------------- /MAC_components/state_machines/packet.hex: -------------------------------------------------------------------------------- 1 | 55 55 55 55 55 55 55 D5 ff ff ff ff ff ff d0 50 99 98 96 8c 08 00 45 00 00 4e 22 2d 00 00 80 11 f5 21 a9 fe cf 53 a9 fe ff ff 00 89 00 89 00 3a 7a aa b0 eb 01 10 00 01 00 00 00 00 00 00 20 45 4d 45 4a 46 47 45 46 43 4f 45 45 45 46 45 46 46 4b 45 46 46 43 43 4f 45 44 45 50 45 4e 41 41 00 00 20 00 01 c0 f4 47 ca 2 | -------------------------------------------------------------------------------- /MAC_components/state_machines/random.v: -------------------------------------------------------------------------------- 1 | module random_gen( 2 | input reset, 3 | input clock, 4 | input init, 5 | input [3:0] retry_count, 6 | output reg trigger 7 | ); 8 | 9 | reg [9:0] random_sequence; 10 | reg [9:0] random; 11 | reg [9:0] random_counter; 12 | reg [7:0] slot_time_counter; //256*2=512bit=1 slot time 13 | 14 | always @ (posedge clock or posedge reset) 15 | if (reset) 16 | random_sequence <= 0; 17 | else 18 | random_sequence <= {random_sequence[8:0],~(random_sequence[2]^random_sequence[9])}; 19 | 20 | always @ (retry_count or random_sequence) 21 | case (retry_count) 22 | 4'h0 : random = {9'b0, random_sequence[0]}; 23 | 4'h1 : random = {8'b0, random_sequence[1:0]}; 24 | 4'h2 : random = {7'b0, random_sequence[2:0]}; 25 | 4'h3 : random = {6'b0, random_sequence[3:0]}; 26 | 4'h4 : random = {5'b0, random_sequence[4:0]}; 27 | 4'h5 : random = {4'b0, random_sequence[5:0]}; 28 | 4'h6 : random = {3'b0, random_sequence[6:0]}; 29 | 4'h7 : random = {2'b0, random_sequence[7:0]}; 30 | 4'h8 : random = {1'b0, random_sequence[8:0]}; 31 | 4'h9 : random = { random_sequence[9:0]}; 32 | default : random = { random_sequence[9:0]}; 33 | endcase 34 | 35 | always @ (posedge clock or posedge reset) 36 | if (reset) 37 | slot_time_counter <= 0; 38 | else if(init) 39 | slot_time_counter <= 0; 40 | else if(!trigger) 41 | slot_time_counter <= slot_time_counter + 1; 42 | 43 | always @ (posedge clock or posedge reset) 44 | if (reset) 45 | random_counter <= 0; 46 | else if (init) 47 | random_counter <= random; 48 | else if (random_counter != 0 && slot_time_counter == 255) 49 | random_counter <= random_counter - 1; 50 | 51 | always @ (posedge clock or posedge reset) 52 | if (reset) 53 | trigger <= 1; 54 | else if (init) 55 | trigger <= 0; 56 | else if (random_counter == 0) 57 | trigger <= 1; 58 | 59 | endmodule 60 | 61 | 62 | -------------------------------------------------------------------------------- /MAC_components/state_machines/rx.v: -------------------------------------------------------------------------------- 1 | module rx #( 2 | parameter STATE_IDLE = 3'h0, 3 | parameter STATE_PREAMBLE = 3'h1, 4 | parameter STATE_DATA = 3'h2, 5 | parameter STATE_OK = 3'h3, 6 | parameter STATE_DROP = 3'h4, 7 | parameter STATE_ERROR = 3'h5 8 | )( 9 | input reset, 10 | input clock, 11 | 12 | input rx_data_valid, 13 | input [7:0] rx_data, 14 | input rx_error, 15 | 16 | output reg [7:0] data_out, 17 | output reg data_out_enable, 18 | output reg data_out_start, 19 | output reg data_out_end, 20 | input wire fifo_full, 21 | output reg error 22 | ); 23 | 24 | localparam CRC_RESIDUE = 32'hC704DD7B; 25 | localparam CRC_POLYNOMIAL = 32'h04C11DB7; 26 | localparam CRC_SEED = 32'hFFFFFFFF; 27 | localparam MAX_SIZE = 1518; 28 | localparam MIN_SIZE = 64; 29 | 30 | reg [2:0] state; 31 | reg [2:0] next_state; 32 | reg [15:0] frame_length_counter; 33 | reg [15:0] data_counter; 34 | reg too_long; 35 | reg too_short; 36 | 37 | reg crc_init; 38 | reg data_enable; 39 | wire [31:0] crc_out; 40 | 41 | reg [39:0] data; 42 | 43 | // RX State Machine 44 | always @ (posedge clock) 45 | if (reset) 46 | state <= STATE_IDLE; 47 | else 48 | state <= next_state; 49 | 50 | always @ (*) 51 | case (state) 52 | STATE_IDLE: 53 | if (rx_data_valid && rx_data == 8'h55) 54 | next_state = STATE_PREAMBLE; 55 | else 56 | next_state = STATE_IDLE; 57 | STATE_PREAMBLE: 58 | if (!rx_data_valid) 59 | next_state = STATE_ERROR; 60 | else if (rx_error) 61 | next_state = STATE_DROP; 62 | else if (rx_data == 8'hd5) 63 | next_state = STATE_DATA; 64 | else if (rx_data == 8'h55) 65 | next_state = STATE_PREAMBLE; 66 | else 67 | next_state = STATE_DROP; 68 | STATE_DATA: 69 | if (!rx_data_valid && !too_short && !too_long && crc_out == CRC_RESIDUE) 70 | next_state = STATE_OK; 71 | else if ((!rx_data_valid && (too_short || too_long)) || (!rx_data_valid && crc_out != CRC_RESIDUE)) 72 | next_state = STATE_ERROR; 73 | else if (fifo_full) 74 | next_state = STATE_DROP; 75 | else if (rx_error || too_long) 76 | next_state = STATE_DROP; 77 | else 78 | next_state = STATE_DATA; 79 | STATE_DROP: 80 | if (!rx_data_valid) 81 | next_state = STATE_ERROR; 82 | else 83 | next_state = STATE_DROP; 84 | STATE_OK: 85 | next_state = STATE_IDLE; 86 | STATE_ERROR: 87 | next_state = STATE_IDLE; 88 | default: 89 | next_state = STATE_IDLE; 90 | endcase 91 | 92 | always @(posedge clock) 93 | data_out <= data[39-:8]; 94 | 95 | always @(posedge clock) 96 | begin 97 | if (reset) 98 | begin 99 | data <= 32'h00000000; 100 | end 101 | else if (state == STATE_IDLE) 102 | begin 103 | data <= 32'h00000000; 104 | end 105 | else 106 | begin 107 | data[39-:8] <= data[31-:8]; 108 | data[31-:8] <= data[23-:8]; 109 | data[23-:8] <= data[15-:8]; 110 | data[15-:8] <= data[7-:8]; 111 | data[7-:8] <= rx_data; 112 | end 113 | end 114 | 115 | always @ (posedge clock) 116 | if (reset) 117 | data_counter <= 0; 118 | else if (state == STATE_DATA) 119 | data_counter = data_counter + 1; 120 | else 121 | data_counter = 0; 122 | 123 | always @ (*) 124 | if (data_counter > 5 && (state == STATE_DATA || state == STATE_OK || state == STATE_ERROR)) 125 | data_out_enable = 1; 126 | else 127 | data_out_enable = 0; 128 | 129 | always @(*) 130 | if (data_counter == 6) 131 | data_out_start = 1; 132 | else 133 | data_out_start = 0; 134 | 135 | always @(*) 136 | if (state == STATE_OK || state == STATE_ERROR) 137 | data_out_end = 1; 138 | else 139 | data_out_end = 0; 140 | 141 | always @(*) 142 | if (state == STATE_ERROR) 143 | error = 1; 144 | else 145 | error = 0; 146 | 147 | // CRC Interface 148 | always @(*) 149 | if (state == STATE_DATA) 150 | data_enable = 1; 151 | else 152 | data_enable = 0; 153 | 154 | always @(*) 155 | if (state == STATE_PREAMBLE && next_state == STATE_DATA) 156 | crc_init = 1; 157 | else 158 | crc_init = 0; 159 | 160 | always @ (posedge clock) 161 | if (reset) 162 | frame_length_counter <= 0; 163 | else if (state == STATE_DATA) 164 | frame_length_counter = frame_length_counter + 1; 165 | else 166 | frame_length_counter = 0; 167 | 168 | always @ (*) 169 | if (frame_length_counter < MIN_SIZE) 170 | too_short = 1; 171 | else 172 | too_short = 0; 173 | 174 | always @ (*) 175 | if (frame_length_counter > MAX_SIZE) 176 | too_long = 1; 177 | else 178 | too_long = 0; 179 | 180 | // CRC 181 | crc #( .POLYNOMIAL(CRC_POLYNOMIAL), 182 | .DATA_WIDTH(8), 183 | .CRC_WIDTH(32), 184 | .SEED(CRC_SEED)) 185 | U_crc( 186 | .reset(reset), 187 | .clock(clock), 188 | .init(crc_init), 189 | .data(rx_data), 190 | .data_enable(data_enable), 191 | .crc_out(crc_out) 192 | ); 193 | 194 | endmodule 195 | -------------------------------------------------------------------------------- /MAC_components/state_machines/rx_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module rx_tb(); 4 | 5 | reg reset; 6 | 7 | wire [7:0] data_out; 8 | wire data_out_enable; 9 | wire data_out_start; 10 | wire data_out_end; 11 | wire error; 12 | reg clock; 13 | reg rx_data_valid; 14 | reg rx_error; 15 | reg [7:0] rx_data; 16 | reg fifo_full; 17 | reg [7:0] packet [0:1518]; 18 | 19 | integer i; 20 | 21 | rx U_rx ( 22 | .reset(reset), 23 | .clock(clock), 24 | 25 | .rx_data_valid(rx_data_valid), 26 | .rx_data(rx_data), 27 | .rx_error(rx_error), 28 | 29 | .data_out(data_out), 30 | .data_out_enable(data_out_enable), 31 | .data_out_start(data_out_start), 32 | .data_out_end(data_out_end), 33 | .fifo_full(fifo_full), 34 | .error(error) 35 | ); 36 | 37 | initial 38 | begin 39 | $dumpfile("test.vcd"); 40 | $dumpvars(0, rx_tb); 41 | end 42 | 43 | initial 44 | begin 45 | reset = 1; 46 | clock = 0; 47 | rx_data = 0; 48 | fifo_full = 0; 49 | $readmemh("packet.hex", packet); 50 | 51 | #15 reset = 0; 52 | 53 | // Send a packet 54 | for(i = 0; i < 104; i = i + 1) 55 | begin 56 | push(packet[i], 1, 0); 57 | end 58 | 59 | #100 60 | 61 | $finish; 62 | end 63 | 64 | always 65 | #2 clock = ~clock; 66 | 67 | task push; 68 | input [7:0] data; 69 | input data_valid; 70 | input data_error; 71 | begin 72 | rx_data = data; 73 | rx_data_valid = data_valid; 74 | rx_error = data_error; 75 | @(posedge clock); 76 | #1 rx_data_valid = 0; 77 | rx_error = 0; 78 | $display("Pushed: %x Valid: %b Error: %b",data, data_valid, data_error ); 79 | end 80 | endtask 81 | 82 | endmodule 83 | 84 | -------------------------------------------------------------------------------- /MAC_components/state_machines/tx.v: -------------------------------------------------------------------------------- 1 | module tx_sm #( 2 | parameter STATE_DEFER = 4'h0, 3 | parameter STATE_IFG = 4'h1, 4 | parameter STATE_IDLE = 4'h2, 5 | parameter STATE_PREAMBLE = 4'h3, 6 | parameter STATE_SFD = 4'h4, 7 | parameter STATE_DATA = 4'h5, 8 | parameter STATE_PAD = 4'h6, 9 | parameter STATE_JAM = 4'h7, 10 | parameter STATE_BACKOFF = 4'h8, 11 | parameter STATE_FCS = 4'h9, 12 | parameter STATE_JAM_DROP = 4'hA, 13 | parameter STATE_NEXT = 4'hB 14 | )( 15 | input wire reset, 16 | input wire clock, 17 | 18 | input wire [7:0] fifo_data, 19 | output reg fifo_data_read, 20 | input wire fifo_data_start, 21 | input wire fifo_data_end, 22 | input wire fifo_data_available, 23 | output reg fifo_retry, 24 | 25 | input wire mode, 26 | 27 | input wire carrier_sense, 28 | input wire collision, 29 | 30 | output reg tx_enable, 31 | output reg [7:0] tx_data 32 | ); 33 | 34 | localparam HALF_DUPLEX = 0; 35 | localparam FULL_DUPLEX = 1; 36 | 37 | reg [3:0] state; 38 | reg [3:0] next_state; 39 | reg [7:0] frame_length_count; 40 | reg [5:0] padding_length_count; 41 | reg [4:0] jam_length_count; 42 | reg [3:0] inter_frame_gap_count; 43 | reg [3:0] preamble_count; 44 | reg [3:0] retry_count; 45 | 46 | reg crc_init; 47 | reg crc_enable; 48 | wire [31:0] crc_out; 49 | integer crc_index; 50 | wire [31:0] crc_rev; 51 | 52 | reg random_init; 53 | wire random_trigger; 54 | 55 | // State update 56 | always @(posedge clock) 57 | if (reset) 58 | state <= STATE_DEFER; 59 | else 60 | state <= next_state; 61 | 62 | // State Machine 63 | always @ (*) 64 | case (state) 65 | STATE_DEFER: 66 | if ((mode == FULL_DUPLEX) || (mode == HALF_DUPLEX && !carrier_sense)) 67 | next_state = STATE_IFG; 68 | else 69 | next_state = STATE_DEFER; 70 | STATE_IFG: 71 | if (mode == HALF_DUPLEX && carrier_sense) 72 | next_state = STATE_DEFER; 73 | else if ((mode == FULL_DUPLEX && inter_frame_gap_count == 12 - 4) || (mode == HALF_DUPLEX && !carrier_sense && inter_frame_gap_count == 12 - 4)) // Drop IFG by four to account for state transitions 74 | next_state = STATE_IDLE; 75 | else 76 | next_state = STATE_IFG; 77 | STATE_IDLE: 78 | if (mode == HALF_DUPLEX && carrier_sense) 79 | next_state = STATE_DEFER; 80 | else if ((mode == FULL_DUPLEX && fifo_data_available) || (mode == HALF_DUPLEX && !carrier_sense && fifo_data_available)) 81 | next_state = STATE_PREAMBLE; 82 | else 83 | next_state = STATE_IDLE; 84 | STATE_PREAMBLE: 85 | if (mode == HALF_DUPLEX && collision) 86 | next_state = STATE_JAM; 87 | else if ((mode == FULL_DUPLEX && preamble_count == 6) || (mode == HALF_DUPLEX && !collision && preamble_count == 6)) 88 | next_state = STATE_SFD; 89 | else 90 | next_state = STATE_PREAMBLE; 91 | STATE_SFD: 92 | if (mode == HALF_DUPLEX && collision) 93 | next_state = STATE_JAM; 94 | else 95 | next_state = STATE_DATA; 96 | STATE_DATA: 97 | if (mode == HALF_DUPLEX && collision) 98 | next_state = STATE_JAM; 99 | else if (fifo_data_end && frame_length_count >= 59 ) 100 | next_state = STATE_FCS; 101 | else if (fifo_data_end) 102 | next_state = STATE_PAD; 103 | else 104 | next_state = STATE_DATA; 105 | STATE_PAD: 106 | if (mode == HALF_DUPLEX && collision) 107 | next_state = STATE_JAM; 108 | else if (frame_length_count >= 59) 109 | next_state = STATE_FCS; 110 | else 111 | next_state = STATE_PAD; 112 | STATE_JAM: 113 | if (retry_count <= 2 && jam_length_count == 16) 114 | next_state = STATE_BACKOFF; 115 | else if (retry_count > 2) 116 | next_state = STATE_JAM_DROP; 117 | else 118 | next_state = STATE_JAM; 119 | STATE_BACKOFF: 120 | if (random_trigger) 121 | next_state = STATE_DEFER; 122 | else 123 | next_state = STATE_BACKOFF; 124 | STATE_FCS: 125 | if (mode == HALF_DUPLEX && collision) 126 | next_state = STATE_JAM; 127 | else if (crc_index > 23) 128 | next_state = STATE_NEXT; 129 | else 130 | next_state = STATE_FCS; 131 | STATE_JAM_DROP: 132 | if (fifo_data_end) 133 | next_state = STATE_NEXT; 134 | else 135 | next_state = STATE_JAM_DROP; 136 | STATE_NEXT: 137 | next_state = STATE_DEFER; 138 | default: 139 | next_state = STATE_DEFER; 140 | endcase 141 | 142 | // Counts 143 | 144 | // Frame Length 145 | always @(posedge clock) 146 | if (reset) 147 | frame_length_count <= 0; 148 | else if (state == STATE_DEFER) 149 | frame_length_count <= 0; 150 | else if (state == STATE_DATA || state == STATE_PAD) 151 | frame_length_count <= frame_length_count+1; 152 | 153 | // Padding Length 154 | always @(posedge clock) 155 | if (reset) 156 | padding_length_count <=0; 157 | else if (state != STATE_PAD) 158 | padding_length_count <= 0; 159 | else 160 | padding_length_count <= padding_length_count + 1; 161 | 162 | // Jam Length 163 | always @ (posedge clock) 164 | if (reset) 165 | jam_length_count <= 0; 166 | else if (state == STATE_JAM || next_state == STATE_JAM) 167 | jam_length_count <= jam_length_count + 1; 168 | else 169 | jam_length_count <= 0; 170 | 171 | // Inter-Frame Gap 172 | always @ (posedge clock) 173 | if (reset) 174 | inter_frame_gap_count <= 0; 175 | else if (state != STATE_IFG) 176 | inter_frame_gap_count <= 0; 177 | else 178 | inter_frame_gap_count <= inter_frame_gap_count + 1; 179 | 180 | // Preamble 181 | always @ (posedge clock) 182 | if (reset) 183 | preamble_count <= 0; 184 | else if (state != STATE_PREAMBLE) 185 | preamble_count <= 0; 186 | else 187 | preamble_count <= preamble_count + 1; 188 | 189 | // Retry Counter 190 | always @ (posedge clock) 191 | if (reset) 192 | retry_count <= 0; 193 | else if (state == STATE_NEXT) 194 | retry_count <= 0; 195 | else if (state == STATE_JAM && next_state == STATE_BACKOFF) 196 | retry_count <= retry_count + 1; 197 | 198 | // State Output Actions 199 | 200 | genvar j; 201 | generate 202 | for (j = 31; j >= 0; j = j - 1) 203 | begin : crc_reverse 204 | assign crc_rev[31-j] = crc_out[j]; 205 | end 206 | endgenerate 207 | 208 | // FIFO 209 | always @ (*) 210 | if (state == STATE_DATA || 211 | state == STATE_JAM_DROP) 212 | fifo_data_read = 1; 213 | else 214 | fifo_data_read = 0; 215 | 216 | always @ (*) 217 | if (state == STATE_JAM) 218 | fifo_retry = 1; 219 | else 220 | fifo_retry = 0; 221 | 222 | // Transmit Enable 223 | always @(*) 224 | if (state == STATE_PREAMBLE || 225 | state == STATE_SFD || 226 | state == STATE_DATA || 227 | state == STATE_FCS || 228 | state == STATE_PAD || 229 | state == STATE_JAM ) 230 | tx_enable <= 1; 231 | else 232 | tx_enable <= 0; 233 | 234 | // Transmit Data 235 | always @(*) 236 | case (state) 237 | STATE_PREAMBLE: 238 | tx_data = 8'h55; 239 | STATE_SFD: 240 | tx_data = 8'hD5; 241 | STATE_DATA: 242 | tx_data = fifo_data; 243 | STATE_PAD: 244 | tx_data = 8'h00; 245 | STATE_JAM: 246 | tx_data = 8'h01; 247 | STATE_FCS: 248 | tx_data = ~crc_rev[crc_index+:8]; 249 | default: 250 | tx_data = 8'b00; 251 | endcase 252 | 253 | always @(posedge clock) 254 | if(state == STATE_FCS) 255 | crc_index = crc_index + 8; 256 | else 257 | crc_index = 0; 258 | 259 | // CRC 260 | always @(*) 261 | if (state == STATE_SFD) 262 | crc_init = 1; 263 | else 264 | crc_init = 0; 265 | 266 | always @(*) 267 | if (state == STATE_DATA || state == STATE_PAD) 268 | crc_enable = 1; 269 | else 270 | crc_enable = 0; 271 | 272 | // Random Calculation for Backoff 273 | always @(*) 274 | if (state == STATE_JAM && next_state == STATE_BACKOFF) 275 | random_init = 1; 276 | else 277 | random_init = 0; 278 | 279 | // Submodule Initialisation 280 | 281 | // CRC 282 | crc #( .POLYNOMIAL(32'h04C11DB7), 283 | .DATA_WIDTH(8), 284 | .CRC_WIDTH(32), 285 | .SEED(32'hFFFFFFFF)) 286 | U_crc( 287 | .reset(reset), 288 | .clock(clock), 289 | .init(crc_init), 290 | .data(tx_data), 291 | .data_enable(crc_enable), 292 | .crc_out(crc_out) 293 | ); 294 | 295 | random_gen U_random_gen( 296 | .reset(reset), 297 | .clock(clock), 298 | .init(random_init), 299 | .retry_count(retry_count), 300 | .trigger(random_trigger) 301 | ); 302 | 303 | endmodule 304 | -------------------------------------------------------------------------------- /MAC_components/state_machines/tx_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module tx_tb(); 4 | 5 | reg reset; 6 | reg clock; 7 | 8 | wire [7:0] tx_data; 9 | wire tx_enable; 10 | reg fifo_data_start; 11 | reg fifo_data_end; 12 | reg [7:0] fifo_data; 13 | wire fifo_data_read; 14 | reg [7:0] packet [0:1518]; 15 | reg data_available; 16 | 17 | 18 | 19 | integer i; 20 | 21 | tx_sm U_tx_sm ( 22 | .reset(reset), 23 | .clock(clock), 24 | 25 | .fifo_data(fifo_data), 26 | .fifo_data_read(fifo_data_read), 27 | .fifo_data_start(fifo_data_start), 28 | .fifo_data_end(fifo_data_end), 29 | .fifo_data_available(data_available), 30 | .fifo_retry(retry), 31 | 32 | .mode(1'b1), 33 | 34 | .carrier_sense(), 35 | .collision(), 36 | 37 | .tx_enable(tx_enable), 38 | .tx_data(tx_data) 39 | ); 40 | 41 | initial 42 | begin 43 | $dumpfile("test.vcd"); 44 | $dumpvars(0, tx_tb); 45 | end 46 | 47 | initial 48 | begin 49 | reset = 1; 50 | clock = 0; 51 | fifo_data = 0; 52 | data_available = 0; 53 | $readmemh("packet.hex", packet); 54 | 55 | #15 reset = 0; 56 | 57 | // Send a packet 58 | 59 | data_available = 1; 60 | wait_for_read(); 61 | 62 | push(packet[8], 1, 0); 63 | 64 | for(i = 9; i < 99; i = i + 1) 65 | begin 66 | push(packet[i], 0, 0); 67 | end 68 | 69 | push(packet[i], 0, 1); 70 | 71 | #100 72 | 73 | $finish; 74 | end 75 | 76 | always 77 | #2 clock = ~clock; 78 | 79 | task push; 80 | input [7:0] data; 81 | input data_start; 82 | input data_end; 83 | begin 84 | fifo_data = data; 85 | fifo_data_start = data_start; 86 | fifo_data_end = data_end; 87 | @(posedge clock); 88 | #1 fifo_data_start = 0; 89 | fifo_data_end = 0; 90 | $display("Pushed: %x Start: %b End: %b",data, data_start, data_end ); 91 | end 92 | endtask 93 | 94 | task wait_for_read; 95 | begin 96 | @(posedge fifo_data_read); 97 | end 98 | endtask 99 | 100 | endmodule 101 | 102 | -------------------------------------------------------------------------------- /Open Source Ethernet MAC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/Open Source Ethernet MAC.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mac 2 | An Ethernet MAC conforming to IEEE 802.3 3 | -------------------------------------------------------------------------------- /Table.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/Table.xlsx -------------------------------------------------------------------------------- /Verilog Open Source Ethernet MAC.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/Verilog Open Source Ethernet MAC.pptx -------------------------------------------------------------------------------- /arbiter.v: -------------------------------------------------------------------------------- 1 | module round_robin_4 2 | ( 3 | input wire clock, 4 | input wire reset, 5 | 6 | input wire [3:0] request, 7 | output wire [3:0] grant 8 | ); 9 | 10 | reg [$clog2(4)-1:0] counter; 11 | wire [3:0] priority [3:0]; 12 | 13 | assign grant[0-:1] = priority[0][0-:1] | priority[1][3-:1] | priority[2][2-:1] | priority[3][1-:1] ; 14 | assign grant[1-:1] = priority[0][1-:1] | priority[1][0-:1] | priority[2][3-:1] | priority[3][2-:1] ; 15 | assign grant[2-:1] = priority[0][2-:1] | priority[1][1-:1] | priority[2][0-:1] | priority[3][3-:1] ; 16 | assign grant[3-:1] = priority[0][3-:1] | priority[1][2-:1] | priority[2][1-:1] | priority[3][0-:1] ; 17 | 18 | // Ring Counter 19 | always @(posedge clock) 20 | if (reset) 21 | counter <= 0; 22 | else 23 | counter <= counter + 1; 24 | 25 | priority_encoder 26 | #( 27 | .NO_INPUTS(4) 28 | ) U_priority_encoder_0 ( 29 | .enable((counter == 0)), 30 | .in({request[0],request[1],request[2],request[3]}), 31 | .out(priority[0]) 32 | ); 33 | 34 | priority_encoder 35 | #( 36 | .NO_INPUTS(4) 37 | ) U_priority_encoder_1 ( 38 | .enable((counter == 1)), 39 | .in({request[1],request[2],request[3],request[0]}), 40 | .out(priority[1]) 41 | ); 42 | 43 | priority_encoder 44 | #( 45 | .NO_INPUTS(4) 46 | ) U_priority_encoder_2 ( 47 | .enable((counter == 2)), 48 | .in({request[2],request[3],request[0],request[1]}), 49 | .out(priority[2]) 50 | ); 51 | 52 | priority_encoder 53 | #( 54 | .NO_INPUTS(4) 55 | ) U_priority_encoder_3 ( 56 | .enable((counter == 3)), 57 | .in({request[3],request[0],request[1],request[2]}), 58 | .out(priority[2]) 59 | ); 60 | 61 | endmodule 62 | -------------------------------------------------------------------------------- /arbiter_tb.v: -------------------------------------------------------------------------------- 1 | module arbiter_tb(); 2 | 3 | reg clock; 4 | reg reset; 5 | reg [3:0] request; 6 | wire [3:0] grant; 7 | 8 | round_robin_4 rr 9 | ( 10 | .clock(clock), 11 | .reset(reset), 12 | .request(request), 13 | .grant(grant) 14 | ); 15 | 16 | initial 17 | begin 18 | $dumpfile("test.vcd"); 19 | $dumpvars(0,arbiter_tb); 20 | end 21 | 22 | initial 23 | begin 24 | clock = 0; 25 | reset = 1; 26 | request = 0; 27 | 28 | #20 reset = 0; 29 | 30 | request = 5; 31 | 32 | #20 $finish(); 33 | 34 | end 35 | 36 | always 37 | #5 clock = ~clock; 38 | 39 | endmodule 40 | -------------------------------------------------------------------------------- /backoff.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/backoff.xlsx -------------------------------------------------------------------------------- /clock_divider.v: -------------------------------------------------------------------------------- 1 | module clock_divider #( 2 | parameter DIVIDER = 2 3 | )( 4 | input wire reset, 5 | input wire clock_in, 6 | output reg clock_out 7 | ); 8 | 9 | integer count; 10 | 11 | always @(posedge clock_in) 12 | begin 13 | if (reset) 14 | begin 15 | count <= 0; 16 | end 17 | else if (count == DIVIDER - 1) 18 | begin 19 | count <= 0; 20 | end 21 | else 22 | begin 23 | count <= count + 1; 24 | end 25 | end 26 | 27 | always @(posedge clock_in) 28 | begin 29 | if (reset) 30 | begin 31 | clock_out <= 0; 32 | end 33 | else if (count == DIVIDER - 1) 34 | begin 35 | clock_out <= ~clock_out; 36 | end 37 | end 38 | 39 | endmodule 40 | -------------------------------------------------------------------------------- /crc.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module crc #( 4 | parameter POLYNOMIAL = 5'b00101, 5 | parameter DATA_WIDTH = 8, 6 | parameter CRC_WIDTH = 5, 7 | parameter SEED = 0, 8 | parameter DEBUG = 0, 9 | parameter REVERSE = 1 10 | )( 11 | input [DATA_WIDTH-1:0] data, 12 | input data_enable, 13 | output reg [CRC_WIDTH-1:0] crc_out, 14 | input init, 15 | input clock, 16 | input reset 17 | ); 18 | 19 | function automatic prev; 20 | input integer level; 21 | input integer index; 22 | input [DATA_WIDTH-1:0] data; 23 | input [CRC_WIDTH-1:0] crc; 24 | begin 25 | if (POLYNOMIAL[index]) 26 | begin 27 | if (level) 28 | begin 29 | if (index) 30 | begin 31 | if (DEBUG) 32 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ crc[%0d] ^ data[%0d]", level, index, (index)?index-1:CRC_WIDTH-1, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 33 | prev = prev(level-1, (index)?index-1:CRC_WIDTH-1, data, crc) ^ prev(level-1, CRC_WIDTH-1, data, crc) ^ data[DATA_WIDTH-1-level]; 34 | end 35 | else 36 | begin 37 | if (DEBUG) 38 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ data[%0d]", level, index, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 39 | prev = prev(level-1, CRC_WIDTH-1, data, crc) ^ data[DATA_WIDTH-1-level]; 40 | end 41 | 42 | end 43 | else 44 | begin 45 | if (index) 46 | begin 47 | if (DEBUG) 48 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ crc[%0d] ^ data[%0d] // STOP", level, index, index-1, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 49 | prev = crc[index-1-:1] ^ crc[CRC_WIDTH-1-:1] ^ data[DATA_WIDTH-1-level]; 50 | end 51 | else 52 | begin 53 | if (DEBUG) 54 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ data[%0d] // STOP", level, index, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 55 | prev = crc[CRC_WIDTH-1-:1] ^ data[DATA_WIDTH-1-level]; 56 | end 57 | end 58 | end 59 | else 60 | begin 61 | if (level) 62 | begin 63 | if (index) 64 | begin 65 | if (DEBUG) 66 | $display("LEVEL %0d | crc[%0d] = crc[%0d]", level, index, index - 1); 67 | prev = prev(level-1, index-1, data, crc); 68 | end 69 | else 70 | begin 71 | if (DEBUG) 72 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ data[%0d]", level, index, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 73 | prev = prev(level-1, CRC_WIDTH-1, data, crc) ^ data[DATA_WIDTH-1-level]; 74 | end 75 | end 76 | else 77 | begin 78 | if (index) 79 | begin 80 | if (DEBUG) 81 | $display("LEVEL %0d | crc[%0d] = crc[%0d] // STOP", level, index, index - 1); 82 | prev = crc[index-1-:1]; 83 | end 84 | else 85 | begin 86 | if (DEBUG) 87 | $display("LEVEL %0d | crc[%0d] = crc[%0d] ^ data[%0d] // STOP", level, index, CRC_WIDTH-1, DATA_WIDTH - 1 - level); 88 | prev = crc[CRC_WIDTH-1-:1] ^ data[DATA_WIDTH-1-level]; 89 | end 90 | end 91 | end 92 | end 93 | endfunction 94 | 95 | wire [DATA_WIDTH-1:0] temp; 96 | 97 | genvar j; 98 | generate 99 | if (REVERSE) 100 | begin 101 | for (j = DATA_WIDTH-1; j >= 0; j = j - 1) 102 | begin : reverse_loop 103 | assign temp[DATA_WIDTH-1-j] = data[j]; 104 | end 105 | end 106 | else 107 | begin 108 | assign temp = data; 109 | end 110 | endgenerate 111 | 112 | genvar i; 113 | generate 114 | for(i = 0; i < CRC_WIDTH; i= i + 1) 115 | begin : loop 116 | always @(posedge clock) 117 | begin 118 | if (reset) 119 | begin 120 | crc_out[i+:1] = SEED[i+:1]; 121 | end 122 | else if (init) 123 | begin 124 | crc_out[i+:1] = SEED[i+:1]; 125 | end 126 | else if (data_enable) 127 | begin 128 | if (DEBUG) 129 | $display("\n\nCRC OUT[%0d]\n***************************************************************************", i); 130 | crc_out[i+:1] <= prev(DATA_WIDTH-1,i,temp,crc_out); 131 | end 132 | end 133 | end 134 | endgenerate 135 | 136 | endmodule 137 | 138 | 139 | -------------------------------------------------------------------------------- /crc.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/crc.xlsx -------------------------------------------------------------------------------- /gmii.v: -------------------------------------------------------------------------------- 1 | module gmii 2 | ( 3 | input wire reset, 4 | input wire clock_125MHz, 5 | 6 | // PHY Interface 7 | output wire phy_tx_er, 8 | output wire [7:0] phy_txd, 9 | output wire phy_tx_en, 10 | output wire phy_gtx_clk, 11 | input wire phy_col, 12 | input wire [7:0] phy_rxd, 13 | input wire phy_rx_er, 14 | input wire phy_rx_clk, 15 | input wire phy_crs, 16 | input wire phy_rx_dv, 17 | 18 | // MAC Interface 19 | input wire mac_tx_er, 20 | input wire [7:0] mac_txd, 21 | input wire mac_tx_en, 22 | output wire mac_tx_clk, 23 | output wire mac_col, 24 | output wire [7:0] mac_rxd, 25 | output wire mac_rx_er, 26 | output wire mac_rx_clk, 27 | output wire mac_crs, 28 | output wire mac_rx_dv 29 | ); 30 | 31 | assign phy_tx_er = mac_tx_er; 32 | assign phy_txd = mac_txd; 33 | assign phy_tx_en = mac_tx_en; 34 | assign phy_gtx_clk = clock_125MHz; 35 | assign mac_col = phy_col; 36 | assign mac_rxd = phy_rxd; 37 | assign mac_rx_er = phy_rx_er; 38 | assign mac_rx_clk = phy_rx_clk; 39 | assign mac_crs = phy_crs; 40 | assign mac_rx_dv = phy_rx_dv; 41 | assign mac_tx_clk = clock_125MHz; 42 | 43 | endmodule 44 | -------------------------------------------------------------------------------- /mii.v: -------------------------------------------------------------------------------- 1 | module mii 2 | ( 3 | input wire reset, 4 | 5 | // PHY Interface 6 | output wire phy_tx_er, 7 | output reg [3:0] phy_txd, 8 | output wire phy_tx_en, 9 | input wire phy_tx_clk, 10 | input wire phy_col, 11 | input wire [3:0] phy_rxd, 12 | input wire phy_rx_er, 13 | input wire phy_rx_clk, 14 | input wire phy_crs, 15 | input wire phy_rx_dv, 16 | 17 | // MAC Interface 18 | input wire mac_tx_er, 19 | input wire [7:0] mac_txd, 20 | input wire mac_tx_en, 21 | output wire mac_tx_clk, 22 | output wire mac_col, 23 | output reg [7:0] mac_rxd, 24 | output wire mac_rx_er, 25 | output wire mac_rx_clk, 26 | output wire mac_crs, 27 | output wire mac_rx_dv 28 | ); 29 | reg tx_index; 30 | reg rx_index; 31 | 32 | assign phy_tx_er = mac_tx_er; 33 | assign phy_tx_en = mac_tx_en; 34 | assign mac_col = phy_col; 35 | assign mac_rx_er = phy_rx_er; 36 | assign mac_crs = phy_crs; 37 | assign mac_rx_dv = phy_rx_dv; 38 | 39 | clock_divider #(.DIVIDER(2)) clk_div_tx 40 | ( 41 | .reset(reset), 42 | .clock_in(phy_tx_clk), 43 | .clock_out(mac_tx_clk) 44 | ); 45 | 46 | clock_divider #(.DIVIDER(2)) clk_div_rx 47 | ( 48 | .reset(reset), 49 | .clock_in(phy_rx_clk), 50 | .clock_out(mac_rx_clk) 51 | ); 52 | 53 | always @(posedge phy_tx_clk) 54 | begin 55 | if (reset) 56 | begin 57 | tx_index <= 0; 58 | end 59 | else 60 | begin 61 | tx_index <= ~tx_index; 62 | end 63 | end 64 | 65 | always @(posedge phy_tx_clk) 66 | begin 67 | if (reset) 68 | begin 69 | phy_txd <= 0; 70 | end 71 | else 72 | begin 73 | phy_txd <= mac_txd[tx_index*4+:4]; 74 | end 75 | end 76 | 77 | always @(posedge phy_rx_clk) 78 | begin 79 | if (reset) 80 | begin 81 | rx_index <= 0; 82 | end 83 | else 84 | begin 85 | rx_index <= ~rx_index; 86 | end 87 | end 88 | 89 | always @(posedge phy_rx_clk) 90 | begin 91 | if (reset) 92 | begin 93 | mac_rxd <= 0; 94 | end 95 | else 96 | begin 97 | mac_rxd[rx_index*4+:4] <= phy_rxd; 98 | end 99 | end 100 | 101 | endmodule 102 | -------------------------------------------------------------------------------- /mii.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/mii.xlsx -------------------------------------------------------------------------------- /priority_encoder.v: -------------------------------------------------------------------------------- 1 | module priority_encoder 2 | # ( 3 | parameter NO_INPUTS = 4 4 | )( 5 | input wire enable, 6 | input wire [NO_INPUTS-1:0] in, 7 | output reg [NO_INPUTS-1:0] out 8 | ); 9 | 10 | integer i; 11 | 12 | always @(*) 13 | if (enable) 14 | begin 15 | for (i = 0; i < NO_INPUTS; i = i + 1) 16 | begin 17 | if(in[i] && !out) 18 | out = 1 << i; 19 | end 20 | end 21 | else 22 | out = 0; 23 | 24 | endmodule 25 | -------------------------------------------------------------------------------- /random.v: -------------------------------------------------------------------------------- 1 | module random_gen( 2 | input reset, 3 | input clock, 4 | input init, 5 | input [3:0] retry_count, 6 | output reg trigger 7 | ); 8 | 9 | reg [9:0] random_sequence; 10 | reg [9:0] random; 11 | reg [9:0] random_counter; 12 | reg [7:0] slot_time_counter; 13 | 14 | always @ (posedge clock) 15 | if (reset) 16 | random_sequence <= 0; 17 | else 18 | random_sequence <= {random_sequence[8:0],~(random_sequence[2]^random_sequence[9])}; 19 | 20 | always @ (*) 21 | case (retry_count) 22 | 4'h0 : random = {9'b0, random_sequence[0]}; 23 | 4'h1 : random = {8'b0, random_sequence[1:0]}; 24 | 4'h2 : random = {7'b0, random_sequence[2:0]}; 25 | 4'h3 : random = {6'b0, random_sequence[3:0]}; 26 | 4'h4 : random = {5'b0, random_sequence[4:0]}; 27 | 4'h5 : random = {4'b0, random_sequence[5:0]}; 28 | 4'h6 : random = {3'b0, random_sequence[6:0]}; 29 | 4'h7 : random = {2'b0, random_sequence[7:0]}; 30 | 4'h8 : random = {1'b0, random_sequence[8:0]}; 31 | 4'h9 : random = { random_sequence[9:0]}; 32 | default : random = { random_sequence[9:0]}; 33 | endcase 34 | 35 | always @ (posedge clock) 36 | if (reset) 37 | slot_time_counter <= 0; 38 | else if(init) 39 | slot_time_counter <= 0; 40 | else if(!trigger) 41 | slot_time_counter <= slot_time_counter + 1; 42 | 43 | always @ (posedge clock) 44 | if (reset) 45 | random_counter <= 0; 46 | else if (init) 47 | random_counter <= random; 48 | else if (random_counter != 0 && slot_time_counter == 255) 49 | random_counter <= random_counter - 1; 50 | 51 | always @ (posedge clock) 52 | if (reset) 53 | trigger <= 1; 54 | else if (init) 55 | trigger <= 0; 56 | else if (random_counter == 0) 57 | trigger <= 1; 58 | 59 | endmodule 60 | 61 | 62 | -------------------------------------------------------------------------------- /rgmii.v: -------------------------------------------------------------------------------- 1 | module rgmii 2 | ( 3 | input wire reset, 4 | input wire generated_clk, 5 | 6 | // PHY Interface 7 | output wire [3:0] phy_txd_rising, 8 | output wire [3:0] phy_txd_falling, 9 | output wire phy_tx_ctl_rising, 10 | output wire phy_tx_ctl_falling, 11 | output wire phy_gtx_clk, 12 | input wire [3:0] phy_rxd_rising, 13 | input wire [3:0] phy_rxd_falling, 14 | input wire phy_rx_ctl_rising, 15 | input wire phy_rx_ctl_falling, 16 | input wire phy_rx_clk, 17 | 18 | // MAC Interface 19 | input wire mac_tx_er, 20 | input wire [7:0] mac_txd, 21 | input wire mac_tx_en, 22 | output wire mac_tx_clk, 23 | output wire mac_col, 24 | output wire [7:0] mac_rxd, 25 | output wire mac_rx_er, 26 | output wire mac_rx_clk, 27 | output wire mac_crs, 28 | output wire mac_rx_dv 29 | ); 30 | 31 | assign phy_txd_rising = mac_txd[3:0]; 32 | assign phy_txd_falling = mac_txd[7:4]; 33 | assign phy_tx_ctl_rising = mac_tx_en; 34 | assign phy_tx_ctl_falling = mac_tx_en ^ mac_tx_er; 35 | assign phy_gtx_clk = generated_clk; 36 | assign mac_col = (mac_crs & mac_tx_en) | (mac_rx_dv & mac_tx_en); 37 | assign mac_rxd [3:0] = phy_rxd_rising; 38 | assign mac_rxd [7:4] = phy_rxd_falling; 39 | assign mac_rx_er = phy_rx_ctl_falling ^ phy_rx_ctl_rising; 40 | assign mac_rx_clk = phy_rx_clk; 41 | assign mac_crs = mac_rx_dv | ( mac_rx_er && mac_rxd == 8'hFF ) | ( mac_rx_er && mac_rxd == 8'h0E ) | ( mac_rx_er && mac_rxd == 8'h0F ) | ( mac_rx_er && mac_rxd == 8'h1F ); 42 | assign mac_rx_dv = phy_rx_ctl_rising; 43 | assign mac_tx_clk = generated_clk; 44 | 45 | endmodule 46 | -------------------------------------------------------------------------------- /rgmii.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/rgmii.xlsx -------------------------------------------------------------------------------- /rmii.v: -------------------------------------------------------------------------------- 1 | module rmii 2 | ( 3 | input wire reset, 4 | 5 | // PHY Interface 6 | input wire phy_ref_clk, 7 | output reg [1:0] phy_txd, 8 | output wire phy_tx_en, 9 | input wire [1:0] phy_rxd, 10 | input wire phy_rx_er, 11 | input wire phy_crs_dv, 12 | 13 | // MAC Interface 14 | input wire mac_tx_er, 15 | input wire [7:0] mac_txd, 16 | input wire mac_tx_en, 17 | output wire mac_tx_clk, 18 | output wire mac_col, 19 | output reg [7:0] mac_rxd, 20 | output wire mac_rx_er, 21 | output wire mac_rx_clk, 22 | output wire mac_crs, 23 | output wire mac_rx_dv 24 | ); 25 | reg [1:0] tx_index; 26 | reg [1:0] rx_index; 27 | 28 | assign phy_tx_er = mac_tx_er; 29 | assign phy_tx_en = mac_tx_en; 30 | assign mac_col = phy_crs_dv & mac_tx_en; 31 | assign mac_rx_er = phy_rx_er; 32 | assign mac_crs = phy_crs_dv; 33 | assign mac_rx_dv = phy_crs_dv; 34 | 35 | clock_divider #(.DIVIDER(4)) clk_div 36 | ( 37 | .reset(reset), 38 | .clock_in(phy_ref_clk), 39 | .clock_out(mac_tx_clk) 40 | ); 41 | 42 | assign mac_rx_clk = mac_tx_clk; 43 | 44 | always @(posedge phy_ref_clk) 45 | begin 46 | if (reset) 47 | begin 48 | tx_index <= 0; 49 | end 50 | else if (mac_tx_en && tx_index < 3) 51 | begin 52 | tx_index <= tx_index + 1; 53 | end 54 | else 55 | begin 56 | tx_index <= 0; 57 | end 58 | 59 | end 60 | 61 | always @(posedge phy_ref_clk) 62 | begin 63 | if (reset) 64 | begin 65 | phy_txd <= 0; 66 | end 67 | else 68 | begin 69 | phy_txd <= mac_txd[tx_index*2+:2]; 70 | end 71 | end 72 | 73 | always @(posedge phy_ref_clk) 74 | begin 75 | if (reset) 76 | begin 77 | rx_index <= 0; 78 | end 79 | else if (phy_crs_dv && rx_index < 3) 80 | begin 81 | rx_index <= rx_index + 1; 82 | end 83 | else 84 | begin 85 | rx_index <= 0; 86 | end 87 | 88 | end 89 | 90 | always @(posedge phy_ref_clk) 91 | begin 92 | if (reset) 93 | begin 94 | mac_rxd <= 0; 95 | end 96 | else 97 | begin 98 | mac_rxd[rx_index*2+:2] <= phy_rxd; 99 | end 100 | end 101 | 102 | endmodule 103 | -------------------------------------------------------------------------------- /rmii.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/rmii.xlsx -------------------------------------------------------------------------------- /rx.dot: -------------------------------------------------------------------------------- 1 | digraph { 2 | 3 | node [shape=circle,fontsize=8,fixedsize=true,width=0.9]; 4 | edge [fontsize=8]; 5 | rankdir=LR; 6 | 7 | "low-priority" [shape="doublecircle" color="orange"]; 8 | "high-priority" [shape="doublecircle" color="orange"]; 9 | 10 | "s1" -> "low-priority"; 11 | "s2" -> "low-priority"; 12 | "s3" -> "low-priority"; 13 | 14 | "low-priority" -> "s4"; 15 | "low-priority" -> "s5"; 16 | "low-priority" -> "high-priority" [label="wait-time exceeded"]; 17 | 18 | "high-priority" -> "s4"; 19 | "high-priority" -> "s5"; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /rx.v: -------------------------------------------------------------------------------- 1 | module rx #( 2 | parameter STATE_IDLE = 3'h0, 3 | parameter STATE_PREAMBLE = 3'h1, 4 | parameter STATE_DATA = 3'h2, 5 | parameter STATE_OK = 3'h3, 6 | parameter STATE_DROP = 3'h4, 7 | parameter STATE_ERROR = 3'h5, 8 | parameter STATE_EXTEND = 3'h6 9 | )( 10 | input reset, 11 | input clock, 12 | 13 | input mode_is_gigabit, 14 | 15 | input rx_data_valid, 16 | input [7:0] rx_data, 17 | input rx_error, 18 | 19 | output reg [7:0] data_out, 20 | output reg data_out_enable, 21 | output reg data_out_start, 22 | output reg data_out_end, 23 | input wire fifo_full, 24 | output reg error 25 | ); 26 | 27 | localparam CRC_RESIDUE = 32'hC704DD7B; 28 | localparam CRC_POLYNOMIAL = 32'h04C11DB7; 29 | localparam CRC_SEED = 32'hFFFFFFFF; 30 | localparam MAX_SIZE = 1518; 31 | localparam MIN_SIZE = 64; 32 | localparam SLOT_TIME = 64; 33 | 34 | reg extending; 35 | reg [2:0] state; 36 | reg [2:0] next_state; 37 | reg [15:0] frame_length_counter; 38 | reg [15:0] data_counter; 39 | reg too_long; 40 | reg too_short; 41 | 42 | reg crc_init; 43 | reg data_enable; 44 | wire [31:0] crc_out; 45 | 46 | reg [39:0] data; 47 | 48 | always @(posedge clock) 49 | begin 50 | if (!rx_data_valid && rx_error && rx_data == 8'h0F && mode_is_gigabit) 51 | extending = 1; 52 | else 53 | extending = 0; 54 | end 55 | 56 | // RX State Machine 57 | always @ (posedge clock) 58 | if (reset) 59 | state <= STATE_IDLE; 60 | else 61 | state <= next_state; 62 | 63 | always @ (*) 64 | case (state) 65 | STATE_IDLE: 66 | if (rx_data_valid && rx_data == 8'h55) 67 | next_state = STATE_PREAMBLE; 68 | else 69 | next_state = STATE_IDLE; 70 | STATE_PREAMBLE: 71 | if (!rx_data_valid) 72 | next_state = STATE_ERROR; 73 | else if (rx_error) 74 | next_state = STATE_DROP; 75 | else if (rx_data == 8'hd5) 76 | next_state = STATE_DATA; 77 | else if (rx_data == 8'h55) 78 | next_state = STATE_PREAMBLE; 79 | else 80 | next_state = STATE_DROP; 81 | STATE_DATA: 82 | if (!rx_data_valid && !too_short && !too_long && crc_out == CRC_RESIDUE && frame_length_counter >= SLOT_TIME && !extending) 83 | next_state = STATE_OK; 84 | else if (!rx_data_valid && !too_short && !too_long && crc_out == CRC_RESIDUE && extending) 85 | next_state = STATE_EXTEND; 86 | else if ((!rx_data_valid && (too_short || too_long)) || (!rx_data_valid && crc_out != CRC_RESIDUE)) 87 | next_state = STATE_ERROR; 88 | else if (fifo_full) 89 | next_state = STATE_DROP; 90 | else if (rx_error || too_long) 91 | next_state = STATE_DROP; 92 | else 93 | next_state = STATE_DATA; 94 | STATE_EXTEND: 95 | if (extending) 96 | next_state = STATE_EXTEND; 97 | else if (frame_length_counter >= SLOT_TIME) 98 | next_state = STATE_OK; 99 | else 100 | next_state = STATE_ERROR; 101 | STATE_DROP: 102 | if (!rx_data_valid) 103 | next_state = STATE_ERROR; 104 | else 105 | next_state = STATE_DROP; 106 | STATE_OK: 107 | next_state = STATE_IDLE; 108 | STATE_ERROR: 109 | next_state = STATE_IDLE; 110 | default: 111 | next_state = STATE_IDLE; 112 | endcase 113 | 114 | always @(posedge clock) 115 | data_out <= data[39-:8]; 116 | 117 | always @(posedge clock) 118 | begin 119 | if (reset) 120 | begin 121 | data <= 32'h00000000; 122 | end 123 | else if (state == STATE_IDLE) 124 | begin 125 | data <= 32'h00000000; 126 | end 127 | else 128 | begin 129 | data[39-:8] <= data[31-:8]; 130 | data[31-:8] <= data[23-:8]; 131 | data[23-:8] <= data[15-:8]; 132 | data[15-:8] <= data[7-:8]; 133 | data[7-:8] <= rx_data; 134 | end 135 | end 136 | 137 | always @ (posedge clock) 138 | if (reset) 139 | data_counter <= 0; 140 | else if (state == STATE_DATA) 141 | data_counter = data_counter + 1; 142 | else 143 | data_counter = 0; 144 | 145 | always @ (*) 146 | if (data_counter > 5 && (state == STATE_DATA || state == STATE_OK || state == STATE_ERROR)) 147 | data_out_enable = 1; 148 | else 149 | data_out_enable = 0; 150 | 151 | always @(*) 152 | if (data_counter == 6) 153 | data_out_start = 1; 154 | else 155 | data_out_start = 0; 156 | 157 | always @(*) 158 | if (state == STATE_OK || state == STATE_ERROR) 159 | data_out_end = 1; 160 | else 161 | data_out_end = 0; 162 | 163 | always @(*) 164 | if (state == STATE_ERROR) 165 | error = 1; 166 | else 167 | error = 0; 168 | 169 | // CRC Interface 170 | always @(*) 171 | if (state == STATE_DATA) 172 | data_enable = 1; 173 | else 174 | data_enable = 0; 175 | 176 | always @(*) 177 | if (state == STATE_PREAMBLE && next_state == STATE_DATA) 178 | crc_init = 1; 179 | else 180 | crc_init = 0; 181 | 182 | always @ (posedge clock) 183 | if (reset) 184 | frame_length_counter <= 0; 185 | else if (state == STATE_DATA || state == STATE_EXTEND) 186 | frame_length_counter = frame_length_counter + 1; 187 | else 188 | frame_length_counter = 0; 189 | 190 | always @ (*) 191 | if (frame_length_counter < MIN_SIZE) 192 | too_short = 1; 193 | else 194 | too_short = 0; 195 | 196 | always @ (*) 197 | if (frame_length_counter > MAX_SIZE) 198 | too_long = 1; 199 | else 200 | too_long = 0; 201 | 202 | // CRC 203 | crc #( .POLYNOMIAL(CRC_POLYNOMIAL), 204 | .DATA_WIDTH(8), 205 | .CRC_WIDTH(32), 206 | .SEED(CRC_SEED)) 207 | U_crc( 208 | .reset(reset), 209 | .clock(clock), 210 | .init(crc_init), 211 | .data(rx_data), 212 | .data_enable(data_enable), 213 | .crc_out(crc_out) 214 | ); 215 | 216 | endmodule 217 | -------------------------------------------------------------------------------- /rx.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/rx.xlsx -------------------------------------------------------------------------------- /sme.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/sme.xlsx -------------------------------------------------------------------------------- /station_management.v: -------------------------------------------------------------------------------- 1 | module station_management 2 | #( 3 | parameter STATE_IDLE = 4'd0, 4 | parameter STATE_PREAMBLE = 4'd1, 5 | parameter STATE_START_OF_FRAME = 4'd2, 6 | parameter STATE_OPCODE = 4'd3, 7 | parameter STATE_PHY_ADDRESS = 4'd4, 8 | parameter STATE_REG_ADDRESS = 4'd5, 9 | parameter STATE_TURNAROUND = 4'd6, 10 | parameter STATE_DATA = 4'd7, 11 | parameter STATE_OK = 4'd8, 12 | parameter READ = 1'b0, 13 | parameter WRITE = 1'b1 14 | )( 15 | input wire reset, 16 | input wire clock, 17 | 18 | output wire mdc, 19 | inout wire mdio, 20 | 21 | input wire mode, 22 | 23 | input wire begin_transaction, 24 | input wire [4:0] phy_address, 25 | input wire [4:0] reg_address, 26 | input wire [15:0] data_in, 27 | output reg [15:0] data_out 28 | ); 29 | 30 | localparam start_of_frame = 2'b01; 31 | localparam turnaround = 2'b10; 32 | 33 | reg [3:0] state; 34 | reg [3:0] next_state; 35 | 36 | reg mdio_data; 37 | reg writing; 38 | 39 | reg [1:0] opcode; 40 | reg [15:0] data_read; 41 | 42 | reg [4:0] preamble_counter; 43 | reg start_of_frame_counter; 44 | reg opcode_counter; 45 | reg [2:0] phy_address_counter; 46 | reg [2:0] reg_address_counter; 47 | reg turnaround_counter; 48 | reg [3:0] data_counter; 49 | 50 | // MDC 51 | assign mdc = clock; 52 | 53 | // MDIO - if reading present high impedance. 54 | assign mdio = (writing) ? mdio_data : 1'bz; 55 | 56 | // State Update 57 | always @(posedge mdc) 58 | if (reset) 59 | state <= STATE_IDLE; 60 | else 61 | state <= next_state; 62 | 63 | // State Machine 64 | always @(*) 65 | case(state) 66 | STATE_IDLE: 67 | if ( begin_transaction ) 68 | next_state <= STATE_PREAMBLE; 69 | else 70 | next_state <= STATE_IDLE; 71 | STATE_PREAMBLE: 72 | if (preamble_counter == 5'b0) 73 | next_state <= STATE_START_OF_FRAME; 74 | else 75 | next_state <= STATE_PREAMBLE; 76 | STATE_START_OF_FRAME: 77 | if (start_of_frame_counter == 0) 78 | next_state <= STATE_OPCODE; 79 | else 80 | next_state <= STATE_START_OF_FRAME; 81 | STATE_OPCODE: 82 | if (opcode_counter == 0) 83 | next_state <= STATE_PHY_ADDRESS; 84 | else 85 | next_state <= STATE_OPCODE; 86 | STATE_PHY_ADDRESS: 87 | if (phy_address_counter == 0) 88 | next_state <= STATE_REG_ADDRESS; 89 | else 90 | next_state <= STATE_PHY_ADDRESS; 91 | STATE_REG_ADDRESS: 92 | if (reg_address_counter == 0) 93 | next_state <= STATE_TURNAROUND; 94 | else 95 | next_state <= STATE_REG_ADDRESS; 96 | STATE_TURNAROUND: 97 | if (turnaround_counter == 0) 98 | next_state <= STATE_DATA; 99 | else 100 | next_state <= STATE_TURNAROUND; 101 | STATE_DATA: 102 | if (data_counter == 0) 103 | next_state <= STATE_OK; 104 | else 105 | next_state <= STATE_DATA; 106 | STATE_OK: 107 | next_state <= STATE_IDLE; 108 | default: 109 | next_state <= STATE_IDLE; 110 | endcase 111 | 112 | // State Outputs 113 | always @(*) 114 | case(state) 115 | STATE_IDLE: 116 | mdio_data <= 0; 117 | STATE_PREAMBLE: 118 | mdio_data <= 1; 119 | STATE_START_OF_FRAME: 120 | mdio_data <= start_of_frame[start_of_frame_counter-:1]; 121 | STATE_OPCODE: 122 | mdio_data <= opcode[opcode_counter-:1]; 123 | STATE_PHY_ADDRESS: 124 | mdio_data <= phy_address[phy_address_counter-:1]; 125 | STATE_REG_ADDRESS: 126 | mdio_data <= reg_address[reg_address_counter-:1]; 127 | STATE_TURNAROUND: 128 | mdio_data <= turnaround[turnaround_counter-:1]; 129 | STATE_DATA: 130 | mdio_data <= data_in[data_counter-:1]; 131 | default: 132 | mdio_data <= 0; 133 | endcase 134 | 135 | always @(posedge mdc) 136 | if (state == STATE_DATA && mode == READ) 137 | data_read[data_counter-:1] <= mdio; 138 | 139 | always @(*) 140 | if (state == STATE_OK) 141 | begin 142 | data_out <= data_read; 143 | end 144 | 145 | always @(*) 146 | if ((state == STATE_TURNAROUND && mode == READ) || 147 | (state == STATE_DATA && mode == READ)) 148 | writing <= 0; 149 | else 150 | writing <= 1; 151 | 152 | always @(*) 153 | if (mode == READ) 154 | opcode <= 2'b10; 155 | else 156 | opcode <= 2'b01; 157 | 158 | // Counters 159 | 160 | // Preamble 161 | always @(posedge mdc) 162 | if (reset) 163 | preamble_counter <= 5'd31; 164 | else if (state == STATE_PREAMBLE) 165 | preamble_counter <= preamble_counter - 1; 166 | else 167 | preamble_counter <= 5'd31; 168 | 169 | // Start of Frame 170 | always @(posedge mdc) 171 | if (reset) 172 | start_of_frame_counter <= 1'b1; 173 | else if (state == STATE_START_OF_FRAME) 174 | start_of_frame_counter <= 1'b0; 175 | else 176 | start_of_frame_counter <= 1'b1; 177 | 178 | // Opcode 179 | always @(posedge mdc) 180 | if (reset) 181 | opcode_counter <= 1'b1; 182 | else if (state == STATE_OPCODE) 183 | opcode_counter <= 1'b0; 184 | else 185 | opcode_counter <= 1'b1; 186 | 187 | // PHY Address 188 | always @(posedge mdc) 189 | if (reset) 190 | phy_address_counter <= 3'd4; 191 | else if (state == STATE_PHY_ADDRESS) 192 | phy_address_counter <= phy_address_counter - 1; 193 | else 194 | phy_address_counter <= 3'd4; 195 | 196 | // Register Address 197 | always @(posedge mdc) 198 | if (reset) 199 | reg_address_counter <= 3'd4; 200 | else if (state == STATE_REG_ADDRESS) 201 | reg_address_counter <= reg_address_counter - 1; 202 | else 203 | reg_address_counter <= 3'd4; 204 | 205 | // Turnaround 206 | always @(posedge mdc) 207 | if (reset) 208 | turnaround_counter <= 1'b1; 209 | else if (state == STATE_TURNAROUND) 210 | turnaround_counter <= 1'b0; 211 | else 212 | turnaround_counter <= 1'b1; 213 | 214 | // Data 215 | always @(posedge mdc) 216 | if (reset) 217 | data_counter <= 4'd15; 218 | else if (state == STATE_DATA) 219 | data_counter <= data_counter - 1; 220 | else 221 | data_counter <= 4'd15; 222 | 223 | endmodule 224 | -------------------------------------------------------------------------------- /station_management_mdo_mdi.v: -------------------------------------------------------------------------------- 1 | 2 | module station_management 3 | #( 4 | parameter STATE_IDLE = 4'd0, 5 | parameter STATE_PREAMBLE = 4'd1, 6 | parameter STATE_START_OF_FRAME = 4'd2, 7 | parameter STATE_OPCODE = 4'd3, 8 | parameter STATE_PHY_ADDRESS = 4'd4, 9 | parameter STATE_REG_ADDRESS = 4'd5, 10 | parameter STATE_TURNAROUND = 4'd6, 11 | parameter STATE_DATA = 4'd7, 12 | parameter STATE_OK = 4'd8, 13 | parameter READ = 1'b0, 14 | parameter WRITE = 1'b1 15 | )( 16 | input wire reset, 17 | input wire clock, 18 | 19 | output wire mdc, 20 | input wire mdi, 21 | output reg mdo, 22 | 23 | input wire mode, 24 | 25 | input wire begin_transaction, 26 | input wire [4:0] phy_address, 27 | input wire [4:0] reg_address, 28 | input wire [15:0] data_in, 29 | output reg [15:0] data_out 30 | ); 31 | 32 | localparam start_of_frame = 2'b01; 33 | localparam turnaround = 2'b10; 34 | 35 | reg [3:0] state; 36 | reg [3:0] next_state; 37 | 38 | reg [1:0] opcode; 39 | reg [15:0] data_read; 40 | 41 | reg [4:0] preamble_counter; 42 | reg start_of_frame_counter; 43 | reg opcode_counter; 44 | reg [2:0] phy_address_counter; 45 | reg [2:0] reg_address_counter; 46 | reg turnaround_counter; 47 | reg [3:0] data_counter; 48 | 49 | // MDC 50 | assign mdc = clock; 51 | 52 | // State Update 53 | always @(posedge mdc) 54 | if (reset) 55 | state <= STATE_IDLE; 56 | else 57 | state <= next_state; 58 | 59 | // State Machine 60 | always @(*) 61 | case(state) 62 | STATE_IDLE: 63 | if ( begin_transaction ) 64 | next_state <= STATE_PREAMBLE; 65 | else 66 | next_state <= STATE_IDLE; 67 | STATE_PREAMBLE: 68 | if (preamble_counter == 5'b0) 69 | next_state <= STATE_START_OF_FRAME; 70 | else 71 | next_state <= STATE_PREAMBLE; 72 | STATE_START_OF_FRAME: 73 | if (start_of_frame_counter == 0) 74 | next_state <= STATE_OPCODE; 75 | else 76 | next_state <= STATE_START_OF_FRAME; 77 | STATE_OPCODE: 78 | if (opcode_counter == 0) 79 | next_state <= STATE_PHY_ADDRESS; 80 | else 81 | next_state <= STATE_OPCODE; 82 | STATE_PHY_ADDRESS: 83 | if (phy_address_counter == 0) 84 | next_state <= STATE_REG_ADDRESS; 85 | else 86 | next_state <= STATE_PHY_ADDRESS; 87 | STATE_REG_ADDRESS: 88 | if (reg_address_counter == 0) 89 | next_state <= STATE_TURNAROUND; 90 | else 91 | next_state <= STATE_REG_ADDRESS; 92 | STATE_TURNAROUND: 93 | if (turnaround_counter == 0) 94 | next_state <= STATE_DATA; 95 | else 96 | next_state <= STATE_TURNAROUND; 97 | STATE_DATA: 98 | if (data_counter == 0) 99 | next_state <= STATE_OK; 100 | else 101 | next_state <= STATE_DATA; 102 | STATE_OK: 103 | next_state <= STATE_IDLE; 104 | default: 105 | next_state <= STATE_IDLE; 106 | endcase 107 | 108 | // State Outputs 109 | always @(*) 110 | case(state) 111 | STATE_IDLE: 112 | mdo <= 0; 113 | STATE_PREAMBLE: 114 | mdo <= 1; 115 | STATE_START_OF_FRAME: 116 | mdo <= start_of_frame[start_of_frame_counter-:1]; 117 | STATE_OPCODE: 118 | mdo <= opcode[opcode_counter-:1]; 119 | STATE_PHY_ADDRESS: 120 | mdo <= phy_address[phy_address_counter-:1]; 121 | STATE_REG_ADDRESS: 122 | mdo <= reg_address[reg_address_counter-:1]; 123 | STATE_TURNAROUND: 124 | mdo <= (mode == READ) ? 1'bz : turnaround[turnaround_counter-:1]; 125 | STATE_DATA: 126 | mdo <= (mode == READ) ? 1'bz : data_in[data_counter-:1]; 127 | default: 128 | mdo <= 0; 129 | endcase 130 | 131 | always @(posedge mdc) 132 | if (reset) 133 | data_read <= 0; 134 | else if (state == STATE_DATA && mode == READ) 135 | begin 136 | $display ("MDI: %b", mdi); 137 | data_read[data_counter-:1] <= mdi; 138 | end 139 | else 140 | data_read <= 0; 141 | 142 | always @(*) 143 | if (reset) 144 | data_out <= 0; 145 | else if (state == STATE_OK) 146 | data_out <= data_read; 147 | else 148 | data_out <= data_out; 149 | 150 | always @(*) 151 | if (mode == READ) 152 | opcode <= 2'b10; 153 | else 154 | opcode <= 2'b01; 155 | 156 | // Counters 157 | 158 | // Preamble 159 | always @(posedge mdc) 160 | if (reset) 161 | preamble_counter <= 5'd31; 162 | else if (state == STATE_PREAMBLE) 163 | preamble_counter <= preamble_counter - 1; 164 | else 165 | preamble_counter <= 5'd31; 166 | 167 | // Start of Frame 168 | always @(posedge mdc) 169 | if (reset) 170 | start_of_frame_counter <= 1'b1; 171 | else if (state == STATE_START_OF_FRAME) 172 | start_of_frame_counter <= 1'b0; 173 | else 174 | start_of_frame_counter <= 1'b1; 175 | 176 | // Opcode 177 | always @(posedge mdc) 178 | if (reset) 179 | opcode_counter <= 1'b1; 180 | else if (state == STATE_OPCODE) 181 | opcode_counter <= 1'b0; 182 | else 183 | opcode_counter <= 1'b1; 184 | 185 | // PHY Address 186 | always @(posedge mdc) 187 | if (reset) 188 | phy_address_counter <= 3'd4; 189 | else if (state == STATE_PHY_ADDRESS) 190 | phy_address_counter <= phy_address_counter - 1; 191 | else 192 | phy_address_counter <= 3'd4; 193 | 194 | // Register Address 195 | always @(posedge mdc) 196 | if (reset) 197 | reg_address_counter <= 3'd4; 198 | else if (state == STATE_REG_ADDRESS) 199 | reg_address_counter <= reg_address_counter - 1; 200 | else 201 | reg_address_counter <= 3'd4; 202 | 203 | // Turnaround 204 | always @(posedge mdc) 205 | if (reset) 206 | turnaround_counter <= 1'b1; 207 | else if (state == STATE_TURNAROUND) 208 | turnaround_counter <= 1'b0; 209 | else 210 | turnaround_counter <= 1'b1; 211 | 212 | // Data 213 | always @(posedge mdc) 214 | if (reset) 215 | data_counter <= 4'd15; 216 | else if (state == STATE_DATA) 217 | data_counter <= data_counter - 1; 218 | else 219 | data_counter <= 4'd15; 220 | 221 | endmodule 222 | -------------------------------------------------------------------------------- /station_management_mdo_mdi_tb.v: -------------------------------------------------------------------------------- 1 | 2 | module station_management_tb (); 3 | 4 | reg reset; 5 | reg clock; 6 | 7 | wire mdc; 8 | reg mdi; 9 | wire mdo; 10 | 11 | reg mode; 12 | 13 | reg begin_transaction; 14 | reg [4:0] phy_address; 15 | reg [4:0] reg_address; 16 | reg [15:0] data_in; 17 | wire [15:0] data_out; 18 | 19 | station_management U_station_management 20 | ( 21 | .reset(reset), 22 | .clock(clock), 23 | 24 | .mdc(mdc), 25 | .mdi(mdi), 26 | .mdo(mdo), 27 | 28 | .mode(mode), 29 | 30 | .begin_transaction(begin_transaction), 31 | .phy_address(phy_address), 32 | .reg_address(reg_address), 33 | .data_in(data_in), 34 | .data_out(data_out) 35 | ); 36 | 37 | integer i; 38 | 39 | initial 40 | begin 41 | $dumpfile("test.vcd"); 42 | $dumpvars(0,station_management_tb); 43 | end 44 | 45 | initial 46 | begin 47 | mdi = 0; 48 | reset = 1; 49 | clock = 1; 50 | mode = 0; 51 | begin_transaction = 0; 52 | phy_address = 5'b00001; 53 | reg_address = 5'b00010; 54 | data_in = 16'hFEDC; 55 | 56 | #20 reset = 0; 57 | 58 | #20 begin_transaction = 1; 59 | #10 begin_transaction = 0; 60 | 61 | #490 62 | 63 | for (i=0; i<16; i = i + 1) 64 | begin 65 | reading_bit((i%2)? 1'b1 : 1'b0); 66 | end 67 | mdi = 0; 68 | 69 | #50 70 | 71 | $finish(); 72 | end 73 | 74 | always 75 | #5 clock = ~clock; 76 | 77 | task reading_bit; 78 | input bit; 79 | begin 80 | mdi = bit; 81 | @(posedge mdc); 82 | end 83 | endtask 84 | 85 | task writing_bit; 86 | begin 87 | @(posedge mdc); 88 | end 89 | endtask 90 | endmodule 91 | -------------------------------------------------------------------------------- /station_management_tb.v: -------------------------------------------------------------------------------- 1 | module station_management_tb (); 2 | 3 | reg reset; 4 | reg clock; 5 | 6 | wire mdc; 7 | reg mdi; 8 | wire mdo; 9 | 10 | reg mode; 11 | 12 | reg begin_transaction; 13 | reg [4:0] phy_address; 14 | reg [4:0] reg_address; 15 | reg [15:0] data_in; 16 | wire [15:0] data_out; 17 | 18 | station_management U_station_management 19 | ( 20 | .reset(reset), 21 | .clock(clock), 22 | 23 | .mdc(mdc), 24 | .mdi(mdi), 25 | .mdo(mdo), 26 | 27 | .mode(mode), 28 | 29 | .begin_transaction(begin_transaction), 30 | .phy_address(phy_address), 31 | .reg_address(reg_address), 32 | .data_in(data_in), 33 | .data_out(data_out) 34 | ); 35 | 36 | integer i; 37 | 38 | initial 39 | begin 40 | $dumpfile("test.vcd"); 41 | $dumpvars(0,station_management_tb); 42 | end 43 | 44 | initial 45 | begin 46 | mdi = 0; 47 | reset = 1; 48 | clock = 1; 49 | mode = 0; 50 | begin_transaction = 0; 51 | phy_address = 5'b00001; 52 | reg_address = 5'b00010; 53 | data_in = 16'hFEDC; 54 | 55 | #20 reset = 0; 56 | 57 | #20 begin_transaction = 1; 58 | #10 begin_transaction = 0; 59 | 60 | #490 61 | 62 | for (i=0; i<16; i = i + 1) 63 | begin 64 | reading_bit((i%2)? 1'b1 : 1'b0); 65 | end 66 | mdi = 0; 67 | 68 | #50 69 | 70 | $finish(); 71 | end 72 | 73 | always 74 | #5 clock = ~clock; 75 | 76 | task reading_bit; 77 | input bit; 78 | begin 79 | mdi = bit; 80 | @(posedge mdc); 81 | end 82 | endtask 83 | 84 | task writing_bit; 85 | begin 86 | @(posedge mdc); 87 | end 88 | endtask 89 | endmodule 90 | -------------------------------------------------------------------------------- /test.vcd: -------------------------------------------------------------------------------- 1 | $date 2 | Mon May 8 15:40:31 2017 3 | $end 4 | $version 5 | Icarus Verilog 6 | $end 7 | $timescale 8 | 1s 9 | $end 10 | $scope module station_management_tb $end 11 | $var wire 1 ! mdo $end 12 | $var wire 1 " mdc $end 13 | $var wire 16 # data_out [15:0] $end 14 | $var reg 1 $ begin_transaction $end 15 | $var reg 1 % clock $end 16 | $var reg 16 & data_in [15:0] $end 17 | $var reg 1 ' mdi $end 18 | $var reg 1 ( mode $end 19 | $var reg 5 ) phy_address [4:0] $end 20 | $var reg 5 * reg_address [4:0] $end 21 | $var reg 1 + reset $end 22 | $var integer 32 , i [31:0] $end 23 | $scope module U_station_management $end 24 | $var wire 1 $ begin_transaction $end 25 | $var wire 1 % clock $end 26 | $var wire 16 - data_in [15:0] $end 27 | $var wire 1 " mdc $end 28 | $var wire 1 ' mdi $end 29 | $var wire 1 ( mode $end 30 | $var wire 5 . phy_address [4:0] $end 31 | $var wire 5 / reg_address [4:0] $end 32 | $var wire 1 + reset $end 33 | $var reg 4 0 data_counter [3:0] $end 34 | $var reg 16 1 data_out [15:0] $end 35 | $var reg 16 2 data_read [15:0] $end 36 | $var reg 1 ! mdo $end 37 | $var reg 4 3 next_state [3:0] $end 38 | $var reg 2 4 opcode [1:0] $end 39 | $var reg 1 5 opcode_counter $end 40 | $var reg 3 6 phy_address_counter [2:0] $end 41 | $var reg 5 7 preamble_counter [4:0] $end 42 | $var reg 3 8 reg_address_counter [2:0] $end 43 | $var reg 1 9 start_of_frame_counter $end 44 | $var reg 4 : state [3:0] $end 45 | $var reg 1 ; turnaround_counter $end 46 | $upscope $end 47 | $scope task reading_bit $end 48 | $var reg 1 < bit $end 49 | $upscope $end 50 | $scope task writing_bit $end 51 | $upscope $end 52 | $upscope $end 53 | $enddefinitions $end 54 | #0 55 | $dumpvars 56 | x< 57 | 1; 58 | b0 : 59 | 19 60 | b100 8 61 | b11111 7 62 | b100 6 63 | 15 64 | b10 4 65 | b0 3 66 | b0 2 67 | b0 1 68 | b1111 0 69 | b10 / 70 | b1 . 71 | b1111111011011100 - 72 | bx , 73 | 1+ 74 | b10 * 75 | b1 ) 76 | 0( 77 | 0' 78 | b1111111011011100 & 79 | 1% 80 | 0$ 81 | b0 # 82 | 1" 83 | 0! 84 | $end 85 | #5 86 | 0" 87 | 0% 88 | #10 89 | 1" 90 | 1% 91 | #15 92 | 0" 93 | 0% 94 | #20 95 | 1" 96 | 1% 97 | 0+ 98 | #25 99 | 0" 100 | 0% 101 | #30 102 | 1" 103 | 1% 104 | #35 105 | 0" 106 | 0% 107 | #40 108 | b1 3 109 | 1" 110 | 1% 111 | 1$ 112 | #45 113 | 0" 114 | 0% 115 | #50 116 | 1! 117 | b1 : 118 | b1 3 119 | 1" 120 | 1% 121 | 0$ 122 | #55 123 | 0" 124 | 0% 125 | #60 126 | b11110 7 127 | 1" 128 | 1% 129 | #65 130 | 0" 131 | 0% 132 | #70 133 | b11101 7 134 | 1" 135 | 1% 136 | #75 137 | 0" 138 | 0% 139 | #80 140 | b11100 7 141 | 1" 142 | 1% 143 | #85 144 | 0" 145 | 0% 146 | #90 147 | b11011 7 148 | 1" 149 | 1% 150 | #95 151 | 0" 152 | 0% 153 | #100 154 | b11010 7 155 | 1" 156 | 1% 157 | #105 158 | 0" 159 | 0% 160 | #110 161 | b11001 7 162 | 1" 163 | 1% 164 | #115 165 | 0" 166 | 0% 167 | #120 168 | b11000 7 169 | 1" 170 | 1% 171 | #125 172 | 0" 173 | 0% 174 | #130 175 | b10111 7 176 | 1" 177 | 1% 178 | #135 179 | 0" 180 | 0% 181 | #140 182 | b10110 7 183 | 1" 184 | 1% 185 | #145 186 | 0" 187 | 0% 188 | #150 189 | b10101 7 190 | 1" 191 | 1% 192 | #155 193 | 0" 194 | 0% 195 | #160 196 | b10100 7 197 | 1" 198 | 1% 199 | #165 200 | 0" 201 | 0% 202 | #170 203 | b10011 7 204 | 1" 205 | 1% 206 | #175 207 | 0" 208 | 0% 209 | #180 210 | b10010 7 211 | 1" 212 | 1% 213 | #185 214 | 0" 215 | 0% 216 | #190 217 | b10001 7 218 | 1" 219 | 1% 220 | #195 221 | 0" 222 | 0% 223 | #200 224 | b10000 7 225 | 1" 226 | 1% 227 | #205 228 | 0" 229 | 0% 230 | #210 231 | b1111 7 232 | 1" 233 | 1% 234 | #215 235 | 0" 236 | 0% 237 | #220 238 | b1110 7 239 | 1" 240 | 1% 241 | #225 242 | 0" 243 | 0% 244 | #230 245 | b1101 7 246 | 1" 247 | 1% 248 | #235 249 | 0" 250 | 0% 251 | #240 252 | b1100 7 253 | 1" 254 | 1% 255 | #245 256 | 0" 257 | 0% 258 | #250 259 | b1011 7 260 | 1" 261 | 1% 262 | #255 263 | 0" 264 | 0% 265 | #260 266 | b1010 7 267 | 1" 268 | 1% 269 | #265 270 | 0" 271 | 0% 272 | #270 273 | b1001 7 274 | 1" 275 | 1% 276 | #275 277 | 0" 278 | 0% 279 | #280 280 | b1000 7 281 | 1" 282 | 1% 283 | #285 284 | 0" 285 | 0% 286 | #290 287 | b111 7 288 | 1" 289 | 1% 290 | #295 291 | 0" 292 | 0% 293 | #300 294 | b110 7 295 | 1" 296 | 1% 297 | #305 298 | 0" 299 | 0% 300 | #310 301 | b101 7 302 | 1" 303 | 1% 304 | #315 305 | 0" 306 | 0% 307 | #320 308 | b100 7 309 | 1" 310 | 1% 311 | #325 312 | 0" 313 | 0% 314 | #330 315 | b11 7 316 | 1" 317 | 1% 318 | #335 319 | 0" 320 | 0% 321 | #340 322 | b10 7 323 | 1" 324 | 1% 325 | #345 326 | 0" 327 | 0% 328 | #350 329 | b1 7 330 | 1" 331 | 1% 332 | #355 333 | 0" 334 | 0% 335 | #360 336 | b10 3 337 | b0 7 338 | 1" 339 | 1% 340 | #365 341 | 0" 342 | 0% 343 | #370 344 | 0! 345 | b11111 7 346 | b10 : 347 | 1" 348 | 1% 349 | #375 350 | 0" 351 | 0% 352 | #380 353 | 1! 354 | b11 3 355 | 09 356 | 1" 357 | 1% 358 | #385 359 | 0" 360 | 0% 361 | #390 362 | b11 : 363 | 1" 364 | 1% 365 | #395 366 | 0" 367 | 0% 368 | #400 369 | 0! 370 | b100 3 371 | 19 372 | 05 373 | 1" 374 | 1% 375 | #405 376 | 0" 377 | 0% 378 | #410 379 | b100 : 380 | 1" 381 | 1% 382 | #415 383 | 0" 384 | 0% 385 | #420 386 | 15 387 | b11 6 388 | 1" 389 | 1% 390 | #425 391 | 0" 392 | 0% 393 | #430 394 | b10 6 395 | 1" 396 | 1% 397 | #435 398 | 0" 399 | 0% 400 | #440 401 | b1 6 402 | 1" 403 | 1% 404 | #445 405 | 0" 406 | 0% 407 | #450 408 | 1! 409 | b101 3 410 | b0 6 411 | 1" 412 | 1% 413 | #455 414 | 0" 415 | 0% 416 | #460 417 | 0! 418 | b101 : 419 | b111 6 420 | 1" 421 | 1% 422 | #465 423 | 0" 424 | 0% 425 | #470 426 | b11 8 427 | b100 6 428 | 1" 429 | 1% 430 | #475 431 | 0" 432 | 0% 433 | #480 434 | b10 8 435 | 1" 436 | 1% 437 | #485 438 | 0" 439 | 0% 440 | #490 441 | 1! 442 | b1 8 443 | 1" 444 | 1% 445 | #495 446 | 0" 447 | 0% 448 | #500 449 | 0! 450 | b110 3 451 | b0 8 452 | 1" 453 | 1% 454 | #505 455 | 0" 456 | 0% 457 | #510 458 | z! 459 | b111 8 460 | b110 : 461 | 1" 462 | 1% 463 | #515 464 | 0" 465 | 0% 466 | #520 467 | b111 3 468 | b100 8 469 | 0; 470 | 1" 471 | 1% 472 | #525 473 | 0" 474 | 0% 475 | #530 476 | b111 : 477 | 1" 478 | 1% 479 | #535 480 | 0" 481 | 0% 482 | #540 483 | 1; 484 | b1110 0 485 | 1' 486 | 1" 487 | 1% 488 | 1< 489 | b1 , 490 | #545 491 | 0" 492 | 0% 493 | #550 494 | b1101 0 495 | b100000000000000 2 496 | 0' 497 | 0< 498 | b10 , 499 | 1" 500 | 1% 501 | #555 502 | 0" 503 | 0% 504 | #560 505 | b1100 0 506 | 1' 507 | 1< 508 | b11 , 509 | 1" 510 | 1% 511 | #565 512 | 0" 513 | 0% 514 | #570 515 | b1011 0 516 | b101000000000000 2 517 | 0' 518 | 0< 519 | b100 , 520 | 1" 521 | 1% 522 | #575 523 | 0" 524 | 0% 525 | #580 526 | b1010 0 527 | 1' 528 | 1< 529 | b101 , 530 | 1" 531 | 1% 532 | #585 533 | 0" 534 | 0% 535 | #590 536 | b1001 0 537 | b101010000000000 2 538 | 0' 539 | 0< 540 | b110 , 541 | 1" 542 | 1% 543 | #595 544 | 0" 545 | 0% 546 | #600 547 | b1000 0 548 | 1' 549 | 1< 550 | b111 , 551 | 1" 552 | 1% 553 | #605 554 | 0" 555 | 0% 556 | #610 557 | b111 0 558 | b101010100000000 2 559 | 0' 560 | 0< 561 | b1000 , 562 | 1" 563 | 1% 564 | #615 565 | 0" 566 | 0% 567 | #620 568 | b110 0 569 | 1' 570 | 1< 571 | b1001 , 572 | 1" 573 | 1% 574 | #625 575 | 0" 576 | 0% 577 | #630 578 | b101 0 579 | b101010101000000 2 580 | 0' 581 | 0< 582 | b1010 , 583 | 1" 584 | 1% 585 | #635 586 | 0" 587 | 0% 588 | #640 589 | b100 0 590 | 1' 591 | 1< 592 | b1011 , 593 | 1" 594 | 1% 595 | #645 596 | 0" 597 | 0% 598 | #650 599 | b11 0 600 | b101010101010000 2 601 | 0' 602 | 0< 603 | b1100 , 604 | 1" 605 | 1% 606 | #655 607 | 0" 608 | 0% 609 | #660 610 | b10 0 611 | 1' 612 | 1< 613 | b1101 , 614 | 1" 615 | 1% 616 | #665 617 | 0" 618 | 0% 619 | #670 620 | b1 0 621 | b101010101010100 2 622 | 0' 623 | 0< 624 | b1110 , 625 | 1" 626 | 1% 627 | #675 628 | 0" 629 | 0% 630 | #680 631 | b1000 3 632 | b0 0 633 | 1' 634 | 1< 635 | b1111 , 636 | 1" 637 | 1% 638 | #685 639 | 0" 640 | 0% 641 | #690 642 | b101010101010101 # 643 | b101010101010101 1 644 | 0! 645 | b0 3 646 | b1111 0 647 | b101010101010101 2 648 | b1000 : 649 | 0' 650 | b10000 , 651 | 1" 652 | 1% 653 | #695 654 | 0" 655 | 0% 656 | #700 657 | b0 : 658 | b0 2 659 | 1" 660 | 1% 661 | #705 662 | 0" 663 | 0% 664 | #710 665 | 1" 666 | 1% 667 | #715 668 | 0" 669 | 0% 670 | #720 671 | 1" 672 | 1% 673 | #725 674 | 0" 675 | 0% 676 | #730 677 | 1" 678 | 1% 679 | #735 680 | 0" 681 | 0% 682 | #740 683 | 1" 684 | 1% 685 | -------------------------------------------------------------------------------- /tx.v: -------------------------------------------------------------------------------- 1 | module tx_sm #( 2 | parameter STATE_DEFER = 4'h0, 3 | parameter STATE_IFG = 4'h1, 4 | parameter STATE_IDLE = 4'h2, 5 | parameter STATE_PREAMBLE = 4'h3, 6 | parameter STATE_SFD = 4'h4, 7 | parameter STATE_DATA = 4'h5, 8 | parameter STATE_PAD = 4'h6, 9 | parameter STATE_JAM = 4'h7, 10 | parameter STATE_BACKOFF = 4'h8, 11 | parameter STATE_FCS = 4'h9, 12 | parameter STATE_JAM_DROP = 4'hA, 13 | parameter STATE_NEXT = 4'hB 14 | )( 15 | input wire reset, 16 | input wire clock, 17 | 18 | input wire [7:0] fifo_data, 19 | output reg fifo_data_read, 20 | input wire fifo_data_start, 21 | input wire fifo_data_end, 22 | input wire fifo_data_available, 23 | output reg fifo_retry, 24 | 25 | input wire mode, 26 | 27 | input wire carrier_sense, 28 | input wire collision, 29 | 30 | output reg tx_enable, 31 | output reg [7:0] tx_data 32 | ); 33 | 34 | localparam HALF_DUPLEX = 0; 35 | localparam FULL_DUPLEX = 1; 36 | 37 | reg [3:0] state; 38 | reg [3:0] next_state; 39 | reg [7:0] frame_length_count; 40 | reg [5:0] padding_length_count; 41 | reg [4:0] jam_length_count; 42 | reg [3:0] inter_frame_gap_count; 43 | reg [3:0] preamble_count; 44 | reg [3:0] retry_count; 45 | 46 | reg crc_init; 47 | reg crc_enable; 48 | wire [31:0] crc_out; 49 | integer crc_index; 50 | wire [31:0] crc_rev; 51 | 52 | reg random_init; 53 | wire random_trigger; 54 | 55 | // State update 56 | always @(posedge clock) 57 | if (reset) 58 | state <= STATE_DEFER; 59 | else 60 | state <= next_state; 61 | 62 | // State Machine 63 | always @ (*) 64 | case (state) 65 | STATE_DEFER: 66 | if ((mode == FULL_DUPLEX) || (mode == HALF_DUPLEX && !carrier_sense)) 67 | next_state = STATE_IFG; 68 | else 69 | next_state = STATE_DEFER; 70 | STATE_IFG: 71 | if (mode == HALF_DUPLEX && carrier_sense) 72 | next_state = STATE_DEFER; 73 | else if ((mode == FULL_DUPLEX && inter_frame_gap_count == 12 - 4) || (mode == HALF_DUPLEX && !carrier_sense && inter_frame_gap_count == 12 - 4)) // Drop IFG by four to account for state transitions 74 | next_state = STATE_IDLE; 75 | else 76 | next_state = STATE_IFG; 77 | STATE_IDLE: 78 | if (mode == HALF_DUPLEX && carrier_sense) 79 | next_state = STATE_DEFER; 80 | else if ((mode == FULL_DUPLEX && fifo_data_available) || (mode == HALF_DUPLEX && !carrier_sense && fifo_data_available)) 81 | next_state = STATE_PREAMBLE; 82 | else 83 | next_state = STATE_IDLE; 84 | STATE_PREAMBLE: 85 | if (mode == HALF_DUPLEX && collision) 86 | next_state = STATE_JAM; 87 | else if ((mode == FULL_DUPLEX && preamble_count == 6) || (mode == HALF_DUPLEX && !collision && preamble_count == 6)) 88 | next_state = STATE_SFD; 89 | else 90 | next_state = STATE_PREAMBLE; 91 | STATE_SFD: 92 | if (mode == HALF_DUPLEX && collision) 93 | next_state = STATE_JAM; 94 | else 95 | next_state = STATE_DATA; 96 | STATE_DATA: 97 | if (mode == HALF_DUPLEX && collision) 98 | next_state = STATE_JAM; 99 | else if (fifo_data_end && frame_length_count >= 59 ) 100 | next_state = STATE_FCS; 101 | else if (fifo_data_end) 102 | next_state = STATE_PAD; 103 | else 104 | next_state = STATE_DATA; 105 | STATE_PAD: 106 | if (mode == HALF_DUPLEX && collision) 107 | next_state = STATE_JAM; 108 | else if (frame_length_count >= 59) 109 | next_state = STATE_FCS; 110 | else 111 | next_state = STATE_PAD; 112 | STATE_JAM: 113 | if (retry_count <= 2 && jam_length_count == 16) 114 | next_state = STATE_BACKOFF; 115 | else if (retry_count > 2) 116 | next_state = STATE_JAM_DROP; 117 | else 118 | next_state = STATE_JAM; 119 | STATE_BACKOFF: 120 | if (random_trigger) 121 | next_state = STATE_DEFER; 122 | else 123 | next_state = STATE_BACKOFF; 124 | STATE_FCS: 125 | if (mode == HALF_DUPLEX && collision) 126 | next_state = STATE_JAM; 127 | else if (crc_index > 23) 128 | next_state = STATE_NEXT; 129 | else 130 | next_state = STATE_FCS; 131 | STATE_JAM_DROP: 132 | if (fifo_data_end) 133 | next_state = STATE_NEXT; 134 | else 135 | next_state = STATE_JAM_DROP; 136 | STATE_NEXT: 137 | next_state = STATE_DEFER; 138 | default: 139 | next_state = STATE_DEFER; 140 | endcase 141 | 142 | // Counts 143 | 144 | // Frame Length 145 | always @(posedge clock) 146 | if (reset) 147 | frame_length_count <= 0; 148 | else if (state == STATE_DEFER) 149 | frame_length_count <= 0; 150 | else if (state == STATE_DATA || state == STATE_PAD) 151 | frame_length_count <= frame_length_count+1; 152 | 153 | // Padding Length 154 | always @(posedge clock) 155 | if (reset) 156 | padding_length_count <=0; 157 | else if (state != STATE_PAD) 158 | padding_length_count <= 0; 159 | else 160 | padding_length_count <= padding_length_count + 1; 161 | 162 | // Jam Length 163 | always @ (posedge clock) 164 | if (reset) 165 | jam_length_count <= 0; 166 | else if (state == STATE_JAM || next_state == STATE_JAM) 167 | jam_length_count <= jam_length_count + 1; 168 | else 169 | jam_length_count <= 0; 170 | 171 | // Inter-Frame Gap 172 | always @ (posedge clock) 173 | if (reset) 174 | inter_frame_gap_count <= 0; 175 | else if (state != STATE_IFG) 176 | inter_frame_gap_count <= 0; 177 | else 178 | inter_frame_gap_count <= inter_frame_gap_count + 1; 179 | 180 | // Preamble 181 | always @ (posedge clock) 182 | if (reset) 183 | preamble_count <= 0; 184 | else if (state != STATE_PREAMBLE) 185 | preamble_count <= 0; 186 | else 187 | preamble_count <= preamble_count + 1; 188 | 189 | // Retry Counter 190 | always @ (posedge clock) 191 | if (reset) 192 | retry_count <= 0; 193 | else if (state == STATE_NEXT) 194 | retry_count <= 0; 195 | else if (state == STATE_JAM && next_state == STATE_BACKOFF) 196 | retry_count <= retry_count + 1; 197 | 198 | // State Output Actions 199 | 200 | genvar j; 201 | generate 202 | for (j = 31; j >= 0; j = j - 1) 203 | begin : crc_reverse 204 | assign crc_rev[31-j] = crc_out[j]; 205 | end 206 | endgenerate 207 | 208 | // FIFO 209 | always @ (*) 210 | if (state == STATE_DATA || 211 | state == STATE_JAM_DROP) 212 | fifo_data_read = 1; 213 | else 214 | fifo_data_read = 0; 215 | 216 | always @ (*) 217 | if (state == STATE_JAM) 218 | fifo_retry = 1; 219 | else 220 | fifo_retry = 0; 221 | 222 | // Transmit Enable 223 | always @(*) 224 | if (state == STATE_PREAMBLE || 225 | state == STATE_SFD || 226 | state == STATE_DATA || 227 | state == STATE_FCS || 228 | state == STATE_PAD || 229 | state == STATE_JAM ) 230 | tx_enable <= 1; 231 | else 232 | tx_enable <= 0; 233 | 234 | // Transmit Data 235 | always @(*) 236 | case (state) 237 | STATE_PREAMBLE: 238 | tx_data = 8'h55; 239 | STATE_SFD: 240 | tx_data = 8'hD5; 241 | STATE_DATA: 242 | tx_data = fifo_data; 243 | STATE_PAD: 244 | tx_data = 8'h00; 245 | STATE_JAM: 246 | tx_data = 8'h01; 247 | STATE_FCS: 248 | tx_data = ~crc_rev[crc_index+:8]; 249 | default: 250 | tx_data = 8'b00; 251 | endcase 252 | 253 | always @(posedge clock) 254 | if(state == STATE_FCS) 255 | crc_index = crc_index + 8; 256 | else 257 | crc_index = 0; 258 | 259 | // CRC 260 | always @(*) 261 | if (state == STATE_SFD) 262 | crc_init = 1; 263 | else 264 | crc_init = 0; 265 | 266 | always @(*) 267 | if (state == STATE_DATA || state == STATE_PAD) 268 | crc_enable = 1; 269 | else 270 | crc_enable = 0; 271 | 272 | // Random Calculation for Backoff 273 | always @(*) 274 | if (state == STATE_JAM && next_state == STATE_BACKOFF) 275 | random_init = 1; 276 | else 277 | random_init = 0; 278 | 279 | // Submodule Initialisation 280 | 281 | // CRC 282 | crc #( .POLYNOMIAL(32'h04C11DB7), 283 | .DATA_WIDTH(8), 284 | .CRC_WIDTH(32), 285 | .SEED(32'hFFFFFFFF)) 286 | U_crc( 287 | .reset(reset), 288 | .clock(clock), 289 | .init(crc_init), 290 | .data(tx_data), 291 | .data_enable(crc_enable), 292 | .crc_out(crc_out) 293 | ); 294 | 295 | random_gen U_random_gen( 296 | .reset(reset), 297 | .clock(clock), 298 | .init(random_init), 299 | .retry_count(retry_count), 300 | .trigger(random_trigger) 301 | ); 302 | 303 | endmodule 304 | -------------------------------------------------------------------------------- /tx.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeMercer/mac/e7fe37d619a6e6ce60eff276091900aab3e4ec5c/tx.xlsx --------------------------------------------------------------------------------