This commit is contained in:
Wiesner András 2024-11-28 17:12:50 +01:00
commit 038be21f4f
24 changed files with 1447 additions and 0 deletions

34
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,34 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Compile design",
"type": "shell",
"command": "./sims/compile_design.sh ${file}",
"problemMatcher": [
"$gcc"
]
},
{
"label": "Compile & simulate design",
"type": "shell",
"command": "./sims/compile_design.sh ${file} && cd sims && ./gtkwave \"${fileBasename}.vcd\" && cd -",
"problemMatcher": []
},
{
"label": "Simulate design",
"type": "shell",
"command": "cd sims && ./gtkwave \"${fileBasename}.vcd\" && cd -",
"problemMatcher": []
},
{
"label": "Simulate design with TCL",
"type": "shell",
"command": "cd sims && ./gtkwave \"${fileBasename}.vcd\" -T \"${fileBasename}.tcl\" && cd -",
"problemMatcher": []
}
]
}

30
sims/.gtkwaverc Normal file
View File

@ -0,0 +1,30 @@
do_initial_zoom_fit 1
enable_vcd_autosave yes
splash_disable on
dynamic_resing 1
initial_window_x 1920
initial_window_y 1120
# ablak háttérszíne
color_back gray90
# értékek színe
color_value blue
# rács színe
color_grid light steel blue
# jelek színe
#color_1 light sea green
color_1 dark olive green
#color_0 dark sea green
color_0 dark olive green
vector_padding 16
enable_vert_grid 1
enable_horiz_grid 0
color_vbox dark olive green
color_xfill dark red
color_time dark orange

80
sims/compile_design.sh Executable file
View File

@ -0,0 +1,80 @@
#!/bin/sh
FILENAME=$1
BASENAME=`basename $1`
DUMPFILE=$BASENAME.vcd
PREPROCFILE=$BASENAME.preproc
OUTFILE=$BASENAME.out
echo "\n"
# modul nevének kinyerése
MODULENAME=$(grep -E "^module (.)+" "$FILENAME" | cut -d\; -f1 | awk '{print $2}')
echo "Module: '$MODULENAME'"
# szimulációban szerepeltetendő jelek kinyerése
SIMSIGNALS=$(grep -E '^([^/]+)( `s )' "$FILENAME" | sed 's/[#(;][.]*//' | awk '{print $NF}')
if [ "$SIMSIGNALS" ] # ha vannak kiválasztott jelek
then
VARSTODUMP=""
# szimulálandó jelek összeírása a $dumpvars-hoz
for SIGNAME in $SIMSIGNALS
do
if [ "$VARSTODUMP" ]
then
VARSTODUMP="$VARSTODUMP, $MODULENAME.$SIGNAME"
else
VARSTODUMP="$MODULENAME.$SIGNAME"
fi
done
echo "Signals to display: $VARSTODUMP"
else # ha nincsenek
echo "No signals marked explicitly to simulate. Dumping all."
VARSTODUMP=$MODULENAME
fi
# szimulációs kiírási sorrend kinyerése
SIGSORT=$(grep -E '^(//# )' "$FILENAME" | sed 's|//# ||' | sed 's/, /,/g')
if [ "$SIGSORT" ] # ha meg van adva lista, akkor TCL-scriptet generál belőle
then
TCLSCRIPT="gtkwave::deleteSignalsFromListIncludingDuplicates [ gtkwave::getDisplayedSignals ]\n\n"
for line in $SIGSORT # parancs generálása soronként
do
TCLSCRIPT="$TCLSCRIPT gtkwave::addSignalsFromList [split \"$line\" ,]\n"
done
TCLFILENAME="$BASENAME.tcl";
# TCL-script kimentése
echo "$TCLSCRIPT" > "sims/$TCLFILENAME"
echo "Signal sorting TCL-file saved in 'sims/$TCLFILENAME'"
fi
# $dumpvars(...) beírása a fájlba
sed "/initial begin/a \$dumpfile(\"$DUMPFILE\");\n \$dumpvars(0, $VARSTODUMP);" "$FILENAME" > "$PREPROCFILE"
echo "\n"
# Verilog-fájl fordítása
iverilog -Wall "$PREPROCFILE" -o "sims/$OUTFILE"
rm "$PREPROCFILE"
#cd sims
# szimuláció futtatása
vvp "sims/$OUTFILE"
mv $DUMPFILE "sims/$DUMPFILE"
#cd -

92
sims/configuration.gtkw Normal file
View File

@ -0,0 +1,92 @@
[*]
[*] GTKWave Analyzer v3.3.103 (w)1999-2019 BSI
[*] Sun Mar 29 08:49:22 2020
[*]
[dumpfile] "/home/epagris/EGYETEM/RA/ra_hf/sims/TB_APB_master_dump.vcd"
[dumpfile_mtime] "Sun Mar 29 08:35:11 2020"
[dumpfile_size] 3919
[savefile] "/home/epagris/EGYETEM/RA/ra_hf/sims/configuration.gtkw"
[timestart] 0
[size] 1920 1110
[pos] -1 -1
*-15.000000 134790 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] TB_APB_master.
[sst_width] 211
[signals_width] 365
[sst_expanded] 1
[sst_vpaned_height] 321
@200
-MASTER
@22
TB_APB_master.apb_master_uut.PADDR[31:0]
@28
TB_APB_master.apb_master_uut.PCLK
TB_APB_master.apb_master_uut.PENABLE
@22
TB_APB_master.apb_master_uut.PRDATA[31:0]
@28
TB_APB_master.apb_master_uut.PREADY
TB_APB_master.apb_master_uut.PRESETn
TB_APB_master.apb_master_uut.PSEL0
TB_APB_master.apb_master_uut.PSLVERR
@22
TB_APB_master.apb_master_uut.PWDATA[31:0]
@28
TB_APB_master.apb_master_uut.PWRITE
@22
TB_APB_master.apb_master_uut.addr[31:0]
@420
TB_APB_master.apb_master_uut.bus_state
@28
TB_APB_master.apb_master_uut.clk
@22
TB_APB_master.apb_master_uut.data_read[31:0]
TB_APB_master.apb_master_uut.data_write[31:0]
@28
TB_APB_master.apb_master_uut.rst
@22
TB_APB_master.apb_master_uut.sampled_addr[31:0]
TB_APB_master.apb_master_uut.sampled_write_data[31:0]
@28
TB_APB_master.apb_master_uut.setup_valid
@420
TB_APB_master.apb_master_uut.transaction_type
@28
TB_APB_master.apb_master_uut.transfer_done
TB_APB_master.apb_master_uut.write_not_read
@200
-SLAVE
@22
TB_APB_master.apb_slave_uut.PADDR[31:0]
@28
TB_APB_master.apb_slave_uut.PCLK
TB_APB_master.apb_slave_uut.PENABLE
@22
TB_APB_master.apb_slave_uut.PRDATA[31:0]
@28
TB_APB_master.apb_slave_uut.PREADY
TB_APB_master.apb_slave_uut.PRESETn
TB_APB_master.apb_slave_uut.PSEL0
TB_APB_master.apb_slave_uut.PSLVERR
@22
TB_APB_master.apb_slave_uut.PWDATA[31:0]
@28
TB_APB_master.apb_slave_uut.PWRITE
@22
TB_APB_master.apb_slave_uut.addr[31:0]
@28
TB_APB_master.apb_slave_uut.bWithinAddressRange
TB_APB_master.apb_slave_uut.clk
@22
TB_APB_master.apb_slave_uut.data_read[31:0]
TB_APB_master.apb_slave_uut.data_write[31:0]
@28
TB_APB_master.apb_slave_uut.ready
TB_APB_master.apb_slave_uut.request_from_master
TB_APB_master.apb_slave_uut.rst
@420
TB_APB_master.apb_slave_uut.state
@28
TB_APB_master.apb_slave_uut.write_not_read
[pattern_trace] 1
[pattern_trace] 0

BIN
sims/gtkwave Executable file

Binary file not shown.

47
src/del_meas/del_meas.v Normal file
View File

@ -0,0 +1,47 @@
`timescale 1ns / 1ps
module del_meas #(
parameter WIDTH = 10
)(
input wire clk, // clock
input wire rst, // reset
input wire ref, // reference signal
input wire sig, // signal being measured
input wire arm, // arm the next measurement cycle
output wire listening, // indicated that measurement is armed
output reg done, // signals when measurement has concluded
input wire ack, // acknowledge latest measurement, turn off done
output reg negative, // indicates if delay is negative
output reg [WIDTH-1:0] delay // delay in ticks
);
// named states
localparam S_IDLE = 2'b0;
localparam S_LISTEN = 2'b1;
// inner state
reg [1:0] state;
// main state machine
always@(posedge clk)
begin
if (rst)
begin
done <= 0;
negative <= 0;
delay <= 0;
state <= S_IDLE;
end
else
begin
end
end
// output logic
assign listening = (state == S_LISTEN);
endmodule

73
src/eth/crc32.v Normal file
View File

@ -0,0 +1,73 @@
`timescale 1ns / 1ps
//-----------------------------------------------------------------------------
// Copyright (C) 2009 OutputLogic.com
// This source file may be used and distributed without restriction
// provided that this copyright statement is not removed from the file
// and that any derivative work contains the original copyright notice
// and the associated disclaimer.
//
// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//-----------------------------------------------------------------------------
// CRC module for data[7:0] , crc[31:0]=1+x^1+x^2+x^4+x^5+x^7+x^8+x^10+x^11+x^12+x^16+x^22+x^23+x^26+x^32;
//-----------------------------------------------------------------------------
module crc32(
input wire clk,
input wire rst,
input wire clear,
input wire [7:0] data_in,
input wire crc_en,
output wire [31:0] crc_out
);
reg [31:0] lfsr_q,lfsr_c;
assign crc_out = ~lfsr_q;
always @(*) begin
lfsr_c[0] = lfsr_q[24] ^ lfsr_q[30] ^ data_in[0] ^ data_in[6];
lfsr_c[1] = lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[0] ^ data_in[1] ^ data_in[6] ^ data_in[7];
lfsr_c[2] = lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[6] ^ data_in[7];
lfsr_c[3] = lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[31] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[7];
lfsr_c[4] = lfsr_q[24] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[30] ^ data_in[0] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[6];
lfsr_c[5] = lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[29] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[0] ^ data_in[1] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7];
lfsr_c[6] = lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[28] ^ lfsr_q[29] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[1] ^ data_in[2] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7];
lfsr_c[7] = lfsr_q[24] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[29] ^ lfsr_q[31] ^ data_in[0] ^ data_in[2] ^ data_in[3] ^ data_in[5] ^ data_in[7];
lfsr_c[8] = lfsr_q[0] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[27] ^ lfsr_q[28] ^ data_in[0] ^ data_in[1] ^ data_in[3] ^ data_in[4];
lfsr_c[9] = lfsr_q[1] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[28] ^ lfsr_q[29] ^ data_in[1] ^ data_in[2] ^ data_in[4] ^ data_in[5];
lfsr_c[10] = lfsr_q[2] ^ lfsr_q[24] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[29] ^ data_in[0] ^ data_in[2] ^ data_in[3] ^ data_in[5];
lfsr_c[11] = lfsr_q[3] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[27] ^ lfsr_q[28] ^ data_in[0] ^ data_in[1] ^ data_in[3] ^ data_in[4];
lfsr_c[12] = lfsr_q[4] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[28] ^ lfsr_q[29] ^ lfsr_q[30] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[4] ^ data_in[5] ^ data_in[6];
lfsr_c[13] = lfsr_q[5] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[29] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[5] ^ data_in[6] ^ data_in[7];
lfsr_c[14] = lfsr_q[6] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[6] ^ data_in[7];
lfsr_c[15] = lfsr_q[7] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[29] ^ lfsr_q[31] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[7];
lfsr_c[16] = lfsr_q[8] ^ lfsr_q[24] ^ lfsr_q[28] ^ lfsr_q[29] ^ data_in[0] ^ data_in[4] ^ data_in[5];
lfsr_c[17] = lfsr_q[9] ^ lfsr_q[25] ^ lfsr_q[29] ^ lfsr_q[30] ^ data_in[1] ^ data_in[5] ^ data_in[6];
lfsr_c[18] = lfsr_q[10] ^ lfsr_q[26] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[2] ^ data_in[6] ^ data_in[7];
lfsr_c[19] = lfsr_q[11] ^ lfsr_q[27] ^ lfsr_q[31] ^ data_in[3] ^ data_in[7];
lfsr_c[20] = lfsr_q[12] ^ lfsr_q[28] ^ data_in[4];
lfsr_c[21] = lfsr_q[13] ^ lfsr_q[29] ^ data_in[5];
lfsr_c[22] = lfsr_q[14] ^ lfsr_q[24] ^ data_in[0];
lfsr_c[23] = lfsr_q[15] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[30] ^ data_in[0] ^ data_in[1] ^ data_in[6];
lfsr_c[24] = lfsr_q[16] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[31] ^ data_in[1] ^ data_in[2] ^ data_in[7];
lfsr_c[25] = lfsr_q[17] ^ lfsr_q[26] ^ lfsr_q[27] ^ data_in[2] ^ data_in[3];
lfsr_c[26] = lfsr_q[18] ^ lfsr_q[24] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[30] ^ data_in[0] ^ data_in[3] ^ data_in[4] ^ data_in[6];
lfsr_c[27] = lfsr_q[19] ^ lfsr_q[25] ^ lfsr_q[28] ^ lfsr_q[29] ^ lfsr_q[31] ^ data_in[1] ^ data_in[4] ^ data_in[5] ^ data_in[7];
lfsr_c[28] = lfsr_q[20] ^ lfsr_q[26] ^ lfsr_q[29] ^ lfsr_q[30] ^ data_in[2] ^ data_in[5] ^ data_in[6];
lfsr_c[29] = lfsr_q[21] ^ lfsr_q[27] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[3] ^ data_in[6] ^ data_in[7];
lfsr_c[30] = lfsr_q[22] ^ lfsr_q[28] ^ lfsr_q[31] ^ data_in[4] ^ data_in[7];
lfsr_c[31] = lfsr_q[23] ^ lfsr_q[29] ^ data_in[5];
end // always
always @(posedge clk, posedge rst) begin
if(rst | clear) begin
lfsr_q <= {32{1'b0}};
end
else begin
lfsr_q <= crc_en ? lfsr_c : lfsr_q;
end
end // always
endmodule // crc32

76
src/eth/crc32_test.v Normal file
View File

@ -0,0 +1,76 @@
`timescale 1ns / 1ps
module crc32_test;
// Inputs
reg clk;
reg rst;
reg clear;
reg [7:0] data_in;
reg crc_en;
// Outputs
wire [31:0] crc_out;
// Instantiate the Unit Under Test (UUT)
crc32 uut (
.clk(clk),
.rst(rst),
.clear(clear),
.data_in(data_in),
.crc_en(crc_en),
.crc_out(crc_out)
);
always #10 clk = ~clk;
integer ifile;
integer c;
initial begin
// Initialize Inputs
clk = 0;
rst = 1;
clear = 0;
data_in = 0;
crc_en = 0;
// Wait 100 ns for global reset to finish
#100;
rst = 0;
// Add stimulus here
// open file holding the test input
ifile = $fopen("src/sim/lorem_ipsum.txt", "r");
if (ifile == 0)
begin
$display("Error on opening test input!\n");
$finish;
end
while (!$feof(ifile))
begin
@(posedge clk);
c = $fgetc(ifile);
if (c != -1)
begin
data_in = c[7:0];
crc_en = 1;
$display("%c", data_in);
end
else
begin
crc_en = 0;
end
end
$fclose(ifile);
#100;
$finish;
end
endmodule

96
src/eth/eth_mac.v Normal file
View File

@ -0,0 +1,96 @@
`timescale 1ns / 1ps
`include "src/eth/mac_memory_access_controller.v"
`include "src/rmii/rmii_clock_generator.v"
`include "src/rmii/rmii_transmit_controller.v"
module eth_mac #(
parameter MAIN_CLK_FREQ = 200,
parameter MEM_DATA_WIDTH = 8,
parameter MEM_ADDR_WIDTH = 12,
// AUTOCALCULATED
parameter MEM_ADDR_MSB = MEM_ADDR_WIDTH - 1,
parameter LEN_WIDTH = 11,
parameter LEN_MSB = LEN_WIDTH - 1,
parameter CTRL_WORD_WIDTH = 32
)(
input clk, rst, clear,
input [MEM_DATA_WIDTH-1:0] mem_data,
output [MEM_ADDR_WIDTH-1:0] mem_addr,
input [CTRL_WORD_WIDTH-1:0] ctrl_word,
output REF_CLK,
output TXEN,
output [1:0] TXD
//input CRS_DV,
//input [1:0] RXD
);
wire REF_pulse;
rmii_clock_generator #(
.MAIN_CLK_FREQ(MAIN_CLK_FREQ)
) clk_gen (
.clk(clk),
.rst(rst),
.REF_CLK(REF_CLK),
.rising(REF_pulse)
);
wire tx_wrt;
wire tx_not_full;
wire transmitter_busy;
rmii_transmit_controller #(
.STORAGE_WIDTH(MEM_DATA_WIDTH)
) tx_ctrl (
.clk(clk),
.rst(rst),
.clear(clear),
.REF_pulse(REF_pulse),
.data_in(mem_data),
.wrt(tx_wrt),
.not_full(tx_not_full),
.busy(transmitter_busy),
.TXEN(TXEN),
.TXD(TXD)
);
wire [MEM_ADDR_MSB:0] frame_addr = ctrl_word[MEM_ADDR_WIDTH-1:0];
wire [LEN_MSB:0] frame_len = ctrl_word[MEM_ADDR_WIDTH + LEN_WIDTH - 1:MEM_ADDR_WIDTH];
wire start = ctrl_word[CTRL_WORD_WIDTH - 1];
wire mem_acc_busy;
mac_memory_access_controller #(
.DATA_WIDTH(MEM_DATA_WIDTH),
.ADDR_WIDTH(MEM_ADDR_WIDTH)
) mem_acc_ctrl (
.clk(clk),
.rst(rst),
.clear(clear),
.mem_data(mem_data),
.mem_addr(mem_addr),
.transmitter_busy(transmitter_busy),
.start(start),
.frame_addr(frame_addr),
.frame_len(frame_len),
.busy(mem_acc_busy),
.tx_data_in(),
.tx_not_full(tx_not_full),
.tx_wrt(tx_wrt)
);
endmodule

View File

@ -0,0 +1,98 @@
`timescale 1ns / 1ps
module mac_memory_access_controller #(
parameter DATA_WIDTH = 8,
parameter ADDR_WIDTH = 12,
// AUTOCALCULATED
parameter DATA_MSB = DATA_WIDTH - 1,
parameter ADDR_MSB = ADDR_WIDTH - 1,
parameter LEN_MSB = 10
)(
input clk, rst, clear, // general signals
input [DATA_MSB:0] mem_data, // data fetched from the memory
output reg [ADDR_MSB:0] mem_addr, // memory address for data fetching
input transmitter_busy, // indicates that the transmitter is busy with previous transmission
input start, // start a new transmission
input [ADDR_MSB:0] frame_addr, // starting address of the Ethernet frame
input [LEN_MSB:0] frame_len, // length of the Ethernet frame
output busy, // a frame is currently being processed and transmitted
output [DATA_MSB:0] tx_data_in, // data input for the transmitter block
input tx_not_full, // transmitter block supports storing new blocks of data
output tx_wrt // issue a write onto the transmitter block
);
wire rstclr = rst | clear;
// state machine states
localparam IDLE = 0;
localparam FETCH_FRAME = 1;
localparam WAIT_TX_COMPL = 2;
// main state machine
reg [1:0] state;
wire frame_params_valid = frame_len != 0;
// frame setup and transmission
reg [LEN_MSB:0] len_left;
always @(posedge clk)
begin
if (rstclr)
begin
len_left <= 0;
//tx_wrt <= 0;
mem_addr <= 0;
len_left <= 0;
end
else
begin
case (state)
IDLE:
begin
mem_addr <= frame_addr;
len_left <= frame_len - 1;
end
FETCH_FRAME:
begin
if (len_left != 0)
begin
//tx_wrt <= 1;
if (tx_not_full)
begin
mem_addr <= mem_addr + 1;
len_left <= len_left - 1;
end
end
else
begin
//tx_wrt <= 0;
end
end
default: ;
endcase
end
// next state logic
case (state)
IDLE: if (start && frame_params_valid) state <= FETCH_FRAME;
FETCH_FRAME: if ((len_left == 0) && tx_not_full) state <= WAIT_TX_COMPL;
WAIT_TX_COMPL: if (!transmitter_busy) state <= IDLE;
default: state <= IDLE;
endcase
end
// combinatorial outputs
assign busy = (state != IDLE);
assign tx_data_in = mem_data;
assign tx_wrt = (state == FETCH_FRAME);
endmodule

108
src/fifo.v Normal file
View File

@ -0,0 +1,108 @@
`timescale 1ns / 1ps
module fifo #(
parameter WIDTH = 8,
parameter DEPTH = 8,
// AUTOCALCULATED
parameter STORAGE_MSB = WIDTH - 1,
parameter INDEX_MSB = $clog2(DEPTH) - 1
)(
input wire clk,
input wire rst,
input wire clear,
input wire [STORAGE_MSB:0] in,
input wire push,
output reg [STORAGE_MSB:0] out,
input wire pop,
output wire empty,
output reg out_valid,
output wire full
);
// combined clear and reset
wire rstclr = rst | clear;
// inner state
reg [STORAGE_MSB:0] mem [DEPTH-1:0]; // buffer
reg [INDEX_MSB + 1:0] level; // fill level
reg [INDEX_MSB:0] push_idx; // this is where the next data will be pushed
reg [INDEX_MSB:0] pop_idx; // this is the index that is going to be popped next
wire will_pop = pop && !empty; // the FIFO will pop in this cycle
wire will_push = push && !full; // the FIFO will store a new item in this cycle
// push
integer i;
always @(posedge clk)
begin
if (rstclr)
begin
for (i = 0; i < DEPTH; i = i + 1)
begin
mem[i] <= 0;
end
push_idx <= 0;
end
else
begin
if (will_push)
begin
mem[push_idx] <= in;
push_idx <= push_idx + 1;
end
end
end
// pop
always @(posedge clk)
begin
if (rst)
begin
pop_idx <= 0;
out <= 0;
out_valid <= 0;
end
else
begin
if (will_pop)
begin
out <= mem[pop_idx];
pop_idx <= pop_idx + 1;
out_valid <= 1;
end
else
begin
out_valid <= 0;
end
end
end
// level maintenance
always @(posedge clk)
begin
if (rst)
begin
level <= 0;
end
else
begin
if (will_push && !will_pop)
begin
level <= level + 1;
end
if (will_pop && !will_push)
begin
level <= level - 1;
end
end
end
// state flags
assign empty = (level == 0);
assign full = (level == DEPTH);
endmodule

45
src/jitmeas_top.v Normal file
View File

@ -0,0 +1,45 @@
`timescale 1ns / 1ps
module jitmeas_top(
input wire clk50M, // 50MHz clock input
input wire rstbt,
//output wire clk200M
output wire [16:4] aio
);
wire rst = ~rstbt;
/* Main Clock Generation module */
wire main_pll_locked;
wire clk200M;
MainPLL main_pll (
// Clock in ports
.In_50MHz(clk50M), // IN
// Clock out ports
.Out_200MHz(clk200M), // OUT
// Status and control signals
.RESET(rst), // IN
.LOCKED(main_pll_locked) // OUT
);
localparam MAIN_CLK_FREQ = 200; // Main Clock Frequency in MHz
assign aio[16:5] = 0;
eth_mac eth_mac_inst (
.clk(clk200M),
.rst(rst),
.REF_CLK(REF_CLK),
//.TXEN(TXEN),
//.TXD(TXD),
.CRS_DV(0),
.RXD(0)
);
endmodule

View File

@ -0,0 +1,37 @@
`timescale 1ns / 1ps
module rmii_clock_generator #(
parameter MAIN_CLK_FREQ = 200, // frequency of the main clock
// AUTOCALCULATED
parameter CNTR_WIDTH = $clog2(MAIN_CLK_FREQ / 50), // width of the CNTR
parameter CNTR_MSB = CNTR_WIDTH - 1 // index of the counter's MSB
)(
input wire clk, // main clock input
input wire rst, // synchronous reset
output wire REF_CLK, // RMII REF_CLK output
output wire rising, // the next clk cycle comes with a rising edge on the REF_CLK
output wire falling // ... falling ...
);
reg [CNTR_MSB:0] ref_clk_cntr;
always @(posedge clk)
begin
if (rst)
begin
ref_clk_cntr = 0;
end
else
begin
ref_clk_cntr = ref_clk_cntr + 1;
end
end
assign REF_CLK = ref_clk_cntr[CNTR_MSB];
assign rising = (&ref_clk_cntr[CNTR_MSB-1:0]) & (~ref_clk_cntr[CNTR_MSB]);
assign falling = &ref_clk_cntr;
endmodule

View File

@ -0,0 +1,43 @@
`timescale 1ns / 1ps
module rmii_controller #(
parameter MAIN_CLK_FREQ = 200
)(
input wire clk,
input wire rst,
/* RMII signals */
// reference clock
output wire REF_CLK,
// transmit signals
output wire [1:0] TXD,
output wire TXEN,
// receive signals
input wire [1:0] RXD,
input wire CRS_DV
);
/* RMII Reference Clock Generation state machine */
wire ref_clk_rising;
wire ref_clk_falling;
rmii_clock_generator #(
.MAIN_CLK_FREQ(MAIN_CLK_FREQ)
) clk_gen (
.clk(clk),
.rst(rst),
.REF_CLK(REF_CLK),
.rising(ref_clk_rising),
.falling(ref_clk_falling)
);
/* */
assign TXD = 0;
assign TXEN = 0;
endmodule

View File

@ -0,0 +1,61 @@
`timescale 1ns / 1ps
module rmii_serializer #(
parameter SHIFT_SIZE = 2,
parameter STORE_SIZE = 8,
parameter DIR = 0, // 0 -> left; 1 -> right
// AUTOCALCULATED
parameter SHIFT_COUNT = STORE_SIZE / SHIFT_SIZE,
parameter SHIFT_COUNT_MSB = $clog2(SHIFT_COUNT) - 1
)(
input clk, rst, clear, // main clock, reset, clear
input [STORE_SIZE-1:0] par_in, // parallel input
input load, // load parallel data
output [SHIFT_SIZE-1:0] ser_out, // serialized output
input shift, // enable shifting
output empty // the inner buffer has depleted
);
// a combine reset or clear signal
wire rstclr = rst | clear;
// shift work register
reg [STORE_SIZE-1:0] shift_work;
// shift count register
reg [SHIFT_COUNT_MSB:0] shift_count;
/* main state machine */
always @(posedge clk)
begin
if (rstclr)
begin
shift_work <= 0;
shift_count <= 0;
end
else
begin
if (load) // load the parallel data
begin
shift_work <= par_in;
shift_count <= SHIFT_COUNT - 1; // data must be shifted SHIFT_COUNT - 1 times
end
else if (shift)
begin
if (shift_count > 0)
begin
shift_count <= shift_count - 1; // decrease shift count
shift_work <= DIR ? (shift_work >> SHIFT_SIZE) : (shift_work << SHIFT_SIZE); // shift the contents of the work register
end
end
end
end
// output logic
assign empty = (shift_count == 0); // indication for depletion
assign ser_out = DIR ? shift_work[SHIFT_SIZE-1:0] : shift_work[STORE_SIZE-1:STORE_SIZE-SHIFT_SIZE]; // serial output
endmodule

View File

@ -0,0 +1,99 @@
`timescale 1ns / 1ps
`include "src/fifo.v"
`include "src/rmii/rmii_serializer.v"
module rmii_transmit_controller #(
parameter FIFO_DEPTH = 16,
parameter STORAGE_WIDTH = 8,
// AUTOCALCULATED
parameter STORAGE_MSB = STORAGE_WIDTH - 1,
parameter SHIFT_COUNT = FIFO_DEPTH
)(
input clk, rst, clear, // general signals
input REF_pulse, // pulse that signals the coming rising edge on REF_CLK
/* FIFO signals */
input [STORAGE_MSB:0] data_in, // input data
input wrt, // store the data
output not_full, // the internal buffer is not full
/* RMII signals */
output reg TXEN, // transmit enable
output [1:0] TXD, // transmit data
output busy // there's an ongoing transmission
);
/* TX FIFO and its signals */
wire tx_fifo_empty;
wire tx_fifo_out_valid;
wire tx_fifo_full;
wire [STORAGE_WIDTH-1:0]tx_fifo_out;
wire tx_fifo_pop = oser_empty && REF_pulse;
fifo #(
.DEPTH(FIFO_DEPTH),
.WIDTH(STORAGE_WIDTH)
) tx_fifo (
.clk(clk),
.rst(rst),
.clear(clear),
.empty(tx_fifo_empty),
.out_valid(tx_fifo_out_valid),
.full(tx_fifo_full),
.in(data_in),
.push(wrt),
.out(tx_fifo_out),
.pop(tx_fifo_pop)
);
assign not_full = !tx_fifo_full;
/* output serializer */
wire oser_load = tx_fifo_out_valid;
wire oser_empty;
rmii_serializer #(
.STORE_SIZE(STORAGE_WIDTH),
.DIR(0) // LEFT
) out_serializer (
.clk(clk),
.rst(rst),
.clear(clear),
.par_in(tx_fifo_out),
.ser_out(TXD),
.load(oser_load),
.shift(REF_pulse),
.empty(oser_empty)
);
/* TXEN control */
always @(posedge clk)
begin
if (rst | clear)
begin
TXEN <= 0;
end
else
begin
if (oser_load) // assert the same time the shift register loading occurs
begin
TXEN <= 1;
end
else if (REF_pulse && oser_empty && tx_fifo_empty) // deassert only when all buffers has depleted
begin
TXEN <= 0;
end
end
end
assign busy = TXEN;
endmodule

View File

@ -0,0 +1 @@
4C 6F 72 65 6D 20 69 70 73 75 6D 20 64 6F 6C 6F 72 20 73 69 74 20 61 6D 65 74

98
src/sim/eth_mac_test.v Normal file
View File

@ -0,0 +1,98 @@
`timescale 1ns / 1ps
`include "src/eth/eth_mac.v"
module eth_mac_test;
// Inputs
reg clk;
reg rst;
reg clear;
wire [7:0] mem_data;
reg [31:0] ctrl_word;
// Outputs
wire [11:0] mem_addr;
wire REF_CLK;
wire TXEN;
wire [1:0] TXD;
// Instantiate the Unit Under Test (UUT)
eth_mac uut (
.clk(clk),
.rst(rst),
.clear(clear),
.mem_data(mem_data),
.mem_addr(mem_addr),
.ctrl_word(ctrl_word),
.REF_CLK(REF_CLK),
.TXEN(TXEN),
.TXD(TXD)
);
always #2.5 clk <= ~clk;
reg run;
// memory
localparam MEM_SIZE = 26;
reg [7:0] mem [0:MEM_SIZE-1];
assign mem_data = mem[mem_addr];
// frame data
localparam FRAME_ADDR = 0;
localparam FRAME_LENGTH = 26;
localparam START = (1 << 31);
// RMII deserializer
integer wrt_cntr;
reg [7:0] deser;
always @(posedge REF_CLK)
begin
if (TXEN && run)
begin
deser = {deser[5:0], TXD};
wrt_cntr = wrt_cntr + 1;
if ((wrt_cntr & 32'b11) == 0)
begin
//$fwrite(ofile, "%c", deser);
$display("%c", deser);
end
end
end
initial begin
// Initialize Inputs
clk <= 0;
rst <= 1;
clear <= 0;
ctrl_word <= 0;
deser = 0;
wrt_cntr = 0;
run <= 0;
// populate memory
$readmemh("src/sim/eth_frame_mem.mem", mem);
// Wait 20 ns for global reset to finish
#20;
rst <= 0;
// Add stimulus here
#20;
@(posedge clk);
ctrl_word <= START | (FRAME_LENGTH << 12) | (FRAME_ADDR);
run <= 1;
@(TXEN == 1);
@(TXEN == 0);
#20;
$finish;
end
endmodule

121
src/sim/fifo_test.v Normal file
View File

@ -0,0 +1,121 @@
`timescale 1ns / 1ps
`include "src/fifo.v"
module fifo_test;
// Inputs
reg clk;
reg rst;
reg clear;
reg [7:0] in;
reg push;
reg pop;
// Outputs
wire [7:0] out;
wire empty;
wire out_valid;
wire full;
// Instantiate the Unit Under Test (UUT)
fifo uut (
.clk(clk),
.rst(rst),
.clear(clear),
.in(in),
.push(push),
.out(out),
.pop(pop),
.empty(empty),
.out_valid(out_valid),
.full(full)
);
always #10 clk = ~clk;
always @(posedge clk)
begin
if (c >= 0 && !rst)
begin
pop <= $random & 1'b1;
push <= $random & 1'b1;
end
else
begin
push <= 0;
end
end
always @(posedge clk)
begin
if (out_valid)
begin
$display("%c", out);
//$fdisplay(ofile, "%c", out);
$fwrite(ofile, "%c", out);
end
end
always @(posedge clk)
begin
if ((!full && push) || start)
begin
c = $fgetc(ifile);
if (c != -1)
begin
in <= c[7:0];
end
end
start <= 0;
end
integer ifile, ofile, c;
reg start;
initial begin
// Initialize Inputs
clk <= 0;
rst <= 1;
clear <= 0;
in <= 0;
pop <= 0;
push <= 0;
c = 0;
start <= 0;
// Wait 20ns for global reset to finish
#20;
rst <= 0;
// Add stimulus here
// open file holding the test input
ifile = $fopen("src/sim/lorem_ipsum.txt", "r");
ofile = $fopen("src/sim/fifo_out.txt", "w");
if ((ifile == 0) || (ofile == 0))
begin
$display("Error on opening at least one of the files!\n");
$finish;
end
// start simulation
start <= 1;
// wait until EOF is reached
@(c == -1);
// wait for FIFO depletion
if (!empty)
begin
@(posedge empty);
end
$fclose(ifile);
$fclose(ofile);
$finish;
end
endmodule

1
src/sim/lorem_ipsum.txt Normal file
View File

@ -0,0 +1 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

1
src/sim/lorem_rovid.txt Normal file
View File

@ -0,0 +1 @@
Lorem ipsum dolor sit amet

39
src/sim/rmii_ctrl_test.v Normal file
View File

@ -0,0 +1,39 @@
`timescale 1ns / 1ps
module rmii_ctrl_test;
// Inputs
reg clk;
reg rst;
// Outputs
wire REF_CLK;
wire [1:0] TXD;
wire TXEN;
// Instantiate the Unit Under Test (UUT)
rmii_controller uut (
.clk(clk),
.rst(rst),
.REF_CLK(REF_CLK),
.TXD(TXD),
.TXEN(TXEN)
);
always #2.5 clk = ~clk;
initial begin
// input initialization
clk = 0;
rst = 1;
// global reset
#5;
// stimulus
rst = 0;
end
endmodule

View File

@ -0,0 +1,133 @@
`timescale 1ns / 500ps
module rmii_transmit_controller_test;
// Inputs
reg clk;
reg rst;
reg clear;
reg [7:0] data_in;
reg wrt;
wire REF_pulse;
wire REF_CLK;
wire REF_negpulse;
// Outputs
wire not_full;
wire TXEN;
wire [1:0] TXD;
// Instantiate the Unit Under Test (UUT)
rmii_transmit_controller uut (
.clk(clk),
.rst(rst),
.clear(clear),
.data_in(data_in),
.wrt(wrt),
.not_full(not_full),
.REF_pulse(REF_pulse),
.TXEN(TXEN),
.TXD(TXD)
);
always #2.5 clk = ~clk;
rmii_clock_generator clk_gen(
.clk(clk),
.rst(rst),
.REF_CLK(REF_CLK),
.rising(REF_pulse),
.falling(REF_negpulse)
);
integer ifile = 0, ofile = 0;
reg run;
reg read_input;
integer c;
always @(posedge clk)
begin
if (read_input)
begin
if (not_full)
begin
c = $fgetc(ifile);
if (c != -1)
begin
data_in <= c[7:0];
wrt <= 1;
end
else
begin
read_input <= 0;
wrt <= 0;
end
end
end
end
integer wrt_cntr;
reg [7:0] deser;
always @(posedge REF_pulse)
begin
if (TXEN && run)
begin
deser = {deser[5:0], TXD};
wrt_cntr = wrt_cntr + 1;
if ((wrt_cntr & 32'b11) == 0)
begin
$fwrite(ofile, "%c", deser);
end
end
end
initial begin
// Initialize Inputs
clk <= 0;
rst <= 1;
clear <= 0;
data_in <= 0;
wrt <= 0;
run <= 0;
c = 0;
wrt_cntr = 0;
deser = 0;
wrt <= 0;
read_input <= 0;
// Wait 20 ns for global reset to finish
#20;
rst <= 0;
// Add stimulus here
// open file holding the test input
ifile = $fopen("src/sim/lorem_ipsum.txt", "r");
ofile = $fopen("src/sim/rmii_TXD.txt", "w");
if ((ifile == 0) || (ofile == 0))
begin
$display("Error on opening at least one of the files!\n");
$finish;
end
// start simulation
run <= 1;
read_input <= 1;
// wait for the deassertion of run
@(TXEN == 1);
@(TXEN == 0);
run <= 0;
@(posedge REF_CLK);
@(posedge REF_CLK);
$fclose(ifile);
$fclose(ofile);
$finish;
end
endmodule

34
src/sim/top_sim.v Normal file
View File

@ -0,0 +1,34 @@
`timescale 1ns / 1ps
module top_sim;
// Inputs
reg clk50M;
reg rstbt;
// Outputs
wire [16:4] aio;
// Instantiate the Unit Under Test (UUT)
jitmeas_top uut (
.clk50M(clk50M),
.rstbt(rstbt),
.aio(aio)
);
always #10 clk50M = ~clk50M;
initial begin
// Initialize Inputs
clk50M = 0;
rstbt = 1;
// Wait 100 ns for global reset to finish
#20;
// Add stimulus here
rstbt = 0;
end
endmodule