Compare commits
128
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
255b46ffb2 | ||
|
|
1ed67ac450 | ||
|
|
f6139daf11 | ||
|
|
4a092a0ece | ||
|
|
7c94cbca56 | ||
|
|
e26d09e89f | ||
|
|
a94e72f05f | ||
|
|
703e32ad5e | ||
|
|
86c555d298 | ||
|
|
d7c826406d | ||
|
|
136b69dd9f | ||
|
|
b41fbca893 | ||
|
|
f898ef2acd | ||
|
|
08ea864c56 | ||
|
|
1f5ef3eab0 | ||
|
|
d6c7632611 | ||
|
|
820f3400ea | ||
|
|
9c66f1b530 | ||
|
|
ae2a9c4f35 | ||
|
|
94c3dee46e | ||
|
|
2094717ad3 | ||
|
|
4e85e57095 | ||
|
|
c95bc94ef8 | ||
|
|
9d22631e0e | ||
|
|
c221a6eef5 | ||
|
|
8fa3beb9b3 | ||
|
|
5e2ac8db62 | ||
|
|
2e740617ae | ||
|
|
b9865e8e1f | ||
|
|
ad8625526d | ||
|
|
5b61319140 | ||
|
|
1d7d7ef5e9 | ||
|
|
73f82ee5c6 | ||
|
|
947ba908fb | ||
|
|
d84e809336 | ||
|
|
ecaf49acfd | ||
|
|
7d0fcd4b29 | ||
|
|
345344e8e2 | ||
|
|
ed38e377a6 | ||
|
|
d9042042ff | ||
|
|
19fcdb1db8 | ||
|
|
034f6ea9e8 | ||
|
|
8a07c4ab6c | ||
|
|
4619c28334 | ||
|
|
ad90d1e3c8 | ||
|
|
d82670827c | ||
|
|
8ca0e197d5 | ||
|
|
5eb746c0ad | ||
|
|
4247a107ef | ||
|
|
7840e0ea7b | ||
|
|
c5bb953d81 | ||
|
|
23731b95c3 | ||
|
|
2fc927d2e7 | ||
|
|
489a2f3475 | ||
|
|
8fc8df6549 | ||
|
|
bec1cee7a8 | ||
|
|
ea9a6ad1e6 | ||
|
|
5e3b0beef9 | ||
|
|
4acaea8d39 | ||
|
|
b731b1b75d | ||
|
|
32076b19f7 | ||
|
|
c21c9d2ab5 | ||
|
|
56a0240f8e | ||
|
|
81970c8b42 | ||
|
|
a528838741 | ||
|
|
04eb927a25 | ||
|
|
4240604f26 | ||
|
|
ef65dd1a97 | ||
|
|
71b825ef2c | ||
|
|
d80f5ff31f | ||
|
|
493d6844c0 | ||
|
|
11a9e97691 | ||
|
|
0ba25a3541 | ||
|
|
64f94a90e6 | ||
|
|
7665afd50b | ||
|
|
9f99021168 | ||
|
|
9c70029f3e | ||
|
|
177c7d0bc2 | ||
|
|
c3275d5b46 | ||
|
|
7b96fbddbf | ||
|
|
2282eb4e16 | ||
|
|
287d855df4 | ||
|
|
8e5b3929ac | ||
|
|
df5469d538 | ||
|
|
725826b07c | ||
|
|
77526c44c2 | ||
|
|
5010c42ae3 | ||
|
|
f0542845b0 | ||
|
|
46333c3601 | ||
|
|
2a3796a60f | ||
|
|
d878bac42a | ||
|
|
425c922690 | ||
|
|
02416a9621 | ||
|
|
771225cd77 | ||
|
|
b38a693676 | ||
|
|
789255fa04 | ||
|
|
efcd6ef5d0 | ||
|
|
4fbecd5e30 | ||
|
|
d71aaf1650 | ||
|
|
035d02234c | ||
|
|
4923f01322 | ||
|
|
45a57d57e4 | ||
|
|
29e1541ffb | ||
|
|
fd9280737d | ||
|
|
64843b462d | ||
|
|
c0714f271e | ||
|
|
c165d346a0 | ||
|
|
753f4a2128 | ||
|
|
6155c6a9fb | ||
|
|
bb65aea4f1 | ||
|
|
5d3b761b07 | ||
|
|
d7e46445d8 | ||
|
|
cacfe04061 | ||
|
|
4270c2fca8 | ||
|
|
cf2985813a | ||
|
|
f670df9b54 | ||
|
|
6542995930 | ||
|
|
b0e886893b | ||
|
|
d90167984a | ||
|
|
3a1d9c27e7 | ||
|
|
c9aa2cde0f | ||
|
|
ccd9964ada | ||
|
|
1a3b811e75 | ||
|
|
9c74fe91e8 | ||
|
|
c8e11a2a1f | ||
|
|
0a68a753be | ||
|
|
906d5090cd | ||
|
|
dc761f31dc |
+6
-1
@@ -16,6 +16,7 @@
|
||||
.Xil
|
||||
xvlog.pb
|
||||
*vivado_pid*
|
||||
**/work/*
|
||||
|
||||
# some generated files (they annoy me)
|
||||
update_config.tcl
|
||||
@@ -26,4 +27,8 @@ run_sim.tcl
|
||||
*.bit
|
||||
*.xsa
|
||||
*.ltx
|
||||
*.bin
|
||||
*.bin
|
||||
|
||||
# slang files
|
||||
.slang
|
||||
files.f
|
||||
@@ -27,6 +27,7 @@ XDC_FILES += ../../constraints/ax7102.xdc
|
||||
XDC_FILES += debug.xdc
|
||||
|
||||
SYN_FILES += tb_sync_top.sv
|
||||
|
||||
SIM_TOP = tb_top
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
# Primary clocks
|
||||
create_clock -name eth_clk -period 8.000 [get_ports dac_clk_in]
|
||||
create_clock -name acc_clk -period 15.385 [get_ports adc_clk_in]
|
||||
create_clock -name geneartor_clk -period 8.000 [get_ports clk_dac]
|
||||
create_clock -name sampler_clk -period 15.385 [get_ports clk_adc]
|
||||
set_clock_groups -asynchronous -group [get_clocks geneartor_clk] -group [get_clocks sampler_clk]
|
||||
|
||||
# set_false_path -through [get_nets -hierarchical {*dac_signal* *internal_wire_singnal* *adc_singnal*}]
|
||||
# set_false_path -through [get_nets {dac_done dac_done_stretched dac_request adc_done adc_request}]
|
||||
|
||||
# Asynchronous clock groups
|
||||
|
||||
set_clock_groups -name ASYNC_ETH_ACC -asynchronous \
|
||||
-group [get_clocks eth_clk] \
|
||||
-group [get_clocks acc_clk]
|
||||
set_property DONT_TOUCH true [get_cells -hierarchical -filter {NAME =~ *generator_inst*pulse_height_reg*}]
|
||||
set_property DONT_TOUCH true [get_cells -hierarchical -filter {NAME =~ *generator_inst*dac_out_reg*}]
|
||||
# Применяем к самому проводу сигнала CE, чтобы Vivado не дробила его
|
||||
# set_property DONT_TOUCH true [get_nets -of_objects [get_pins -hierarchical -filter {PIN_NAME =~ *CE} -of_objects [get_cells *pulse_height_reg*]]]
|
||||
@@ -2,113 +2,137 @@
|
||||
|
||||
module sync_top
|
||||
#(
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned PACK_FACTOR = 1,
|
||||
parameter int unsigned PROCESS_MODE = 0
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14, // DAC bit-width
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12, // ADC bit-width
|
||||
parameter int unsigned PACK_FACTOR = 1, // number of ADC readings per transaction
|
||||
parameter int unsigned PROCESS_MODE = 0, // representation format of ADC readings (0 - direct code, 1 - 2's completment)
|
||||
parameter int unsigned ZERO_LEVEL = 0,
|
||||
parameter int unsigned USE_DELAY_LINE = 0
|
||||
)
|
||||
(
|
||||
input adc_clk_in,
|
||||
input adc_rst,
|
||||
|
||||
input dac_clk_in,
|
||||
input dac_rst,
|
||||
|
||||
input dac_start,
|
||||
|
||||
input clk_adc,
|
||||
input rst_adc,
|
||||
input clk_dac,
|
||||
input rst_dac,
|
||||
input start,
|
||||
input out_of_range,
|
||||
input [31:0] pulse_width,
|
||||
input [31:0] pulse_period,
|
||||
input [31:0] pulse_period, // DAC counter limit
|
||||
input [DAC_DATA_WIDTH-1:0] pulse_height,
|
||||
input [15:0] pulse_num,
|
||||
input [31:0] smp_num,
|
||||
|
||||
output logic [ADC_DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata,
|
||||
output logic m_axis_tvalid
|
||||
input [31:0] smp_num, // ADC counter limit
|
||||
output [ADC_DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata,
|
||||
output m_axis_tvalid
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Internal signals
|
||||
//------------------------------------------------------------
|
||||
wire dac_done, dac_request, adc_done, adc_request;
|
||||
wire [DAC_DATA_WIDTH-1:0] dac_signal;
|
||||
wire [ADC_DATA_WIDTH-1:0] internal_wire_signal;
|
||||
wire [ADC_DATA_WIDTH-1:0] adc_signal;
|
||||
|
||||
(* MARK_DEBUG="true" *) logic sample_req;
|
||||
(* MARK_DEBUG="true" *) logic sample_req_sync1;
|
||||
(* MARK_DEBUG="true" *) logic sample_req_sync2;
|
||||
(* MARK_DEBUG="true" *) logic sample_req_sync3;
|
||||
// 1. Адаптация разрядности и «заземление» лишних бит
|
||||
generate
|
||||
if (ADC_DATA_WIDTH > DAC_DATA_WIDTH) begin : g_pad_zeros
|
||||
// АЦП шире ЦАП: добиваем нулями старшие биты
|
||||
assign internal_wire_signal = { {(ADC_DATA_WIDTH - DAC_DATA_WIDTH){1'b0}}, dac_signal };
|
||||
end
|
||||
else if (ADC_DATA_WIDTH < DAC_DATA_WIDTH) begin : g_truncate
|
||||
// ЦАП шире АЦП (например, 14 -> 12): забираем младшие биты
|
||||
assign internal_wire_signal = dac_signal[DAC_DATA_WIDTH-1:DAC_DATA_WIDTH-ADC_DATA_WIDTH];
|
||||
// (* mark_debug = "true" *) wire dummy;
|
||||
// assign dummy = ^dac_signal;
|
||||
end
|
||||
else begin : g_match
|
||||
// Разрядности равны
|
||||
assign internal_wire_signal = dac_signal;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
(* MARK_DEBUG="true" *) logic sample_done;
|
||||
(* MARK_DEBUG="true" *) logic sample_done_sync1;
|
||||
(* MARK_DEBUG="true" *) logic sample_done_sync2;
|
||||
(* MARK_DEBUG="true" *) logic sample_done_sync3;
|
||||
|
||||
(* MARK_DEBUG="true" *) logic pulse;
|
||||
(* MARK_DEBUG="true" *) logic [DAC_DATA_WIDTH-1:0] pulse_height_out;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Simple DAC -> ADC test source
|
||||
//
|
||||
// generator output is directly connected to sampler input
|
||||
// with width truncation:
|
||||
//
|
||||
// pulse_height_out[13:0] -> data_in[11:0]
|
||||
//------------------------------------------------------------
|
||||
(* MARK_DEBUG="true" *) logic [ADC_DATA_WIDTH-1:0] data_in;
|
||||
(* MARK_DEBUG="true" *) logic out_of_range;
|
||||
|
||||
assign data_in = pulse_height_out[ADC_DATA_WIDTH-1:0];
|
||||
assign out_of_range = 1'b0;
|
||||
generate
|
||||
if (USE_DELAY_LINE > 0) begin : g_delay_line
|
||||
localparam int DELAY_LENGTH = USE_DELAY_LINE;
|
||||
// Двумерный массив для линии задержки
|
||||
logic [DELAY_LENGTH-1:0][ADC_DATA_WIDTH-1:0] signal_delay_line;
|
||||
|
||||
always_ff @(posedge clk_dac) begin
|
||||
signal_delay_line[0] <= internal_wire_signal;
|
||||
for (int i = 0; i < DELAY_LENGTH-1; i++) begin
|
||||
signal_delay_line[i+1] <= signal_delay_line[i];
|
||||
end
|
||||
end
|
||||
|
||||
// ИСПРАВЛЕНО: читаем из последнего элемента массива
|
||||
assign adc_signal = signal_delay_line[DELAY_LENGTH-1];
|
||||
end
|
||||
else begin : g_no_delay
|
||||
assign adc_signal = internal_wire_signal;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
//------------------------------------------------------------
|
||||
// DAC -> ADC CDC
|
||||
//------------------------------------------------------------
|
||||
always_ff @(posedge adc_clk_in or posedge adc_rst) begin
|
||||
if (adc_rst) begin
|
||||
sample_req <= 1'b0;
|
||||
sample_req_sync2 <= 1'b0;
|
||||
sample_req_sync3 <= 1'b0;
|
||||
end
|
||||
logic [2:0] stretch; // 125/65~=2. Чтобы поймать единичный импульс, растянем его во времени
|
||||
logic [1:0] sync_DA;
|
||||
wire dac_done_stretched;
|
||||
|
||||
always_ff @(posedge clk_dac or posedge rst_dac)
|
||||
begin
|
||||
if (rst_dac)
|
||||
stretch <= 0;
|
||||
else begin
|
||||
sample_req_sync2 <= sample_req_sync1;
|
||||
sample_req_sync3 <= sample_req_sync2;
|
||||
sample_req <= sample_req_sync3;
|
||||
stretch[0] <= dac_done;
|
||||
stretch[1] <= stretch[0];
|
||||
stretch[2] <= stretch[1];
|
||||
end
|
||||
end
|
||||
assign dac_done_stretched = |stretch;
|
||||
|
||||
always_ff @(posedge clk_adc or posedge rst_adc) begin
|
||||
if (rst_adc)
|
||||
sync_DA <= 0;
|
||||
else begin
|
||||
sync_DA[0] <= dac_done_stretched;
|
||||
sync_DA[1] <= sync_DA[0];
|
||||
end
|
||||
end
|
||||
assign adc_request = sync_DA[1];
|
||||
|
||||
//------------------------------------------------------------
|
||||
// ADC -> DAC CDC
|
||||
//------------------------------------------------------------
|
||||
always_ff @(posedge dac_clk_in or posedge dac_rst) begin
|
||||
if (dac_rst) begin
|
||||
sample_done <= 1'b0;
|
||||
sample_done_sync2 <= 1'b0;
|
||||
sample_done_sync3 <= 1'b0;
|
||||
end
|
||||
logic [1:0] sync_AD;
|
||||
|
||||
always_ff @(posedge clk_dac or posedge rst_dac) begin
|
||||
if (rst_dac)
|
||||
sync_AD <= 0;
|
||||
else begin
|
||||
sample_done_sync2 <= sample_done_sync1;
|
||||
sample_done_sync3 <= sample_done_sync2;
|
||||
sample_done <= sample_done_sync3;
|
||||
sync_AD[0] <= adc_done;
|
||||
sync_AD[1] <= sync_AD[0];
|
||||
end
|
||||
end
|
||||
assign dac_request = sync_AD[1];
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Generator
|
||||
//------------------------------------------------------------
|
||||
generator #(
|
||||
.DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
.DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ZERO_LEVEL(ZERO_LEVEL)
|
||||
) generator_inst (
|
||||
.clk_in(dac_clk_in),
|
||||
.rst(dac_rst),
|
||||
.start(dac_start),
|
||||
|
||||
.clk_dac(clk_dac),
|
||||
.rst(rst_dac),
|
||||
.start(start),
|
||||
.pulse_width(pulse_width),
|
||||
.pulse_period(pulse_period),
|
||||
.pulse_height(pulse_height),
|
||||
.pulse_num(pulse_num),
|
||||
|
||||
.sample_done(sample_done),
|
||||
|
||||
.pulse(pulse),
|
||||
.pulse_height_out(pulse_height_out),
|
||||
.sample_req(sample_req_sync1)
|
||||
.dac_out(dac_signal),
|
||||
.request(dac_request),
|
||||
.done(dac_done)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
@@ -119,18 +143,15 @@ module sync_top
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE)
|
||||
) sampler_inst (
|
||||
.clk_in(adc_clk_in),
|
||||
.rst(adc_rst),
|
||||
|
||||
.data_in(data_in),
|
||||
.clk_in(clk_adc),
|
||||
.rst(rst_adc),
|
||||
.data_in(adc_signal),
|
||||
.out_of_range(out_of_range),
|
||||
|
||||
.smp_num(smp_num),
|
||||
.sample_req(sample_req),
|
||||
|
||||
.m_axis_tdata(m_axis_tdata),
|
||||
.m_axis_tvalid(m_axis_tvalid),
|
||||
.sample_done(sample_done_sync1)
|
||||
.request(adc_request),
|
||||
.done(adc_done)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -2,39 +2,50 @@
|
||||
|
||||
module tb_top;
|
||||
|
||||
localparam DAC_DATA_WIDTH = 14;
|
||||
localparam ADC_DATA_WIDTH = 12;
|
||||
localparam PACK_FACTOR = 1;
|
||||
localparam PROCESS_MODE = 0;
|
||||
//------------------------------------------------------------
|
||||
// Параметры
|
||||
//------------------------------------------------------------
|
||||
parameter string ZERO_LEVEL_PARAM = "logic"; // "logic" VS "true"
|
||||
parameter VERBOSE = 1;
|
||||
|
||||
localparam DAC_DATA_WIDTH = 14;
|
||||
localparam ADC_DATA_WIDTH = 12;
|
||||
localparam PACK_FACTOR = 1;
|
||||
localparam PROCESS_MODE = 0;
|
||||
localparam CLK_DAC_PERIOD = 8;
|
||||
localparam CLK_ADC_PERIOD = 15.385;
|
||||
localparam USE_DELAY_LINE = 0;
|
||||
localparam LOGIC_ZERO_LEVEL = 0; // DAC -5V for logic zero
|
||||
localparam VOLTAGE_ZERO_LEVEL = 2**(DAC_DATA_WIDTH-1); // DAC 0V for logic zero
|
||||
localparam ZERO_LEVEL = (ZERO_LEVEL_PARAM == "logic") ? LOGIC_ZERO_LEVEL : VOLTAGE_ZERO_LEVEL;
|
||||
|
||||
localparam CLOCK_DEVIATION = 3; // Maximum clock deviation of pulse stats
|
||||
|
||||
//------------------------------------------------------------
|
||||
// clocks / reset
|
||||
// Тактовые сигналы и сброс
|
||||
//------------------------------------------------------------
|
||||
logic adc_clk_in;
|
||||
logic adc_rst;
|
||||
|
||||
logic dac_clk_in;
|
||||
logic dac_rst;
|
||||
|
||||
logic clk_dac;
|
||||
logic rst_dac;
|
||||
logic clk_adc;
|
||||
logic rst_adc;
|
||||
//------------------------------------------------------------
|
||||
// control
|
||||
// Управление и конфиг
|
||||
//------------------------------------------------------------
|
||||
logic dac_start;
|
||||
|
||||
logic [31:0] pulse_width;
|
||||
logic [31:0] pulse_period;
|
||||
logic [DAC_DATA_WIDTH-1:0] pulse_height;
|
||||
logic [15:0] pulse_num;
|
||||
logic [31:0] smp_num;
|
||||
|
||||
logic [31:0] pulse_width;
|
||||
logic [31:0] pulse_period;
|
||||
logic [DAC_DATA_WIDTH-1:0] pulse_height;
|
||||
logic [15:0] pulse_num;
|
||||
logic [31:0] smp_num;
|
||||
//------------------------------------------------------------
|
||||
// outputs
|
||||
// Входы
|
||||
//------------------------------------------------------------
|
||||
logic [ADC_DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata;
|
||||
logic m_axis_tvalid;
|
||||
|
||||
integer valid_count;
|
||||
|
||||
reg out_of_range;
|
||||
//------------------------------------------------------------
|
||||
// Выходы
|
||||
//------------------------------------------------------------
|
||||
wire [ADC_DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata;
|
||||
wire m_axis_tvalid;
|
||||
//------------------------------------------------------------
|
||||
// DUT
|
||||
//------------------------------------------------------------
|
||||
@@ -42,127 +53,521 @@ module tb_top;
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE)
|
||||
.PROCESS_MODE(PROCESS_MODE),
|
||||
.ZERO_LEVEL(ZERO_LEVEL),
|
||||
.USE_DELAY_LINE(USE_DELAY_LINE)
|
||||
) dut (
|
||||
.adc_clk_in(adc_clk_in),
|
||||
.adc_rst(adc_rst),
|
||||
|
||||
.dac_clk_in(dac_clk_in),
|
||||
.dac_rst(dac_rst),
|
||||
|
||||
.dac_start(dac_start),
|
||||
|
||||
.clk_adc(clk_adc),
|
||||
.clk_dac(clk_dac),
|
||||
.rst_adc(rst_adc),
|
||||
.rst_dac(rst_dac),
|
||||
.start(dac_start),
|
||||
.pulse_width(pulse_width),
|
||||
.pulse_period(pulse_period),
|
||||
.pulse_height(pulse_height),
|
||||
.pulse_num(pulse_num),
|
||||
.smp_num(smp_num),
|
||||
|
||||
.m_axis_tdata(m_axis_tdata),
|
||||
.m_axis_tvalid(m_axis_tvalid)
|
||||
.m_axis_tvalid(m_axis_tvalid),
|
||||
.out_of_range(out_of_range)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// ADC clock
|
||||
//------------------------------------------------------------
|
||||
// Тактовые сигналы
|
||||
initial begin
|
||||
adc_clk_in = 1'b0;
|
||||
forever #5 adc_clk_in = ~adc_clk_in; // 100 MHz
|
||||
clk_adc = 0;
|
||||
forever #(CLK_ADC_PERIOD/2) clk_adc = ~clk_adc;
|
||||
end
|
||||
initial begin
|
||||
clk_dac = 0;
|
||||
forever #(CLK_DAC_PERIOD/2) clk_dac = ~clk_dac;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// DAC clock
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
dac_clk_in = 1'b0;
|
||||
forever #8 dac_clk_in = ~dac_clk_in; // slower domain
|
||||
end
|
||||
// === Таски для тестирования ===
|
||||
// Функция модуля
|
||||
function automatic real fabs(real val);
|
||||
return (val < 0.0) ? -val : val;
|
||||
endfunction
|
||||
|
||||
//------------------------------------------------------------
|
||||
// monitor output stream
|
||||
//------------------------------------------------------------
|
||||
always @(posedge adc_clk_in) begin
|
||||
if (m_axis_tvalid) begin
|
||||
valid_count = valid_count + 1;
|
||||
`define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
$display("[%0t] VALID: data=%0d",
|
||||
$time,
|
||||
m_axis_tdata);
|
||||
// Таска сброса DAC DUT
|
||||
task automatic reset_dut_dac(
|
||||
input int rst_duration // сколько тактов держать сброс
|
||||
);
|
||||
@(negedge clk_dac);
|
||||
rst_dac <= 1;
|
||||
repeat(rst_duration) @(negedge clk_dac);
|
||||
rst_dac <= 0;
|
||||
endtask
|
||||
|
||||
// Таска сброса ADC DUT
|
||||
task automatic reset_dut_adc(
|
||||
input int rst_duration // сколько тактов держать сброс
|
||||
);
|
||||
@(negedge clk_adc);
|
||||
rst_adc <= 1;
|
||||
repeat(rst_duration) @(negedge clk_adc);
|
||||
rst_adc <= 0;
|
||||
endtask
|
||||
|
||||
// Таска запуска DUT
|
||||
task automatic start_dut(
|
||||
input int start_duration // сколько тактов держать импульс
|
||||
);
|
||||
@(negedge clk_dac); // to make signal stable
|
||||
dac_start <= 1;
|
||||
repeat(start_duration) @(negedge clk_dac);
|
||||
dac_start <= 0;
|
||||
endtask
|
||||
|
||||
// Таска конфигурации DUT
|
||||
task automatic set_config(
|
||||
input logic [31:0] w, // ширина импульса
|
||||
input logic [31:0] p, // период импульса
|
||||
input logic [15:0] n, // количество импульсов
|
||||
input logic [DAC_DATA_WIDTH-1:0] h, // высота импульса
|
||||
input logic [31:0] sn // число сэмплов
|
||||
);
|
||||
// Задаем конфигурационные регистры
|
||||
pulse_width <= w;
|
||||
pulse_period <= p;
|
||||
pulse_num <= n;
|
||||
pulse_height <= h;
|
||||
smp_num <= sn;
|
||||
endtask
|
||||
|
||||
// Основная таска проверки DUT
|
||||
task automatic run_test_case(
|
||||
input int pulse_width,
|
||||
input int pulse_period,
|
||||
input int pulse_height,
|
||||
input int pulse_num,
|
||||
input int sample_num,
|
||||
input bit skip_reset,
|
||||
input bit randomize_start_timing,
|
||||
input bit out_of_range_val,
|
||||
input bit randomize_out_of_range
|
||||
);
|
||||
int error_flag = 0;
|
||||
int start_hold_time = 1;
|
||||
realtime sync_start_time, pulse_start_time, pulse_update_val_time;
|
||||
realtime sync_time_stats[$], pulse_width_time_stats[$], pulse_period_time_stats[$], pulse_delay_time_stats[$];
|
||||
realtime avearge_pulse_delay, average_pulse_width, average_pulse_period, average_sync_time;
|
||||
|
||||
out_of_range = out_of_range_val;
|
||||
|
||||
if (VERBOSE >= 2) begin
|
||||
$display("[TB] -run_test_case- Starting test case");
|
||||
end
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// test
|
||||
//------------------------------------------------------------
|
||||
if (randomize_out_of_range)
|
||||
fork
|
||||
begin : randomize_out_of_range_proc
|
||||
forever begin
|
||||
@(posedge clk_adc);
|
||||
out_of_range = $urandom_range(0, 1);
|
||||
end
|
||||
end
|
||||
join_none
|
||||
|
||||
if (!skip_reset)
|
||||
fork
|
||||
reset_dut_adc(1);
|
||||
reset_dut_dac(1);
|
||||
join
|
||||
|
||||
set_config(
|
||||
.w(pulse_width),
|
||||
.p(pulse_period),
|
||||
.n(pulse_num),
|
||||
.h(pulse_height),
|
||||
.sn(sample_num)
|
||||
);
|
||||
@(posedge clk_dac);
|
||||
@(posedge clk_dac);
|
||||
|
||||
if (randomize_start_timing)
|
||||
start_hold_time = $urandom_range(1, 15);
|
||||
fork // warning: check not forever
|
||||
start_dut(start_hold_time);
|
||||
begin
|
||||
@(posedge clk_dac);
|
||||
// старт первой синхронизации
|
||||
sync_start_time = $realtime;
|
||||
end
|
||||
join_none
|
||||
|
||||
if (VERBOSE >= 2) begin
|
||||
$display("[TB] -run_test_case- Starting pulse generation");
|
||||
end
|
||||
|
||||
for (int i = 0; i < pulse_num; i++) begin
|
||||
if (VERBOSE >= 3) begin
|
||||
$display("[TB] -run_test_case- Start sync for pulse #%d", i);
|
||||
end
|
||||
@(posedge m_axis_tvalid);
|
||||
if (VERBOSE >= 3) begin
|
||||
$display("[TB] -run_test_case- Found valid pulse response data positive front");
|
||||
end
|
||||
// Старт цикла. Завершение синхронизации
|
||||
sync_time_stats.push_back($realtime - sync_start_time);
|
||||
pulse_start_time = $realtime;
|
||||
|
||||
fork
|
||||
// Поток будет запущен для ненулевых импульсов и гарантированно завершится как только зафиксирует статистику импульса
|
||||
// Начало импульса
|
||||
if (pulse_height != ZERO_LEVEL && pulse_width != 0) begin
|
||||
if (VERBOSE >= 4) begin
|
||||
$display("[TB] -run_test_case- Wait until pulse become high");
|
||||
end
|
||||
wait(m_axis_tdata != ZERO_LEVEL);
|
||||
// Фактическое начало импульса. Поступление высокого уровня
|
||||
pulse_update_val_time = $realtime;
|
||||
pulse_delay_time_stats.push_back(pulse_update_val_time - pulse_start_time);
|
||||
|
||||
// Проверим что высота импульса совпала с заданной. Т.к. OTR != 0 влияет на выходные данные сэмплера, то не будем проверять такие случаи.
|
||||
@(posedge clk_adc);
|
||||
#1.5; // Ожидание завершения переходных процессов
|
||||
// Будем считать что из-за OTR данные изменились (по условию OTR + MSB), проверка пропускается, т.к. сложно понять точное значение OTR в момент обработки данных от tdata
|
||||
if (m_axis_tdata != (pulse_height >> 2) && (randomize_out_of_range || out_of_range_val)) begin
|
||||
$display("[ERROR] -run_test_case- Wrong pulse height: %d. Must be: %d", m_axis_tdata, pulse_height >> 2);
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (VERBOSE >= 4) begin
|
||||
$display("[TB] -run_test_case- Wait until pulse become low");
|
||||
end
|
||||
wait(m_axis_tdata == ZERO_LEVEL);
|
||||
pulse_width_time_stats.push_back($realtime - pulse_update_val_time);
|
||||
end
|
||||
// Конец импульса
|
||||
join_none
|
||||
|
||||
@(negedge m_axis_tvalid);
|
||||
if (VERBOSE >= 3) begin
|
||||
$display("[TB] -run_test_case- Found valid pulse response data negative front");
|
||||
end
|
||||
// Завершение цикла. Старт синхронизации
|
||||
pulse_period_time_stats.push_back($realtime - pulse_start_time);
|
||||
sync_start_time = $realtime;
|
||||
end
|
||||
|
||||
if (VERBOSE >= 2) begin
|
||||
$display("[TB] -run_test_case- Stop pulse generation");
|
||||
end
|
||||
|
||||
fork // Проверка с таймаутом на лишние циклы
|
||||
@(posedge m_axis_tvalid);
|
||||
repeat(30) @(posedge clk_adc);
|
||||
join_any
|
||||
if (m_axis_tvalid == 1) begin
|
||||
$display("[ERROR] -run_test_case- Extra pulse cycle num. More than must be.");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (VERBOSE >= 2) begin
|
||||
$display("[TB] -run_test_case- Exit waiting via timeout");
|
||||
end
|
||||
|
||||
if (randomize_out_of_range) begin
|
||||
disable randomize_out_of_range_proc;
|
||||
if (VERBOSE >= 2) begin
|
||||
$display("[TB] -run_test_case- Stop randomize_out_of_range_proc");
|
||||
end
|
||||
end
|
||||
out_of_range = 0;
|
||||
|
||||
// Проверка по статистике. Подсчет средних значений
|
||||
if (pulse_delay_time_stats.size() != pulse_num && pulse_height != ZERO_LEVEL && pulse_width != 0 && !(randomize_out_of_range || out_of_range_val)) begin // Detected with pulse level. Skip if pulse level undetectable
|
||||
$display("[ERROR] -run_test_case- Size of pulse_delay_time_stats samples not equal to pulse_num: %d VS %d", pulse_delay_time_stats.size(), pulse_num);
|
||||
$finish;
|
||||
end
|
||||
if (pulse_width_time_stats.size() != pulse_num && pulse_height != ZERO_LEVEL && pulse_width != 0 && !(randomize_out_of_range || out_of_range_val)) begin // Detected with pulse level. Skip if pulse level undetectable
|
||||
$display("[ERROR] -run_test_case- Size of pulse_width_time_stats samples not equal to pulse_num: %d VS %d", pulse_width_time_stats.size(), pulse_num);
|
||||
$finish;
|
||||
end
|
||||
if (pulse_period_time_stats.size() != pulse_num) begin
|
||||
$display("[ERROR] -run_test_case- Size of pulse_period_time_stats samples not equal to pulse_num: %d VS %d", pulse_period_time_stats.size(), pulse_num);
|
||||
$finish;
|
||||
end
|
||||
if (sync_time_stats.size() != pulse_num) begin
|
||||
$display("[ERROR] -run_test_case- Size of sync_time_stats samples not equal to pulse_num: %d VS %d", sync_time_stats.size(), pulse_num);
|
||||
$finish;
|
||||
end
|
||||
|
||||
avearge_pulse_delay = 0;
|
||||
foreach (pulse_delay_time_stats[i])
|
||||
avearge_pulse_delay += pulse_delay_time_stats[i];
|
||||
avearge_pulse_delay /= pulse_num;
|
||||
|
||||
average_pulse_width = 0;
|
||||
foreach (pulse_width_time_stats[i])
|
||||
average_pulse_width += pulse_width_time_stats[i];
|
||||
average_pulse_width /= pulse_num;
|
||||
|
||||
average_pulse_period = 0;
|
||||
foreach (pulse_period_time_stats[i])
|
||||
average_pulse_period += pulse_period_time_stats[i];
|
||||
average_pulse_period /= pulse_num;
|
||||
|
||||
average_sync_time = 0;
|
||||
foreach (sync_time_stats[i])
|
||||
average_sync_time += sync_time_stats[i];
|
||||
average_sync_time /= pulse_num;
|
||||
|
||||
if (VERBOSE >= 1) begin
|
||||
$display("[TB] -run_test_case- Pulse test stats:\n\tavearge_pulse_delay: %0.3f\n\taverage_pulse_width: %0.3f\n\taverage_pulse_period: %0.3f\n\taverage_sync_time: %0.3f", avearge_pulse_delay, average_pulse_width, average_pulse_period, average_sync_time);
|
||||
end
|
||||
|
||||
if (avearge_pulse_delay > CLOCK_DEVIATION * CLK_ADC_PERIOD) begin
|
||||
$display("[ERROR] -run_test_case- avearge_pulse_delay too big: %0.3f", avearge_pulse_delay);
|
||||
error_flag = 1;
|
||||
end
|
||||
if (fabs(average_pulse_width - pulse_width * CLK_DAC_PERIOD * (pulse_height != ZERO_LEVEL)) > CLOCK_DEVIATION * CLK_ADC_PERIOD && sample_num * CLK_ADC_PERIOD >= pulse_width * CLK_DAC_PERIOD) begin
|
||||
$display("[ERROR] -run_test_case- average_pulse_width deviates from choosen pulse_width. Deviation: %0.3f > %0.3f ns", fabs(average_pulse_width - pulse_width * CLK_DAC_PERIOD), CLOCK_DEVIATION * CLK_ADC_PERIOD);
|
||||
error_flag = 1;
|
||||
end
|
||||
if (fabs(average_pulse_period - sample_num * CLK_ADC_PERIOD) > CLOCK_DEVIATION * CLK_ADC_PERIOD) begin
|
||||
$display("[ERROR] -run_test_case- average_pulse_period deviates from choosen pulse_width. Deviation: %0.3f > %0.3f ns", fabs(average_pulse_period - sample_num * CLK_ADC_PERIOD), CLOCK_DEVIATION * CLK_ADC_PERIOD);
|
||||
error_flag = 1;
|
||||
end
|
||||
|
||||
if (VERBOSE >= 2) begin
|
||||
$display("[TB] -run_test_case- Pass error processing");
|
||||
end
|
||||
|
||||
if (error_flag)
|
||||
$finish;
|
||||
|
||||
if (VERBOSE >= 2) begin
|
||||
$display("[TB] -run_test_case- Passed checks");
|
||||
end
|
||||
endtask
|
||||
// Таска
|
||||
|
||||
// --- ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ ---
|
||||
initial begin
|
||||
$display("[TB] Tests start");
|
||||
|
||||
adc_rst = 1'b1;
|
||||
dac_rst = 1'b1;
|
||||
|
||||
dac_start = 1'b0;
|
||||
|
||||
// Инициализация
|
||||
dac_start = 0;
|
||||
pulse_width = 0;
|
||||
pulse_period = 0;
|
||||
pulse_height = 0;
|
||||
pulse_num = 0;
|
||||
smp_num = 0;
|
||||
out_of_range = 0;
|
||||
rst_adc = 0;
|
||||
rst_dac = 0;
|
||||
|
||||
valid_count = 0;
|
||||
#100; // init
|
||||
|
||||
//--------------------------------------------------------
|
||||
// reset
|
||||
//--------------------------------------------------------
|
||||
repeat (10) @(posedge adc_clk_in);
|
||||
repeat (10) @(posedge dac_clk_in);
|
||||
$display("[TB] Test 1. Simple test. (1/4)");
|
||||
run_test_case(
|
||||
.pulse_width(50),
|
||||
.pulse_period(125),
|
||||
.pulse_height(2**DAC_DATA_WIDTH-1),
|
||||
.pulse_num(5),
|
||||
.sample_num(65),
|
||||
.skip_reset(0),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(0),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
$display("[TB] Test 1. Simple test. (2/4)");
|
||||
run_test_case(
|
||||
.pulse_width(25),
|
||||
.pulse_period(125),
|
||||
.pulse_height(2**(ADC_DATA_WIDTH-1)),
|
||||
.pulse_num(10),
|
||||
.sample_num(65),
|
||||
.skip_reset(1),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(0),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
$display("[TB] Test 1. Simple test. (3/4)");
|
||||
run_test_case(
|
||||
.pulse_width(10),
|
||||
.pulse_period(50),
|
||||
.pulse_height(ZERO_LEVEL),
|
||||
.pulse_num(4),
|
||||
.sample_num(25),
|
||||
.skip_reset(1),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(0),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
|
||||
adc_rst = 1'b0;
|
||||
dac_rst = 1'b0;
|
||||
$display("[TB] Test 1. Simple test. (4/4)");
|
||||
run_test_case(
|
||||
.pulse_width(25),
|
||||
.pulse_period(125),
|
||||
.pulse_height(2**(DAC_DATA_WIDTH-1)),
|
||||
.pulse_num(10),
|
||||
.sample_num(65),
|
||||
.skip_reset(1),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(0),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
$display("[TB] Test 1 complete");
|
||||
|
||||
$display("[TB] Test 2. Edge cases. Pulse width 0%%. (1/7)");
|
||||
run_test_case(
|
||||
.pulse_width(0),
|
||||
.pulse_period(125),
|
||||
.pulse_height(2**(ADC_DATA_WIDTH-1)),
|
||||
.pulse_num(5),
|
||||
.sample_num(65),
|
||||
.skip_reset(1),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(0),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
$display("[TB] Test 2. Edge cases. Pulse width 100%%. (2/7)");
|
||||
run_test_case(
|
||||
.pulse_width(10),
|
||||
.pulse_period(10),
|
||||
.pulse_height(2**(ADC_DATA_WIDTH-1)),
|
||||
.pulse_num(5),
|
||||
.sample_num(65),
|
||||
.skip_reset(1),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(0),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
$display("[TB] Test 2. Edge cases. Pulse height == ZERO_LEVEL. (3/7)");
|
||||
run_test_case(
|
||||
.pulse_width(10),
|
||||
.pulse_period(125),
|
||||
.pulse_height(ZERO_LEVEL),
|
||||
.pulse_num(5),
|
||||
.sample_num(65),
|
||||
.skip_reset(1),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(0),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
$display("[TB] Test 2. Edge cases. Pulse num == 0. (4/7)");
|
||||
run_test_case(
|
||||
.pulse_width(10),
|
||||
.pulse_period(125),
|
||||
.pulse_height(2**(ADC_DATA_WIDTH-3)),
|
||||
.pulse_num(0),
|
||||
.sample_num(65),
|
||||
.skip_reset(1),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(0),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
|
||||
repeat (5) @(posedge dac_clk_in);
|
||||
$display("[TB] Test 2. Edge cases. Sample num time << Pulse width time. (5/7)");
|
||||
run_test_case(
|
||||
.pulse_width(10),
|
||||
.pulse_period(125),
|
||||
.pulse_height(2**(ADC_DATA_WIDTH-1)),
|
||||
.pulse_num(5),
|
||||
.sample_num(2),
|
||||
.skip_reset(1),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(0),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
|
||||
//--------------------------------------------------------
|
||||
// config
|
||||
//--------------------------------------------------------
|
||||
pulse_width = 32'd3;
|
||||
pulse_period = 32'd8;
|
||||
pulse_height = 14'd200;
|
||||
pulse_num = 16'd4;
|
||||
smp_num = 32'd8;
|
||||
// Ожидание окончания работы генератора. Т.к. конец работы определяется по tvalid сэмплера, а он завершается сильно раньше. Чтобы не пропустить start следующей таски, ждем
|
||||
wait(dut.generator_inst.enable == 0);
|
||||
#50;
|
||||
|
||||
//--------------------------------------------------------
|
||||
// start
|
||||
//--------------------------------------------------------
|
||||
@(posedge dac_clk_in);
|
||||
dac_start = 1'b1;
|
||||
$display("[TB] Test 2. Edge cases. Sample num == 0. (6/7)");
|
||||
// Запустим в работу вручную, т.к. run_test_case обязательно ждет pulse num циклов. Детекция цикла производится по активности сэплера. Ее не должно быть при sample num = 0
|
||||
set_config(
|
||||
.w(10),
|
||||
.p(125),
|
||||
.h(2**(ADC_DATA_WIDTH-1)),
|
||||
.n(5),
|
||||
.sn(0)
|
||||
);
|
||||
start_dut(3);
|
||||
fork
|
||||
begin : wait_sampler_active_proc
|
||||
@(posedge m_axis_tvalid);
|
||||
$display("[ERROR] Sampler active with sample num == 0");
|
||||
$finish;
|
||||
end
|
||||
begin
|
||||
@(negedge dut.generator_inst.enable);
|
||||
end
|
||||
join_any
|
||||
disable wait_sampler_active_proc;
|
||||
repeat(30) @(posedge clk_adc);
|
||||
|
||||
// Данный тест должен приводить к тому, что сэмплер будет давать крайние значения вместо заданного pulse height из-за OTR=1
|
||||
// Дописать авто тест
|
||||
$display("[TB] Test 2. Edge cases. OTR == 1. (7/7)");
|
||||
run_test_case(
|
||||
.pulse_width(10),
|
||||
.pulse_period(125),
|
||||
.pulse_height(10), // goes to 0x0..
|
||||
.pulse_num(5),
|
||||
.sample_num(65),
|
||||
.skip_reset(1),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(1),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
$display("[TB] Test 2. Edge cases. OTR == 1. (7-2/7)");
|
||||
run_test_case(
|
||||
.pulse_width(10),
|
||||
.pulse_period(125),
|
||||
.pulse_height(14'b11010000000000), // goes to 0xff..
|
||||
.pulse_num(5),
|
||||
.sample_num(65),
|
||||
.skip_reset(1),
|
||||
.randomize_start_timing(1),
|
||||
.out_of_range_val(1),
|
||||
.randomize_out_of_range(0)
|
||||
);
|
||||
$display("[TB] Test 2 complete");
|
||||
|
||||
@(posedge dac_clk_in);
|
||||
dac_start = 1'b0;
|
||||
$display("[TB] Test 3. Random tests");
|
||||
for (int i = 0; i < 100; i++) begin
|
||||
int r_w, r_p, r_n, r_h, r_sn;
|
||||
bit r_skip, r_otr, r_otr_rand;
|
||||
|
||||
$display("==================================");
|
||||
$display("TEST START");
|
||||
$display("==================================");
|
||||
// Генерируем параметры
|
||||
r_p = $urandom_range(50, 150); // Период от 5 до 50
|
||||
r_w = $urandom_range(10, r_p); // Ширина не больше периода
|
||||
r_n = $urandom_range(1, 10); // Количество импульсов
|
||||
r_h = $urandom_range(0, 2**(`MIN(ADC_DATA_WIDTH, DAC_DATA_WIDTH))-1); // Высота импульса
|
||||
r_sn = $urandom_range(2, 40); // Число сэмплов
|
||||
r_skip = $urandom_range(0, 1); // Случайный сброс (0 - сброс, 1 - пропуск)
|
||||
r_otr = 0; // Out Of Range стартовое значение
|
||||
r_otr_rand = 0; // Сделать OTR случайным
|
||||
|
||||
//--------------------------------------------------------
|
||||
// wait
|
||||
//--------------------------------------------------------
|
||||
repeat (600) @(posedge adc_clk_in);
|
||||
if (VERBOSE >= 1)
|
||||
$display("[TB] --- Test #%0d (Config: W=%0d, P=%0d, N=%0d, H=%0d, SN=%0d, SkipReset=%0b) ---",
|
||||
i+1, r_w, r_p, r_n, r_h, r_sn, r_skip);
|
||||
|
||||
run_test_case(
|
||||
.pulse_width(r_w),
|
||||
.pulse_period(r_p),
|
||||
.pulse_height(r_h),
|
||||
.pulse_num(r_n),
|
||||
.sample_num(r_sn),
|
||||
.skip_reset(r_skip),
|
||||
.randomize_start_timing(0),
|
||||
.out_of_range_val(r_otr),
|
||||
.randomize_out_of_range(r_otr_rand)
|
||||
);
|
||||
|
||||
//--------------------------------------------------------
|
||||
// check
|
||||
//--------------------------------------------------------
|
||||
if (valid_count > 0) begin
|
||||
$display("==================================");
|
||||
$display("TEST PASSED");
|
||||
$display("valid_count = %0d", valid_count);
|
||||
$display("==================================");
|
||||
wait(dut.generator_inst.enable == 0); // Проверка на завершение работы
|
||||
#50;
|
||||
end
|
||||
else begin
|
||||
$display("==================================");
|
||||
$display("TEST FAILED");
|
||||
$display("No valid output detected");
|
||||
$display("==================================");
|
||||
end
|
||||
|
||||
$display("[TB] Test 3 complete");
|
||||
|
||||
$display("[TB] ALL PASSED");
|
||||
$display("[TB] Maximum clock deviation of stats %0.2f", CLOCK_DEVIATION);
|
||||
$finish;
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// SystemVerilog interface wrapper around alexforencich/verilog-axi axi_dma.v.
|
||||
//
|
||||
// AXI memory, AXI-Stream data, DMA descriptor, and DMA status channels are all
|
||||
// exposed through compact interfaces. The original Forencich core remains
|
||||
// untouched and is connected through local flat wires.
|
||||
|
||||
`default_nettype none
|
||||
import dma_reg_pkg::*;
|
||||
|
||||
// DMA Specific wrappers & converters
|
||||
module axi_dma_wrapper #(
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0
|
||||
)(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
|
||||
axis_if.slave s_axis_read_desc,
|
||||
|
||||
axis_if.master m_axis_read_desc_status,
|
||||
|
||||
axis_if.master m_axis_read_data,
|
||||
|
||||
axis_if.slave s_axis_write_desc,
|
||||
|
||||
axis_if.master m_axis_write_desc_status,
|
||||
|
||||
axis_if.slave s_axis_write_data,
|
||||
|
||||
axi4_if.master m_axi
|
||||
);
|
||||
|
||||
dma_read_desc_t read_desc;
|
||||
assign read_desc = dma_read_desc_t'(s_axis_read_desc.req.t.data);
|
||||
|
||||
|
||||
dma_write_desc_t write_desc;
|
||||
assign write_desc = dma_write_desc_t'(s_axis_write_desc.req.t.data);
|
||||
|
||||
|
||||
dma_read_status_t read_status;
|
||||
assign m_axis_read_desc_status.req.t.data = read_status;
|
||||
logic m_axis_read_desc_status_valid;
|
||||
assign m_axis_read_desc_status.req.t.valid = m_axis_read_desc_status_valid;
|
||||
|
||||
|
||||
|
||||
dma_write_status_t write_status;
|
||||
assign m_axis_write_desc_status.req.t.data = write_status;
|
||||
logic m_axis_write_desc_status_valid;
|
||||
assign m_axis_write_desc_status.req.t.valid = m_axis_write_desc_status_valid;
|
||||
|
||||
|
||||
// Original DMA: flat ports only.
|
||||
axi_dma #(
|
||||
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
|
||||
.AXI_ADDR_WIDTH (dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.AXI_STRB_WIDTH (AXI_STRB_WIDTH),
|
||||
.AXI_ID_WIDTH (AXI_ID_WIDTH),
|
||||
.AXI_MAX_BURST_LEN (AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH (AXIS_DATA_WIDTH),
|
||||
.AXIS_KEEP_ENABLE (AXIS_KEEP_ENABLE),
|
||||
.AXIS_KEEP_WIDTH (AXIS_KEEP_WIDTH),
|
||||
.AXIS_LAST_ENABLE (AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE (AXIS_ID_ENABLE),
|
||||
.AXIS_ID_WIDTH (dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.AXIS_DEST_ENABLE (AXIS_DEST_ENABLE),
|
||||
.AXIS_DEST_WIDTH (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.AXIS_USER_ENABLE (AXIS_USER_ENABLE),
|
||||
.AXIS_USER_WIDTH (dma_reg_pkg::AXIS_USER_WIDTH),
|
||||
.LEN_WIDTH (dma_reg_pkg::LEN_WIDTH),
|
||||
.TAG_WIDTH (dma_reg_pkg::TAG_WIDTH),
|
||||
.ENABLE_SG (ENABLE_SG),
|
||||
.ENABLE_UNALIGNED (ENABLE_UNALIGNED)
|
||||
) i_axi_dma (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.s_axis_read_desc_addr (read_desc.addr),
|
||||
.s_axis_read_desc_len (read_desc.len),
|
||||
.s_axis_read_desc_tag (read_desc.tag),
|
||||
.s_axis_read_desc_id (read_desc.id),
|
||||
.s_axis_read_desc_dest (read_desc.dest),
|
||||
.s_axis_read_desc_user (read_desc.user),
|
||||
.s_axis_read_desc_valid (s_axis_read_desc.req.t.valid),
|
||||
.s_axis_read_desc_ready (s_axis_read_desc.resp.ready),
|
||||
|
||||
.m_axis_read_desc_status_tag (read_status.tag),
|
||||
.m_axis_read_desc_status_error (read_status.error),
|
||||
.m_axis_read_desc_status_valid (m_axis_read_desc_status_valid),
|
||||
|
||||
.m_axis_read_data_tdata (m_axis_read_data.req.t.data),
|
||||
.m_axis_read_data_tkeep (m_axis_read_data.req.t.keep),
|
||||
.m_axis_read_data_tvalid (m_axis_read_data.req.t.valid),
|
||||
.m_axis_read_data_tready (m_axis_read_data.resp.ready),
|
||||
.m_axis_read_data_tlast (m_axis_read_data.req.t.last),
|
||||
.m_axis_read_data_tid (m_axis_read_data.req.t.id),
|
||||
.m_axis_read_data_tdest (m_axis_read_data.req.t.dest),
|
||||
.m_axis_read_data_tuser (m_axis_read_data.req.t.user),
|
||||
|
||||
.s_axis_write_desc_addr (write_desc.addr),
|
||||
.s_axis_write_desc_len (write_desc.len),
|
||||
.s_axis_write_desc_tag (write_desc.tag),
|
||||
.s_axis_write_desc_valid (s_axis_write_desc.req.t.valid),
|
||||
.s_axis_write_desc_ready (s_axis_write_desc.resp.ready),
|
||||
|
||||
.m_axis_write_desc_status_len (write_status.len),
|
||||
.m_axis_write_desc_status_tag (write_status.tag),
|
||||
.m_axis_write_desc_status_id (write_status.id),
|
||||
.m_axis_write_desc_status_dest (write_status.dest),
|
||||
.m_axis_write_desc_status_user (write_status.user),
|
||||
.m_axis_write_desc_status_error (write_status.error),
|
||||
.m_axis_write_desc_status_valid (m_axis_write_desc_status_valid),
|
||||
|
||||
.s_axis_write_data_tdata (s_axis_write_data.req.t.data),
|
||||
.s_axis_write_data_tkeep (s_axis_write_data.req.t.keep),
|
||||
.s_axis_write_data_tvalid (s_axis_write_data.req.t.valid),
|
||||
.s_axis_write_data_tready (s_axis_write_data.resp.ready),
|
||||
.s_axis_write_data_tlast (s_axis_write_data.req.t.last),
|
||||
.s_axis_write_data_tid (s_axis_write_data.req.t.id),
|
||||
.s_axis_write_data_tdest (s_axis_write_data.req.t.dest),
|
||||
.s_axis_write_data_tuser (s_axis_write_data.req.t.user),
|
||||
|
||||
.m_axi_awid (m_axi.req.aw.id),
|
||||
.m_axi_awaddr (m_axi.req.aw.addr),
|
||||
.m_axi_awlen (m_axi.req.aw.len),
|
||||
.m_axi_awsize (m_axi.req.aw.size),
|
||||
.m_axi_awburst (m_axi.req.aw.burst),
|
||||
.m_axi_awlock (m_axi.req.aw.lock),
|
||||
.m_axi_awcache (m_axi.req.aw.cache),
|
||||
.m_axi_awprot (m_axi.req.aw.prot),
|
||||
.m_axi_awvalid (m_axi.req.aw.valid),
|
||||
.m_axi_awready (m_axi.resp.aw_ready),
|
||||
|
||||
.m_axi_wdata (m_axi.req.w.data),
|
||||
.m_axi_wstrb (m_axi.req.w.strb),
|
||||
.m_axi_wlast ( m_axi.req.w.last),
|
||||
.m_axi_wvalid (m_axi.req.w.valid),
|
||||
.m_axi_wready (m_axi.resp.w_ready),
|
||||
|
||||
.m_axi_bid (m_axi.resp.b.id),
|
||||
.m_axi_bresp (m_axi.resp.b.resp),
|
||||
.m_axi_bvalid (m_axi.resp.b.valid),
|
||||
.m_axi_bready (m_axi.req.b_ready),
|
||||
|
||||
.m_axi_arid (m_axi.req.ar.id),
|
||||
.m_axi_araddr (m_axi.req.ar.addr),
|
||||
.m_axi_arlen (m_axi.req.ar.len),
|
||||
.m_axi_arsize (m_axi.req.ar.size),
|
||||
.m_axi_arburst (m_axi.req.ar.burst),
|
||||
.m_axi_arlock (m_axi.req.ar.lock),
|
||||
.m_axi_arcache (m_axi.req.ar.cache),
|
||||
.m_axi_arprot (m_axi.req.ar.prot),
|
||||
.m_axi_arvalid (m_axi.req.ar.valid),
|
||||
.m_axi_arready (m_axi.resp.ar_ready),
|
||||
|
||||
.m_axi_rid (m_axi.resp.r.id),
|
||||
.m_axi_rdata (m_axi.resp.r.data),
|
||||
.m_axi_rresp (m_axi.resp.r.resp),
|
||||
.m_axi_rlast (m_axi.resp.r.last),
|
||||
.m_axi_rvalid (m_axi.resp.r.valid),
|
||||
.m_axi_rready (m_axi.req.r_ready),
|
||||
|
||||
.read_enable (1'b1),
|
||||
.write_enable (1'b1),
|
||||
.write_abort (1'b0)
|
||||
);
|
||||
|
||||
|
||||
endmodule : axi_dma_wrapper
|
||||
|
||||
`default_nettype wire
|
||||
@@ -0,0 +1,60 @@
|
||||
module axi_ram_wrapper
|
||||
#(
|
||||
parameter int unsigned DATA_WIDTH = 32,
|
||||
parameter int unsigned ADDR_WIDTH = 16,
|
||||
parameter int unsigned ID_WIDTH = 8,
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0
|
||||
)
|
||||
(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
axi4_if.slave s_axi
|
||||
);
|
||||
|
||||
axi_ram
|
||||
#(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.ADDR_WIDTH(ADDR_WIDTH),
|
||||
.ID_WIDTH(ID_WIDTH),
|
||||
.PIPELINE_OUTPUT(PIPELINE_OUTPUT)
|
||||
) axi_ram_inst
|
||||
(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axi_awid(s_axi.req.aw.id),
|
||||
.s_axi_awaddr(s_axi.req.aw.addr),
|
||||
.s_axi_awlen(s_axi.req.aw.len),
|
||||
.s_axi_awsize(s_axi.req.aw.size),
|
||||
.s_axi_awburst(s_axi.req.aw.burst),
|
||||
.s_axi_awlock(s_axi.req.aw.lock),
|
||||
.s_axi_awcache(s_axi.req.aw.cache),
|
||||
.s_axi_awprot(s_axi.req.aw.prot),
|
||||
.s_axi_awvalid(s_axi.req.aw.valid),
|
||||
.s_axi_awready(s_axi.resp.aw_ready),
|
||||
.s_axi_wdata(s_axi.req.w.data),
|
||||
.s_axi_wstrb(s_axi.req.w.strb),
|
||||
.s_axi_wlast(s_axi.req.w.last),
|
||||
.s_axi_wvalid(s_axi.req.w.valid),
|
||||
.s_axi_wready(s_axi.resp.w_ready),
|
||||
.s_axi_bid(s_axi.resp.b.id),
|
||||
.s_axi_bresp(s_axi.resp.b.resp),
|
||||
.s_axi_bvalid(s_axi.resp.b.valid),
|
||||
.s_axi_bready(s_axi.req.b_ready),
|
||||
.s_axi_arid(s_axi.req.ar.id),
|
||||
.s_axi_araddr(s_axi.req.ar.addr),
|
||||
.s_axi_arlen(s_axi.req.ar.len),
|
||||
.s_axi_arsize(s_axi.req.ar.size),
|
||||
.s_axi_arburst(s_axi.req.ar.burst),
|
||||
.s_axi_arlock(s_axi.req.ar.lock),
|
||||
.s_axi_arcache(s_axi.req.ar.cache),
|
||||
.s_axi_arprot(s_axi.req.ar.prot),
|
||||
.s_axi_arvalid(s_axi.req.ar.valid),
|
||||
.s_axi_arready(s_axi.resp.ar_ready),
|
||||
.s_axi_rid(s_axi.resp.r.id),
|
||||
.s_axi_rdata(s_axi.resp.r.data),
|
||||
.s_axi_rresp(s_axi.resp.r.resp),
|
||||
.s_axi_rlast(s_axi.resp.r.last),
|
||||
.s_axi_rvalid(s_axi.resp.r.valid),
|
||||
.s_axi_rready(s_axi.req.r_ready)
|
||||
);
|
||||
endmodule
|
||||
@@ -0,0 +1,193 @@
|
||||
import dma_reg_pkg::*;
|
||||
|
||||
module wrapper_controller_dma
|
||||
#(
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
|
||||
parameter int unsigned DAC_DATA_WIDTH = 12,
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0
|
||||
)
|
||||
(
|
||||
input logic ctrl_clk,
|
||||
input logic dac_clk_in,
|
||||
input logic adc_clk_in,
|
||||
input logic rst_n,
|
||||
axi4l_if.slave s_axil,
|
||||
|
||||
// adc_clk_in domain
|
||||
input logic finish,
|
||||
output logic [31:0] adc_window_size,
|
||||
|
||||
// dac_clk_in domain outputs
|
||||
output logic [31:0] dac_pulse_width,
|
||||
output logic [31:0] dac_pulse_period,
|
||||
output logic [DAC_DATA_WIDTH-1:0] dac_pulse_height,
|
||||
output logic [15:0] dac_pulse_num,
|
||||
|
||||
// adc_clk_in domain outputs
|
||||
output logic [31:0] adc_pulse_period,
|
||||
output logic [15:0] adc_pulse_num,
|
||||
|
||||
// pulse outputs
|
||||
output logic dac_start,
|
||||
output logic adc_start,
|
||||
output logic dac_rst,
|
||||
output logic adc_rst,
|
||||
|
||||
axis_if.master m_axis_read_data,
|
||||
axis_if.slave s_axis_write_data
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_read_status_t)),
|
||||
.KEEP_W(($bits(dma_read_status_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) s_axis_status_read (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_write_status_t)),
|
||||
.KEEP_W(($bits(dma_write_status_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) s_axis_status_write (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_read_desc_t)),
|
||||
.KEEP_W(($bits(dma_read_desc_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_desc_read (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_write_desc_t)),
|
||||
.KEEP_W(($bits(dma_write_desc_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_desc_write (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
controller_wrapper_axil
|
||||
#(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W),
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
)
|
||||
controller_wrapper_axil_inst
|
||||
(
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.dac_clk_in(dac_clk_in),
|
||||
.adc_clk_in(adc_clk_in),
|
||||
.rst_n(rst_n),
|
||||
|
||||
.s_axil(s_axil),
|
||||
|
||||
.finish(finish),
|
||||
.adc_window_size(adc_window_size),
|
||||
.dac_pulse_width(dac_pulse_width),
|
||||
.dac_pulse_period(dac_pulse_period),
|
||||
.dac_pulse_height(dac_pulse_height),
|
||||
.dac_pulse_num(dac_pulse_num),
|
||||
.adc_pulse_period(adc_pulse_period),
|
||||
.adc_pulse_num(adc_pulse_num),
|
||||
.dac_start(dac_start),
|
||||
.adc_start(adc_start),
|
||||
.dac_rst(dac_rst),
|
||||
.adc_rst(adc_rst),
|
||||
|
||||
.s_axis_status_read(s_axis_status_read),
|
||||
.s_axis_status_write(s_axis_status_write),
|
||||
.m_axis_desc_read(m_axis_desc_read),
|
||||
.m_axis_desc_write(m_axis_desc_write)
|
||||
);
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_W(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.DATA_W(AXI_DATA_WIDTH),
|
||||
.ID_W (AXI_ID_WIDTH),
|
||||
.USER_W(AXI_USER_WIDTH)
|
||||
) m_axi (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axi_dma_wrapper
|
||||
#(
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
|
||||
.AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED)
|
||||
)
|
||||
axi_dma_wrapper_inst
|
||||
(
|
||||
.clk(ctrl_clk),
|
||||
.rst(!rst_n),
|
||||
.s_axis_read_desc(m_axis_desc_read),
|
||||
.m_axis_read_desc_status(s_axis_status_read),
|
||||
.m_axis_read_data(m_axis_read_data),
|
||||
.s_axis_write_desc(m_axis_desc_write),
|
||||
.m_axis_write_desc_status(s_axis_status_write),
|
||||
.s_axis_write_data(s_axis_write_data),
|
||||
.m_axi(m_axi)
|
||||
);
|
||||
|
||||
axi_ram_wrapper
|
||||
#(
|
||||
.DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.ADDR_WIDTH(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.ID_WIDTH(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.PIPELINE_OUTPUT(PIPELINE_OUTPUT)
|
||||
) axi_ram_wrapper_inst
|
||||
(
|
||||
.clk(ctrl_clk),
|
||||
.rst(!rst_n),
|
||||
.s_axi(m_axi)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,231 @@
|
||||
import dma_reg_pkg::*;
|
||||
|
||||
module wrapper_controller_dma_accum
|
||||
#(
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
|
||||
parameter int unsigned DAC_DATA_WIDTH = 12,
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0,
|
||||
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 64,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32
|
||||
)
|
||||
(
|
||||
input logic ctrl_clk,
|
||||
input logic clk_generator,
|
||||
input logic clk_sampler,
|
||||
input logic rst_n,
|
||||
axi4l_if.slave s_axil,
|
||||
|
||||
// adc_clk_in domain
|
||||
|
||||
input logic [ADC_DATA_WIDTH-1:0] sampler_m_axis_tdata,
|
||||
input logic sampler_m_axis_tvalid,
|
||||
|
||||
axis_if.master m_axis_read_data
|
||||
);
|
||||
|
||||
logic workflow_done, processing_done;
|
||||
logic [31:0] window_size;
|
||||
logic adc_start, adc_rst;
|
||||
logic [31:0] dac_pulse_width;
|
||||
logic [31:0] dac_pulse_period;
|
||||
logic [DAC_DATA_WIDTH-1:0] dac_pulse_height;
|
||||
logic [15:0] dac_pulse_num;
|
||||
|
||||
// adc_clk_in domain outputs
|
||||
logic [31:0] adc_pulse_period;
|
||||
logic [15:0] adc_pulse_num;
|
||||
|
||||
// pulse outputs
|
||||
logic dac_start, dac_rst;
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_read_status_t)),
|
||||
.KEEP_W(($bits(dma_read_status_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) s_axis_status_read (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_write_status_t)),
|
||||
.KEEP_W(($bits(dma_write_status_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) s_axis_status_write (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W(RD_FIFO_WIDTH),
|
||||
.KEEP_W((RD_FIFO_WIDTH+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_accum (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_read_desc_t)),
|
||||
.KEEP_W(($bits(dma_read_desc_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_desc_read (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_write_desc_t)),
|
||||
.KEEP_W(($bits(dma_write_desc_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_desc_write (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
controller_wrapper_axil #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W),
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
) controller_wrapper_axil_inst
|
||||
(
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.dac_clk_in(clk_generator),
|
||||
.adc_clk_in(clk_sampler),
|
||||
.rst_n(rst_n),
|
||||
|
||||
.s_axil(s_axil),
|
||||
|
||||
.workflow_done(workflow_done),
|
||||
.processing_done(processing_done),
|
||||
|
||||
.adc_window_size(window_size),
|
||||
.dac_pulse_width(dac_pulse_width),
|
||||
.dac_pulse_period(dac_pulse_period),
|
||||
.dac_pulse_height(dac_pulse_height),
|
||||
.dac_pulse_num(dac_pulse_num),
|
||||
.adc_pulse_period(adc_pulse_period),
|
||||
.adc_pulse_num(adc_pulse_num),
|
||||
.dac_start(dac_start),
|
||||
.adc_start(adc_start),
|
||||
.dac_rst(dac_rst),
|
||||
.adc_rst(adc_rst),
|
||||
|
||||
.s_axis_status_read(s_axis_status_read),
|
||||
.s_axis_status_write(s_axis_status_write),
|
||||
.m_axis_desc_read(m_axis_desc_read),
|
||||
.m_axis_desc_write(m_axis_desc_write)
|
||||
);
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_W(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.DATA_W(AXI_DATA_WIDTH),
|
||||
.ID_W (AXI_ID_WIDTH),
|
||||
.USER_W(AXI_USER_WIDTH)
|
||||
) m_axi (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axi_dma_wrapper
|
||||
#(
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
|
||||
.AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED)
|
||||
)
|
||||
axi_dma_wrapper_inst
|
||||
(
|
||||
.clk(ctrl_clk),
|
||||
.rst(!rst_n),
|
||||
.s_axis_read_desc(m_axis_desc_read),
|
||||
.m_axis_read_desc_status(s_axis_status_read),
|
||||
.m_axis_read_data(m_axis_read_data),
|
||||
.s_axis_write_desc(m_axis_desc_write),
|
||||
.m_axis_write_desc_status(s_axis_status_write),
|
||||
.s_axis_write_data(m_axis_accum),
|
||||
.m_axi(m_axi)
|
||||
);
|
||||
|
||||
axi_ram_wrapper
|
||||
#(
|
||||
.DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.ADDR_WIDTH(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.ID_WIDTH(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.PIPELINE_OUTPUT(PIPELINE_OUTPUT)
|
||||
) axi_ram_wrapper_inst
|
||||
(
|
||||
.clk(ctrl_clk),
|
||||
.rst(!rst_n),
|
||||
.s_axi(m_axi)
|
||||
);
|
||||
|
||||
accumulator_top #(
|
||||
.DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RW_WIDTH(RD_FIFO_WIDTH)
|
||||
) accumulator_top_inst (
|
||||
.clk_in(clk_sampler),
|
||||
.rst(adc_rst),
|
||||
.s_axis_tdata(sampler_m_axis_tdata),
|
||||
.s_axis_tvalid(sampler_m_axis_tvalid),
|
||||
.start(adc_start),
|
||||
.smp_num(adc_pulse_period),
|
||||
.seq_num(adc_pulse_num),
|
||||
.window_size(window_size),
|
||||
.dma_clk_in(ctrl_clk),
|
||||
.req_ready(1'b1),
|
||||
.m_axis_accum(m_axis_accum),
|
||||
.finish(workflow_done),
|
||||
.accum_done(processing_done)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,48 @@
|
||||
TOPLEVEL_LANG = verilog
|
||||
SIM ?= verilator
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
WRAP_DIR = $(PWD)/../src
|
||||
RTL_DIR = $(PWD)/../../controller_new/src
|
||||
LIBS_DIR = $(PWD)/../../../external/rtl_libs
|
||||
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi_pkg.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/dma_reg_pkg.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi_if.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/axi_reg/axi4l_reg_map.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma_rd.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma_wr.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_ram.v
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi_ram_wrapper.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/controller.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/dma_controller.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/shaper_axis_desc.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/shaper_axis_status.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/controller_wrapper_axil.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi4l_reg_map_controller_pkg.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axis_defaults_helper.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi4l_reg_map_controller.sv
|
||||
VERILOG_SOURCES += $(WRAP_DIR)/wrapper_controller_dma.sv
|
||||
VERILOG_SOURCES += $(WRAP_DIR)/axi_dma_wrapper_if.sv
|
||||
VERILOG_SOURCES += $(PWD)/tb_controller_dma_wrapper_axil.sv
|
||||
|
||||
TOPLEVEL = tb_controller_dma_wrapper_axil
|
||||
MODULE = test_controller_and_dma
|
||||
|
||||
|
||||
ifeq ($(SIM),verilator)
|
||||
EXTRA_ARGS += --trace --trace-structs
|
||||
EXTRA_ARGS += -I$(LIBS_DIR)/axi/rtl/
|
||||
COMPILE_ARGS += -Wno-fatal
|
||||
COMPILE_ARGS += -I$(LIBS_DIR)/axi/rtl/
|
||||
EXTRA_ARGS += --trace
|
||||
EXTRA_ARGS += --trace-structs
|
||||
EXTRA_ARGS += --public-flat-rw
|
||||
EXTRA_ARGS += -Wno-fatal
|
||||
EXTRA_ARGS += --timing
|
||||
endif
|
||||
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
@@ -0,0 +1,61 @@
|
||||
TOPLEVEL_LANG = verilog
|
||||
SIM ?= verilator
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
WRAP_DIR = $(PWD)/../src
|
||||
RTL_DIR = $(PWD)/../../controller_new/src
|
||||
RTL_ACCUM_DIR = $(PWD)/../src/accum/src
|
||||
|
||||
LIBS_DIR = $(PWD)/../../../external/rtl_libs
|
||||
XPM_DIR = /mnt/c/Xilinx/Vivado/2021.2/data/ip/xpm
|
||||
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi_pkg.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/dma_reg_pkg.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi_if.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/axi_reg/axi4l_reg_map.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma_rd.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma_wr.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_ram.v
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi_ram_wrapper.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/controller.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/dma_controller.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/shaper_axis_desc.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/shaper_axis_status.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/controller_wrapper_axil.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi4l_reg_map_controller_pkg.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axis_defaults_helper.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi4l_reg_map_controller.sv
|
||||
VERILOG_SOURCES += $(WRAP_DIR)/wrapper_controller_dma_accum.sv
|
||||
VERILOG_SOURCES += $(WRAP_DIR)/axi_dma_wrapper_if.sv
|
||||
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/adder.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/out_axis_fifo.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/accum.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/accum_top.sv
|
||||
|
||||
VERILOG_SOURCES += $(XPM_DIR)/xpm_fifo/hdl/xpm_fifo.sv
|
||||
VERILOG_SOURCES += $(XPM_DIR)/xpm_memory/hdl/xpm_memory.sv
|
||||
VERILOG_SOURCES += $(XPM_DIR)/xpm_cdc/hdl/xpm_cdc.sv
|
||||
|
||||
VERILOG_SOURCES += $(PWD)/tb_controller_dma_accum_wrapper_axil.sv
|
||||
|
||||
TOPLEVEL = tb_controller_dma_accum_wrapper_axil
|
||||
MODULE = test_controller_dma_accum
|
||||
|
||||
|
||||
ifeq ($(SIM),verilator)
|
||||
EXTRA_ARGS += --trace --trace-structs
|
||||
EXTRA_ARGS += -I$(LIBS_DIR)/axi/rtl/
|
||||
COMPILE_ARGS += -Wno-fatal
|
||||
COMPILE_ARGS += -I$(LIBS_DIR)/axi/rtl/
|
||||
EXTRA_ARGS += --trace
|
||||
EXTRA_ARGS += --trace-structs
|
||||
EXTRA_ARGS += --public-flat-rw
|
||||
EXTRA_ARGS += -Wno-fatal
|
||||
EXTRA_ARGS += --timing
|
||||
endif
|
||||
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
|
||||
import dma_reg_pkg::*;
|
||||
|
||||
module tb_controller_dma_accum_wrapper_axil #(
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
|
||||
parameter int unsigned DAC_DATA_WIDTH = 12,
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 64,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32
|
||||
)(
|
||||
input logic ctrl_clk,
|
||||
input logic adc_clk_in,
|
||||
input logic dac_clk_in,
|
||||
input logic rst,
|
||||
|
||||
input logic [ADDR_W-1:0] s_axil_awaddr,
|
||||
input logic [2:0] s_axil_awprot,
|
||||
input logic s_axil_awvalid,
|
||||
output logic s_axil_awready,
|
||||
|
||||
input logic [DATA_W-1:0] s_axil_wdata,
|
||||
input logic [DATA_W/8-1:0] s_axil_wstrb,
|
||||
input logic s_axil_wvalid,
|
||||
output logic s_axil_wready,
|
||||
|
||||
output logic [1:0] s_axil_bresp,
|
||||
output logic s_axil_bvalid,
|
||||
input logic s_axil_bready,
|
||||
|
||||
input logic [ADDR_W-1:0] s_axil_araddr,
|
||||
input logic [2:0] s_axil_arprot,
|
||||
input logic s_axil_arvalid,
|
||||
output logic s_axil_arready,
|
||||
|
||||
output logic [DATA_W-1:0] s_axil_rdata,
|
||||
output logic [1:0] s_axil_rresp,
|
||||
output logic s_axil_rvalid,
|
||||
input logic s_axil_rready,
|
||||
|
||||
output wire [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata,
|
||||
output wire [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep,
|
||||
output wire m_axis_read_data_tvalid,
|
||||
input wire m_axis_read_data_tready,
|
||||
output wire m_axis_read_data_tlast,
|
||||
output wire [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid,
|
||||
output wire [dma_reg_pkg::AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest,
|
||||
output wire [dma_reg_pkg::AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser,
|
||||
|
||||
input wire [ADC_DATA_WIDTH-1:0] sampler_m_axis_tdata,
|
||||
input wire sampler_m_axis_tvalid
|
||||
);
|
||||
|
||||
logic rst_n;
|
||||
|
||||
assign rst_n = ~rst;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AXI-Lite flat -> axi4l_if
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
axi4l_if #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W)
|
||||
) axil_bus (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axi4l_flat_to_if #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W)
|
||||
) u_axil_flat_to_if (
|
||||
.s_axil_awaddr (s_axil_awaddr),
|
||||
.s_axil_awprot (s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
|
||||
.s_axil_wdata (s_axil_wdata),
|
||||
.s_axil_wstrb (s_axil_wstrb),
|
||||
.s_axil_wvalid (s_axil_wvalid),
|
||||
.s_axil_wready (s_axil_wready),
|
||||
|
||||
.s_axil_bresp (s_axil_bresp),
|
||||
.s_axil_bvalid (s_axil_bvalid),
|
||||
.s_axil_bready (s_axil_bready),
|
||||
|
||||
.s_axil_araddr (s_axil_araddr),
|
||||
.s_axil_arprot (s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
|
||||
.s_axil_rdata (s_axil_rdata),
|
||||
.s_axil_rresp (s_axil_rresp),
|
||||
.s_axil_rvalid (s_axil_rvalid),
|
||||
.s_axil_rready (s_axil_rready),
|
||||
|
||||
.m_axil(axil_bus)
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AXIS interfaces for the updated controller_wrapper_axil
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// AXIS READ DMA MASTER output
|
||||
axis_if #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W (dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) dma_read_data (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
logic [AXIS_KEEP_WIDTH-1:0] unused_read_tstrb;
|
||||
|
||||
axis_if_to_flat #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W (dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) u_read_data_if_to_flat (
|
||||
.s_axis(dma_read_data),
|
||||
|
||||
.m_axis_tdata (m_axis_read_data_tdata),
|
||||
.m_axis_tkeep (m_axis_read_data_tkeep),
|
||||
.m_axis_tstrb (unused_read_tstrb),
|
||||
.m_axis_tlast (m_axis_read_data_tlast),
|
||||
.m_axis_tid (m_axis_read_data_tid),
|
||||
.m_axis_tdest (m_axis_read_data_tdest),
|
||||
.m_axis_tuser (m_axis_read_data_tuser),
|
||||
.m_axis_tvalid(m_axis_read_data_tvalid),
|
||||
.m_axis_tready(m_axis_read_data_tready)
|
||||
);
|
||||
|
||||
|
||||
wrapper_controller_dma_accum #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W),
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_ID_WIDTH(AXI_ID_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED),
|
||||
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RD_FIFO_WIDTH(RD_FIFO_WIDTH)
|
||||
) dut (
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.clk_generator(dac_clk_in),
|
||||
.clk_sampler(adc_clk_in),
|
||||
.rst_n(rst_n),
|
||||
.s_axil(axil_bus),
|
||||
|
||||
.sampler_m_axis_tdata(sampler_m_axis_tdata),
|
||||
.sampler_m_axis_tvalid(sampler_m_axis_tvalid),
|
||||
|
||||
.m_axis_read_data(dma_read_data)
|
||||
);
|
||||
|
||||
endmodule : tb_controller_dma_accum_wrapper_axil
|
||||
+568
@@ -0,0 +1,568 @@
|
||||
import cocotb
|
||||
import random
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotbext.axi import AxiLiteBus, AxiLiteMaster
|
||||
from cocotbext.axi import AxiBus, AxiRam, AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamFrame
|
||||
|
||||
|
||||
# Register indexes from axi4l_reg_map_controller_pkg.sv
|
||||
REG_CONTROL = 0
|
||||
REG_STATUS = 1
|
||||
REG_DAC_WIDTH = 2
|
||||
REG_DAC_PERIOD = 3
|
||||
REG_DAC_PULSE_NUM = 4
|
||||
REG_DAC_PULSE_HEIGHT = 5
|
||||
REG_ADC_PERIOD = 6
|
||||
REG_WINDOW_SIZE = 7
|
||||
REG_ERROR = 8
|
||||
REG_DESC_READ_ADDR = 9
|
||||
REG_DESC_READ_LEN = 10
|
||||
REG_DESC_READ_CONFIG = 11
|
||||
REG_READ_STATUS = 12
|
||||
REG_DESC_WRITE_ADDR = 13
|
||||
REG_DESC_WRITE_LEN_AND_TAG = 14
|
||||
REG_STATUS_WRITE_LEN = 15
|
||||
REG_STATUS_WRITE_CONFIG = 16
|
||||
|
||||
|
||||
# REG_CONTROL pulse bits
|
||||
CTRL_START = 1 << 0
|
||||
CTRL_RST_SOFT = 1 << 1
|
||||
CTRL_CFG_BUS_VALID = 1 << 2
|
||||
CTRL_SEND_DESC_READ = 1 << 3
|
||||
CTRL_SEND_DESC_WRITE = 1 << 4
|
||||
CTRL_TAKE_STATUS_READ = 1 << 5
|
||||
CTRL_TAKE_STATUS_WRITE = 1 << 6
|
||||
|
||||
# REG_STATUS bits
|
||||
STATUS_BUSY = 1 << 0
|
||||
STATUS_PROCESSING_DONE = 1 << 1
|
||||
|
||||
STATUS_DESC_READ_BUSY = 1 << 2
|
||||
STATUS_DESC_WRITE_BUSY = 1 << 3
|
||||
STATUS_STATUS_READ_BUSY = 1 << 4
|
||||
STATUS_STATUS_WRITE_BUSY = 1 << 5
|
||||
|
||||
STATUS_DESC_READ_HS = 1 << 6
|
||||
STATUS_DESC_WRITE_HS = 1 << 7
|
||||
STATUS_STATUS_READ_HS = 1 << 8
|
||||
STATUS_STATUS_WRITE_HS = 1 << 9
|
||||
|
||||
# PARAMETERS for accumulator reference model
|
||||
|
||||
DAC_DATA_WIDTH = 14
|
||||
ADC_DATA_WIDTH = 12
|
||||
PACK_FACTOR = 1
|
||||
PROCESS_MODE = 0
|
||||
ZERO_LEVEL = 8192
|
||||
ACCUM_WIDTH = 32
|
||||
N_MAX = 4096
|
||||
PACKET_SIZE = 1024
|
||||
RD_FIFO_WIDTH = 32
|
||||
|
||||
|
||||
def reg_addr(reg_index: int) -> int:
|
||||
# AXI-Lite uses byte addresses, 32-bit registers are spaced by 4 bytes.
|
||||
return reg_index * 4
|
||||
|
||||
|
||||
def u32(value: int) -> bytes:
|
||||
return int(value & 0xFFFFFFFF).to_bytes(4, "little")
|
||||
|
||||
|
||||
class TB:
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
cocotb.start_soon(Clock(dut.ctrl_clk, 10, units="ns").start())
|
||||
|
||||
cocotb.start_soon(Clock(dut.adc_clk_in, 15.3846, units="ns").start())
|
||||
|
||||
cocotb.start_soon(Clock(dut.dac_clk_in, 8.333, units="ns").start())
|
||||
|
||||
self.axil = AxiLiteMaster(
|
||||
AxiLiteBus.from_prefix(dut, "s_axil"),
|
||||
dut.ctrl_clk,
|
||||
dut.rst
|
||||
)
|
||||
|
||||
|
||||
self.axis_source = AxiStreamSource(
|
||||
AxiStreamBus.from_prefix(dut, "s_axis_write_data"),
|
||||
dut.ctrl_clk,
|
||||
dut.rst
|
||||
)
|
||||
|
||||
self.axis_sink = AxiStreamSink(
|
||||
AxiStreamBus.from_prefix(dut, "m_axis_read_data"),
|
||||
dut.ctrl_clk,
|
||||
dut.rst
|
||||
)
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.value = 1
|
||||
for _ in range(5):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
self.dut.rst.value = 0
|
||||
for _ in range(5):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
async def write_reg(self, reg_index: int, value: int):
|
||||
await self.axil.write(reg_addr(reg_index), u32(value))
|
||||
|
||||
async def read_reg(self, reg_index: int) -> int:
|
||||
resp = await self.axil.read(reg_addr(reg_index), 4)
|
||||
return int.from_bytes(bytes(resp.data), "little")
|
||||
|
||||
async def pulse_control(self, mask):
|
||||
await self.write_reg( REG_CONTROL, mask )
|
||||
|
||||
# Reflectometer Driver
|
||||
|
||||
async def configure_reflectometer (
|
||||
self,
|
||||
pulse_width,
|
||||
pulse_period,
|
||||
pulse_num,
|
||||
pulse_height,
|
||||
adc_period,
|
||||
window_size
|
||||
):
|
||||
await self.write_reg(REG_DAC_WIDTH, pulse_width)
|
||||
await self.write_reg(REG_DAC_PERIOD, pulse_period)
|
||||
await self.write_reg(REG_DAC_PULSE_NUM, pulse_num)
|
||||
await self.write_reg(REG_DAC_PULSE_HEIGHT, pulse_height)
|
||||
await self.write_reg(REG_ADC_PERIOD, adc_period)
|
||||
await self.write_reg(REG_WINDOW_SIZE, window_size)
|
||||
|
||||
await self.pulse_control(CTRL_CFG_BUS_VALID)
|
||||
|
||||
async def send_start(self):
|
||||
await self.pulse_control(CTRL_START)
|
||||
|
||||
async def soft_reset(self):
|
||||
await self.pulse_control(CTRL_RST_SOFT)
|
||||
|
||||
async def get_status(self):
|
||||
status = await self.read_reg(REG_STATUS)
|
||||
return {
|
||||
"busy": bool(status & STATUS_BUSY),
|
||||
"processing_done": bool(status & STATUS_PROCESSING_DONE),
|
||||
"desc_read_busy": bool(status & STATUS_DESC_READ_BUSY),
|
||||
"desc_write_busy": bool(status & STATUS_DESC_WRITE_BUSY),
|
||||
"status_read_busy": bool(status & STATUS_STATUS_READ_BUSY),
|
||||
"status_write_busy": bool(status & STATUS_STATUS_WRITE_BUSY),
|
||||
"desc_read_hs": bool(status & STATUS_DESC_READ_HS),
|
||||
"desc_write_hs": bool(status & STATUS_DESC_WRITE_HS),
|
||||
"status_read_hs": bool(status & STATUS_STATUS_READ_HS),
|
||||
"status_write_hs": bool(status & STATUS_STATUS_WRITE_HS)
|
||||
}
|
||||
|
||||
async def wait_status(self, field, value=True):
|
||||
|
||||
while True:
|
||||
|
||||
status = await self.get_status()
|
||||
|
||||
if status[field] == value:
|
||||
return
|
||||
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
async def wait_processing_done(self):
|
||||
await self.wait_status("processing_done")
|
||||
|
||||
|
||||
async def wait_finish(self):
|
||||
await self.wait_status("busy", False)
|
||||
|
||||
# DMA Driver
|
||||
|
||||
async def send_desc_write(self, addr, length_tag):
|
||||
|
||||
await self.write_reg(REG_DESC_WRITE_ADDR, addr)
|
||||
await self.write_reg(REG_DESC_WRITE_LEN_AND_TAG, length_tag)
|
||||
await self.pulse_control(CTRL_SEND_DESC_WRITE)
|
||||
|
||||
async def send_desc_read(self, addr, length, config):
|
||||
|
||||
await self.write_reg(REG_DESC_READ_ADDR, addr)
|
||||
await self.write_reg(REG_DESC_READ_LEN, length)
|
||||
await self.write_reg(REG_DESC_READ_CONFIG, config)
|
||||
await self.pulse_control( CTRL_SEND_DESC_READ)
|
||||
|
||||
async def take_status_write(self):
|
||||
await self.pulse_control(CTRL_TAKE_STATUS_WRITE)
|
||||
|
||||
return (
|
||||
await self.read_reg(REG_STATUS_WRITE_LEN),
|
||||
await self.read_reg(REG_STATUS_WRITE_CONFIG) )
|
||||
|
||||
async def take_read_status(self):
|
||||
|
||||
await self.pulse_control( CTRL_TAKE_STATUS_READ)
|
||||
return await self.read_reg(REG_READ_STATUS)
|
||||
|
||||
async def wait_dma_write_done(self):
|
||||
await self.wait_status("desc_write_busy", True)
|
||||
await self.wait_status("desc_write_busy", False)
|
||||
|
||||
async def wait_dma_read_done(self):
|
||||
await self.wait_status("desc_read_busy", True)
|
||||
await self.wait_status("desc_read_busy", False)
|
||||
|
||||
async def wait_status_read_handshake(self):
|
||||
await self.wait_status("status_read_hs")
|
||||
|
||||
async def wait_status_write_handshake(self):
|
||||
await self.wait_status("status_write_hs")
|
||||
|
||||
# AxiStream Driver
|
||||
|
||||
async def send_axis_data(self, data: bytes):
|
||||
|
||||
await self.axis_source.send(AxiStreamFrame(data) )
|
||||
|
||||
async def receive_axis_data(self):
|
||||
|
||||
frame = await self.axis_sink.recv()
|
||||
return bytes(frame)
|
||||
|
||||
# Accum transaction generator
|
||||
|
||||
def generate_samples(
|
||||
self,
|
||||
seq_num: int,
|
||||
smp_num: int,
|
||||
data_width: int,
|
||||
seed: int | None = None):
|
||||
if seq_num <= 0:
|
||||
raise ValueError(f"seq_num must be > 0, got {seq_num}")
|
||||
|
||||
if smp_num <= 0:
|
||||
raise ValueError(f"smp_num must be > 0, got {smp_num}")
|
||||
|
||||
rng = random.Random(seed)
|
||||
|
||||
max_value = (1 << data_width) - 1
|
||||
|
||||
samples = []
|
||||
|
||||
for _ in range(seq_num):
|
||||
seq_samples = []
|
||||
|
||||
for _ in range(smp_num):
|
||||
seq_samples.append( rng.randint(0, max_value))
|
||||
|
||||
samples.append(seq_samples)
|
||||
|
||||
return samples
|
||||
|
||||
def calculate_expected(
|
||||
self,
|
||||
samples,
|
||||
window_size: int,
|
||||
accum_width: int):
|
||||
if window_size <= 0:
|
||||
raise ValueError( f"window_size must be > 0, got {window_size}")
|
||||
|
||||
if not samples:
|
||||
raise ValueError("samples must not be empty")
|
||||
|
||||
seq_num = len(samples)
|
||||
smp_num = len(samples[0])
|
||||
|
||||
if smp_num == 0:
|
||||
raise ValueError("samples must not contain empty sequences")
|
||||
|
||||
for seq_idx, seq_samples in enumerate(samples):
|
||||
if len(seq_samples) != smp_num:
|
||||
raise ValueError(f"Sequence {seq_idx} has {len(seq_samples)} samples, " f"expected {smp_num}" )
|
||||
|
||||
if smp_num % window_size != 0:
|
||||
raise ValueError(f"smp_num ({smp_num}) must be divisible " f"by window_size ({window_size})")
|
||||
|
||||
exp_word_count = smp_num // window_size
|
||||
accum_mask = (1 << accum_width) - 1
|
||||
|
||||
expected = []
|
||||
|
||||
for word_idx in range(exp_word_count):
|
||||
local_sum = 0
|
||||
|
||||
for seq_idx in range(seq_num):
|
||||
for k in range(window_size):
|
||||
sample_idx = word_idx * window_size + k
|
||||
local_sum += samples[seq_idx][sample_idx]
|
||||
|
||||
expected.append(local_sum & accum_mask)
|
||||
|
||||
return expected
|
||||
|
||||
async def send_samples(self, samples):
|
||||
self.dut.sampler_m_axis_tvalid.value = 0
|
||||
self.dut.sampler_m_axis_tdata.value = 0
|
||||
|
||||
for seq_samples in samples:
|
||||
|
||||
for sample in seq_samples:
|
||||
|
||||
self.dut.sampler_m_axis_tdata.value = sample
|
||||
self.dut.sampler_m_axis_tvalid.value = 1
|
||||
|
||||
await RisingEdge(self.dut.adc_clk_in)
|
||||
|
||||
self.dut.sampler_m_axis_tdata.value = 0
|
||||
self.dut.sampler_m_axis_tvalid.value = 0
|
||||
|
||||
await RisingEdge(self.dut.adc_clk_in)
|
||||
await RisingEdge(self.dut.adc_clk_in)
|
||||
|
||||
def bytes_to_words(self, data: bytes, word_width: int = 32):
|
||||
word_bytes = word_width // 8
|
||||
|
||||
if len(data) % word_bytes != 0:
|
||||
raise ValueError(f"Data length {len(data)} is not divisible " f"by word size {word_bytes}" )
|
||||
|
||||
words = []
|
||||
|
||||
for i in range(0, len(data), word_bytes):
|
||||
word = int.from_bytes(data[i:i + word_bytes], byteorder="little" )
|
||||
words.append(word)
|
||||
|
||||
return words
|
||||
|
||||
def check_results(self, expected, received):
|
||||
|
||||
assert len(received) == len(expected), (
|
||||
f"Number of words mismatch: "
|
||||
f"expected={len(expected)}, "
|
||||
f"received={len(received)}" )
|
||||
|
||||
for i, (exp, rec) in enumerate(zip(expected, received)):
|
||||
assert rec == exp, (
|
||||
f"Payload mismatch at index {i}: "
|
||||
f"expected=0x{exp:08X}, "
|
||||
f"received=0x{rec:08X}" )
|
||||
|
||||
print( f"Payload check passed: " f"{len(expected)} words")
|
||||
|
||||
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def simple_axil_write_read(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
|
||||
await tb.write_reg(REG_DAC_WIDTH, 0x0000_0123)
|
||||
|
||||
value = await tb.read_reg(REG_DAC_WIDTH)
|
||||
assert value == 0x0000_0123
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def simple_controller_config_write(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
|
||||
await tb.write_reg(REG_DAC_WIDTH, 0x10)
|
||||
await tb.write_reg(REG_DAC_PERIOD, 0x40)
|
||||
await tb.write_reg(REG_DAC_PULSE_NUM, 3)
|
||||
await tb.write_reg(REG_DAC_PULSE_HEIGHT, 0x7FF)
|
||||
await tb.write_reg(REG_ADC_PERIOD, 0x80)
|
||||
await tb.write_reg(REG_WINDOW_SIZE, 16)
|
||||
|
||||
assert await tb.read_reg(REG_DAC_WIDTH) == 0x10
|
||||
assert await tb.read_reg(REG_WINDOW_SIZE) == 16
|
||||
|
||||
# write data: set cfg_bus_valid signal
|
||||
await tb.write_reg(REG_CONTROL, 1 << CTRL_CFG_BUS_VALID)
|
||||
|
||||
# wait
|
||||
for _ in range(30):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
# check config
|
||||
assert int(dut.dac_pulse_width) == 0x10
|
||||
assert int(dut.dac_pulse_period) == 0x40
|
||||
assert int(dut.dac_pulse_num) == 3
|
||||
assert int(dut.dac_pulse_height) == 0x7FF
|
||||
assert int(dut.adc_pulse_period) == 0x80
|
||||
assert int(dut.adc_window_size) == 16
|
||||
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def simple_controller_start_check(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
await tb.write_reg(REG_CONTROL, 1 << CTRL_START)
|
||||
|
||||
await RisingEdge(dut.dac_start)
|
||||
|
||||
@cocotb.test()
|
||||
async def simple_dma_mem_to_mem(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
|
||||
SRC_ADDR = 0x1000
|
||||
LENGTH = 8
|
||||
|
||||
tx_data = bytes([ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 ])
|
||||
|
||||
## write part
|
||||
|
||||
await tb.write_reg(REG_DESC_WRITE_ADDR, SRC_ADDR)
|
||||
await tb.write_reg(REG_DESC_WRITE_LEN_AND_TAG, LENGTH)
|
||||
|
||||
await tb.write_reg(REG_CONTROL, 1 << CTRL_SEND_DESC_WRITE)
|
||||
|
||||
await tb.axis_source.send(AxiStreamFrame(tx_data))
|
||||
|
||||
for _ in range(20):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
await tb.write_reg(REG_CONTROL, 1 << CTRL_TAKE_STATUS_WRITE)
|
||||
|
||||
for _ in range(10):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
|
||||
assert await tb.read_reg(REG_STATUS_WRITE_CONFIG) == 0
|
||||
assert await tb.read_reg(REG_STATUS_WRITE_LEN) == 0x8
|
||||
|
||||
## read part
|
||||
|
||||
await tb.write_reg(REG_DESC_READ_ADDR, SRC_ADDR)
|
||||
await tb.write_reg(REG_DESC_READ_LEN, LENGTH)
|
||||
await tb.write_reg(REG_DESC_READ_CONFIG, 0x0000_0001)
|
||||
|
||||
await tb.write_reg(REG_CONTROL, 1 << CTRL_SEND_DESC_READ)
|
||||
|
||||
rx_frame = await tb.axis_sink.recv()
|
||||
|
||||
for _ in range(20):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
await tb.write_reg(REG_CONTROL, 1 << CTRL_TAKE_STATUS_READ)
|
||||
|
||||
for _ in range(10):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
assert await tb.read_reg(REG_READ_STATUS) == 0x1
|
||||
|
||||
assert bytes(rx_frame) == tx_data
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def dma_accum_connection(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
|
||||
SEQ_NUM = 3
|
||||
SMP_NUM = 0x40 # 64 samples per sequence
|
||||
WINDOW_SIZE = 16
|
||||
|
||||
PULSE_WIDTH = 0x10
|
||||
PULSE_PERIOD = 0x40
|
||||
PULSE_HEIGHT = 0x7FF
|
||||
ADC_PERIOD = 0x80
|
||||
|
||||
RANDOM_SEED = 12345
|
||||
|
||||
await tb.configure_reflectometer(
|
||||
pulse_width=PULSE_WIDTH,
|
||||
pulse_period=PULSE_PERIOD,
|
||||
pulse_num=SEQ_NUM,
|
||||
pulse_height=PULSE_HEIGHT,
|
||||
adc_period=ADC_PERIOD,
|
||||
window_size=WINDOW_SIZE )
|
||||
|
||||
samples = tb.generate_samples(
|
||||
seq_num=SEQ_NUM,
|
||||
smp_num=SMP_NUM,
|
||||
data_width=ADC_DATA_WIDTH,
|
||||
seed=RANDOM_SEED )
|
||||
|
||||
|
||||
expected = tb.calculate_expected(
|
||||
samples=samples,
|
||||
window_size=WINDOW_SIZE,
|
||||
accum_width=ACCUM_WIDTH
|
||||
)
|
||||
|
||||
print("")
|
||||
print("========================================")
|
||||
print("ACCUMULATOR RANDOM TEST")
|
||||
print("========================================")
|
||||
print(f"seq_num = {SEQ_NUM}")
|
||||
print(f"smp_num = {SMP_NUM}")
|
||||
print(f"window_size = {WINDOW_SIZE}")
|
||||
print(f"data_width = {ADC_DATA_WIDTH}")
|
||||
print(f"accum_width = {ACCUM_WIDTH}")
|
||||
print(f"expected words = {len(expected)}")
|
||||
|
||||
RESULT_WORDS = len(expected)
|
||||
RESULT_BYTES = RESULT_WORDS * (ACCUM_WIDTH // 8)
|
||||
|
||||
print(f"result bytes = {RESULT_BYTES}")
|
||||
assert RESULT_WORDS == 4
|
||||
assert RESULT_BYTES == 16
|
||||
|
||||
|
||||
await tb.send_start()
|
||||
|
||||
await tb.send_samples(samples)
|
||||
|
||||
await tb.wait_processing_done()
|
||||
|
||||
RESULT_ADDR = 0x1000
|
||||
|
||||
await tb.send_desc_write( addr=RESULT_ADDR, length_tag=RESULT_BYTES )
|
||||
|
||||
await tb.wait_dma_write_done()
|
||||
|
||||
status_write_len, status_write_config = \
|
||||
await tb.take_status_write()
|
||||
|
||||
assert status_write_config == 0
|
||||
assert status_write_len == RESULT_BYTES
|
||||
|
||||
await tb.send_desc_read(addr=RESULT_ADDR, length=RESULT_BYTES, config=0x0000_0001 )
|
||||
|
||||
received_data = await tb.receive_axis_data()
|
||||
|
||||
await tb.wait_dma_read_done()
|
||||
|
||||
read_status = await tb.take_read_status()
|
||||
|
||||
assert read_status == 0x1
|
||||
|
||||
received = tb.bytes_to_words(received_data, RD_FIFO_WIDTH)
|
||||
|
||||
print("")
|
||||
print("Expected:")
|
||||
for i, value in enumerate(expected):
|
||||
print(f" [{i}] = 0x{value:08X}")
|
||||
|
||||
print("")
|
||||
print("Received:")
|
||||
for i, value in enumerate(received):
|
||||
print(f" [{i}] = 0x{value:08X}")
|
||||
|
||||
tb.check_results(
|
||||
expected=expected,
|
||||
received=received
|
||||
)
|
||||
|
||||
print("")
|
||||
print("========================================")
|
||||
print("ACCUMULATOR RANDOM TEST PASSED")
|
||||
print("========================================")
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Primary clocks
|
||||
create_clock -name eth_clk -period 8.000 [get_ports eth_clk_in]
|
||||
create_clock -name dac_clk -period 7.692 [get_ports dac_clk_in]
|
||||
create_clock -name adc_clk -period 15.385 [get_ports adc_clk_in]
|
||||
|
||||
|
||||
# Asynchronous clock groups
|
||||
# eth, dac, adc are independent domains
|
||||
|
||||
set_clock_groups -name ASYNC_ETH_DAC_ADC -asynchronous \
|
||||
-group [get_clocks eth_clk] \
|
||||
-group [get_clocks dac_clk] \
|
||||
-group [get_clocks adc_clk]
|
||||
@@ -0,0 +1,298 @@
|
||||
|
||||
import dma_reg_pkg::*;
|
||||
|
||||
module tb_controller_wrapper_axil #(
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
|
||||
parameter int unsigned DAC_DATA_WIDTH = 12,
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0
|
||||
)(
|
||||
input logic ctrl_clk,
|
||||
input logic rst,
|
||||
|
||||
input logic [ADDR_W-1:0] s_axil_awaddr,
|
||||
input logic [2:0] s_axil_awprot,
|
||||
input logic s_axil_awvalid,
|
||||
output logic s_axil_awready,
|
||||
|
||||
input logic [DATA_W-1:0] s_axil_wdata,
|
||||
input logic [DATA_W/8-1:0] s_axil_wstrb,
|
||||
input logic s_axil_wvalid,
|
||||
output logic s_axil_wready,
|
||||
|
||||
output logic [1:0] s_axil_bresp,
|
||||
output logic s_axil_bvalid,
|
||||
input logic s_axil_bready,
|
||||
|
||||
input logic [ADDR_W-1:0] s_axil_araddr,
|
||||
input logic [2:0] s_axil_arprot,
|
||||
input logic s_axil_arvalid,
|
||||
output logic s_axil_arready,
|
||||
|
||||
output logic [DATA_W-1:0] s_axil_rdata,
|
||||
output logic [1:0] s_axil_rresp,
|
||||
output logic s_axil_rvalid,
|
||||
input logic s_axil_rready,
|
||||
|
||||
input wire [AXIS_DATA_WIDTH-1:0] s_axis_write_data_tdata,
|
||||
input wire [AXIS_KEEP_WIDTH-1:0] s_axis_write_data_tkeep,
|
||||
input wire s_axis_write_data_tvalid,
|
||||
output wire s_axis_write_data_tready,
|
||||
input wire s_axis_write_data_tlast,
|
||||
input wire [AXIS_ID_WIDTH-1:0] s_axis_write_data_tid,
|
||||
input wire [AXIS_DEST_WIDTH-1:0] s_axis_write_data_tdest,
|
||||
input wire [AXIS_USER_WIDTH-1:0] s_axis_write_data_tuser,
|
||||
|
||||
output wire [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata,
|
||||
output wire [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep,
|
||||
output wire m_axis_read_data_tvalid,
|
||||
input wire m_axis_read_data_tready,
|
||||
output wire m_axis_read_data_tlast,
|
||||
output wire [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid,
|
||||
output wire [AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest,
|
||||
output wire [AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser,
|
||||
|
||||
output wire [AXI_ID_WIDTH-1:0] m_axi_awid,
|
||||
output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr,
|
||||
output wire [7:0] m_axi_awlen,
|
||||
output wire [2:0] m_axi_awsize,
|
||||
output wire [1:0] m_axi_awburst,
|
||||
output wire m_axi_awlock,
|
||||
output wire [3:0] m_axi_awcache,
|
||||
output wire [2:0] m_axi_awprot,
|
||||
output wire m_axi_awvalid,
|
||||
input wire m_axi_awready,
|
||||
output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata,
|
||||
output wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb,
|
||||
output wire m_axi_wlast,
|
||||
output wire m_axi_wvalid,
|
||||
input wire m_axi_wready,
|
||||
input wire [AXI_ID_WIDTH-1:0] m_axi_bid,
|
||||
input wire [1:0] m_axi_bresp,
|
||||
input wire m_axi_bvalid,
|
||||
output wire m_axi_bready,
|
||||
output wire [AXI_ID_WIDTH-1:0] m_axi_arid,
|
||||
output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr,
|
||||
output wire [7:0] m_axi_arlen,
|
||||
output wire [2:0] m_axi_arsize,
|
||||
output wire [1:0] m_axi_arburst,
|
||||
output wire m_axi_arlock,
|
||||
output wire [3:0] m_axi_arcache,
|
||||
output wire [2:0] m_axi_arprot,
|
||||
output wire m_axi_arvalid,
|
||||
input wire m_axi_arready,
|
||||
input wire [AXI_ID_WIDTH-1:0] m_axi_rid,
|
||||
input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata,
|
||||
input wire [1:0] m_axi_rresp,
|
||||
input wire m_axi_rlast,
|
||||
input wire m_axi_rvalid,
|
||||
output wire m_axi_rready
|
||||
|
||||
|
||||
);
|
||||
|
||||
logic rst_n;
|
||||
assign rst_n = ~rst;
|
||||
|
||||
// Для минимального теста держим все clock domain-ы на одном clock.
|
||||
logic dac_clk_in;
|
||||
logic adc_clk_in;
|
||||
assign dac_clk_in = ctrl_clk;
|
||||
assign adc_clk_in = ctrl_clk;
|
||||
|
||||
logic finish;
|
||||
assign finish = 1'b0;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AXI-Lite flat -> axi4l_if
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
axi4l_if #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W)
|
||||
) axil_bus (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axi4l_flat_to_if #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W)
|
||||
) u_axil_flat_to_if (
|
||||
.s_axil_awaddr (s_axil_awaddr),
|
||||
.s_axil_awprot (s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
|
||||
.s_axil_wdata (s_axil_wdata),
|
||||
.s_axil_wstrb (s_axil_wstrb),
|
||||
.s_axil_wvalid (s_axil_wvalid),
|
||||
.s_axil_wready (s_axil_wready),
|
||||
|
||||
.s_axil_bresp (s_axil_bresp),
|
||||
.s_axil_bvalid (s_axil_bvalid),
|
||||
.s_axil_bready (s_axil_bready),
|
||||
|
||||
.s_axil_araddr (s_axil_araddr),
|
||||
.s_axil_arprot (s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
|
||||
.s_axil_rdata (s_axil_rdata),
|
||||
.s_axil_rresp (s_axil_rresp),
|
||||
.s_axil_rvalid (s_axil_rvalid),
|
||||
.s_axil_rready (s_axil_rready),
|
||||
|
||||
.m_axil(axil_bus)
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AXIS interfaces for the updated controller_wrapper_axil
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// AXIS READ DMA MASTER output
|
||||
axis_if #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (AXIS_DEST_WIDTH),
|
||||
.USER_W (AXIS_USER_WIDTH)
|
||||
) dma_read_data (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
logic [AXIS_KEEP_WIDTH-1:0] unused_read_tstrb;
|
||||
|
||||
axis_if_to_flat #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (AXIS_DEST_WIDTH),
|
||||
.USER_W (AXIS_USER_WIDTH)
|
||||
) u_read_data_if_to_flat (
|
||||
.s_axis(dma_read_data),
|
||||
|
||||
.m_axis_tdata (m_axis_read_data_tdata),
|
||||
.m_axis_tkeep (m_axis_read_data_tkeep),
|
||||
.m_axis_tstrb (unused_read_tstrb),
|
||||
.m_axis_tlast (m_axis_read_data_tlast),
|
||||
.m_axis_tid (m_axis_read_data_tid),
|
||||
.m_axis_tdest (m_axis_read_data_tdest),
|
||||
.m_axis_tuser (m_axis_read_data_tuser),
|
||||
.m_axis_tvalid(m_axis_read_data_tvalid),
|
||||
.m_axis_tready(m_axis_read_data_tready)
|
||||
);
|
||||
|
||||
// AXIS WRITE DMA SLAVE input
|
||||
axis_if #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (AXIS_DEST_WIDTH),
|
||||
.USER_W (AXIS_USER_WIDTH)
|
||||
) dma_write_data (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
|
||||
axis_flat_to_if #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (AXIS_DEST_WIDTH),
|
||||
.USER_W (AXIS_USER_WIDTH)
|
||||
) u_write_data_flat_to_if (
|
||||
.s_axis_tdata (s_axis_write_data_tdata),
|
||||
.s_axis_tkeep (s_axis_write_data_tkeep),
|
||||
.s_axis_tstrb (s_axis_write_data_tkeep),
|
||||
.s_axis_tlast (s_axis_write_data_tlast),
|
||||
.s_axis_tid (s_axis_write_data_tid),
|
||||
.s_axis_tdest (s_axis_write_data_tdest),
|
||||
.s_axis_tuser (s_axis_write_data_tuser),
|
||||
.s_axis_tvalid(s_axis_write_data_tvalid),
|
||||
.s_axis_tready(s_axis_write_data_tready),
|
||||
|
||||
.m_axis(dma_write_data)
|
||||
);
|
||||
|
||||
|
||||
|
||||
// Controller ADC/DAC outputs.
|
||||
logic [31:0] adc_window_size;
|
||||
logic [31:0] dac_pulse_width;
|
||||
logic [31:0] dac_pulse_period;
|
||||
logic [DAC_DATA_WIDTH-1:0] dac_pulse_height;
|
||||
logic [15:0] dac_pulse_num;
|
||||
logic [31:0] adc_pulse_period;
|
||||
logic [15:0] adc_pulse_num;
|
||||
logic dac_start;
|
||||
logic adc_start;
|
||||
logic dac_rst;
|
||||
logic adc_rst;
|
||||
|
||||
wrapper_controller_dma #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W),
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_ID_WIDTH(AXI_ID_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED)
|
||||
) dut (
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.dac_clk_in(dac_clk_in),
|
||||
.adc_clk_in(adc_clk_in),
|
||||
.rst_n(rst_n),
|
||||
.s_axil(axil_bus),
|
||||
|
||||
.finish(finish),
|
||||
.adc_window_size(adc_window_size),
|
||||
|
||||
.dac_pulse_width(dac_pulse_width),
|
||||
.dac_pulse_period(dac_pulse_period),
|
||||
.dac_pulse_height(dac_pulse_height),
|
||||
.dac_pulse_num(dac_pulse_num),
|
||||
|
||||
.adc_pulse_period(adc_pulse_period),
|
||||
.adc_pulse_num(adc_pulse_num),
|
||||
|
||||
.dac_start(dac_start),
|
||||
.adc_start(adc_start),
|
||||
.dac_rst(dac_rst),
|
||||
.adc_rst(adc_rst),
|
||||
|
||||
.m_axis_read_data(dma_read_data),
|
||||
.s_axis_write_data(dma_write_data)
|
||||
);
|
||||
|
||||
endmodule : tb_controller_wrapper_axil
|
||||
@@ -0,0 +1,194 @@
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotbext.axi import AxiLiteBus, AxiLiteMaster
|
||||
from cocotbext.axi import AxiBus, AxiRam, AxiStreamBus, AxiStreamSource, AxiStreamSink, AxiStreamFrame
|
||||
|
||||
|
||||
# Register indexes from axi4l_reg_map_controller_pkg.sv
|
||||
REG_CONTROL = 0
|
||||
REG_STATUS = 1
|
||||
REG_DAC_WIDTH = 2
|
||||
REG_DAC_PERIOD = 3
|
||||
REG_DAC_PULSE_NUM = 4
|
||||
REG_DAC_PULSE_HEIGHT = 5
|
||||
REG_ADC_PERIOD = 6
|
||||
REG_WINDOW_SIZE = 7
|
||||
REG_ERROR = 8
|
||||
REG_DESC_READ_ADDR = 9
|
||||
REG_DESC_READ_LEN = 10
|
||||
REG_DESC_READ_CONFIG = 11
|
||||
REG_READ_STATUS = 12
|
||||
REG_DESC_WRITE_ADDR = 13
|
||||
REG_DESC_WRITE_LEN_AND_TAG = 14
|
||||
REG_STATUS_WRITE_LEN = 15
|
||||
REG_STATUS_WRITE_CONFIG = 16
|
||||
|
||||
|
||||
# REG_CONTROL pulse bits
|
||||
CTRL_START = 0
|
||||
CTRL_RST_SOFT = 1
|
||||
CTRL_CFG_BUS_VALID = 2
|
||||
CTRL_SEND_DESC_READ = 3
|
||||
CTRL_SEND_DESC_WRITE = 4
|
||||
CTRL_TAKE_STATUS_READ = 5
|
||||
CTRL_TAKE_STATUS_WRITE = 6
|
||||
|
||||
|
||||
def reg_addr(reg_index: int) -> int:
|
||||
# AXI-Lite uses byte addresses, 32-bit registers are spaced by 4 bytes.
|
||||
return reg_index * 4
|
||||
|
||||
|
||||
def u32(value: int) -> bytes:
|
||||
return int(value & 0xFFFFFFFF).to_bytes(4, "little")
|
||||
|
||||
|
||||
class TB:
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
cocotb.start_soon(Clock(dut.ctrl_clk, 10, units="ns").start())
|
||||
|
||||
self.axil = AxiLiteMaster(
|
||||
AxiLiteBus.from_prefix(dut, "s_axil"),
|
||||
dut.ctrl_clk,
|
||||
dut.rst
|
||||
)
|
||||
|
||||
|
||||
self.axis_source = AxiStreamSource(
|
||||
AxiStreamBus.from_prefix(dut, "s_axis_write_data"),
|
||||
dut.ctrl_clk,
|
||||
dut.rst
|
||||
)
|
||||
|
||||
self.axis_sink = AxiStreamSink(
|
||||
AxiStreamBus.from_prefix(dut, "m_axis_read_data"),
|
||||
dut.ctrl_clk,
|
||||
dut.rst
|
||||
)
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.value = 1
|
||||
for _ in range(5):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
self.dut.rst.value = 0
|
||||
for _ in range(5):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
async def write_reg(self, reg_index: int, value: int):
|
||||
await self.axil.write(reg_addr(reg_index), u32(value))
|
||||
|
||||
async def read_reg(self, reg_index: int) -> int:
|
||||
resp = await self.axil.read(reg_addr(reg_index), 4)
|
||||
return int.from_bytes(bytes(resp.data), "little")
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def simple_axil_write_read(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
|
||||
await tb.write_reg(REG_DAC_WIDTH, 0x0000_0123)
|
||||
|
||||
value = await tb.read_reg(REG_DAC_WIDTH)
|
||||
assert value == 0x0000_0123
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def simple_controller_config_write(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
|
||||
await tb.write_reg(REG_DAC_WIDTH, 0x10)
|
||||
await tb.write_reg(REG_DAC_PERIOD, 0x40)
|
||||
await tb.write_reg(REG_DAC_PULSE_NUM, 3)
|
||||
await tb.write_reg(REG_DAC_PULSE_HEIGHT, 0x7FF)
|
||||
await tb.write_reg(REG_ADC_PERIOD, 0x80)
|
||||
await tb.write_reg(REG_WINDOW_SIZE, 16)
|
||||
|
||||
assert await tb.read_reg(REG_DAC_WIDTH) == 0x10
|
||||
assert await tb.read_reg(REG_WINDOW_SIZE) == 16
|
||||
|
||||
# write data: set cfg_bus_valid signal
|
||||
await tb.write_reg(REG_CONTROL, 1 << CTRL_CFG_BUS_VALID)
|
||||
|
||||
# wait
|
||||
for _ in range(30):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
# check config
|
||||
assert int(dut.dac_pulse_width) == 0x10
|
||||
assert int(dut.dac_pulse_period) == 0x40
|
||||
assert int(dut.dac_pulse_num) == 3
|
||||
assert int(dut.dac_pulse_height) == 0x7FF
|
||||
assert int(dut.adc_pulse_period) == 0x80
|
||||
assert int(dut.adc_window_size) == 16
|
||||
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def simple_controller_start_check(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
await tb.write_reg(REG_CONTROL, 1 << CTRL_START)
|
||||
|
||||
await RisingEdge(dut.dac_start)
|
||||
|
||||
@cocotb.test()
|
||||
async def simple_dma_mem_to_mem(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
|
||||
SRC_ADDR = 0x1000
|
||||
LENGTH = 8
|
||||
|
||||
tx_data = bytes([ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 ])
|
||||
|
||||
## write part
|
||||
|
||||
await tb.write_reg(REG_DESC_WRITE_ADDR, SRC_ADDR)
|
||||
await tb.write_reg(REG_DESC_WRITE_LEN_AND_TAG, LENGTH)
|
||||
|
||||
await tb.write_reg(REG_CONTROL, 1 << CTRL_SEND_DESC_WRITE)
|
||||
|
||||
await tb.axis_source.send(AxiStreamFrame(tx_data))
|
||||
|
||||
for _ in range(20):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
await tb.write_reg(REG_CONTROL, 1 << CTRL_TAKE_STATUS_WRITE)
|
||||
|
||||
for _ in range(10):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
|
||||
assert await tb.read_reg(REG_STATUS_WRITE_CONFIG) == 0
|
||||
assert await tb.read_reg(REG_STATUS_WRITE_LEN) == 0x8
|
||||
|
||||
## read part
|
||||
|
||||
await tb.write_reg(REG_DESC_READ_ADDR, SRC_ADDR)
|
||||
await tb.write_reg(REG_DESC_READ_LEN, LENGTH)
|
||||
await tb.write_reg(REG_DESC_READ_CONFIG, 0x0000_0001)
|
||||
|
||||
await tb.write_reg(REG_CONTROL, 1 << CTRL_SEND_DESC_READ)
|
||||
|
||||
rx_frame = await tb.axis_sink.recv()
|
||||
|
||||
for _ in range(20):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
await tb.write_reg(REG_CONTROL, 1 << CTRL_TAKE_STATUS_READ)
|
||||
|
||||
for _ in range(10):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
assert await tb.read_reg(REG_READ_STATUS) == 0x1
|
||||
|
||||
assert bytes(rx_frame) == tx_data
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# Primary clocks
|
||||
create_clock -name eth_clk -period 8.000 [get_ports eth_clk_in]
|
||||
create_clock -name dac_clk -period 7.692 [get_ports dac_clk_in]
|
||||
create_clock -name adc_clk -period 15.385 [get_ports adc_clk_in]
|
||||
|
||||
|
||||
# Asynchronous clock groups
|
||||
# eth, dac, adc are independent domains
|
||||
|
||||
set_clock_groups -name ASYNC_ETH_DAC_ADC -asynchronous \
|
||||
-group [get_clocks eth_clk] \
|
||||
-group [get_clocks dac_clk] \
|
||||
-group [get_clocks adc_clk]
|
||||
@@ -0,0 +1,199 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// SystemVerilog interface wrapper around alexforencich/verilog-axi axi_dma.v.
|
||||
//
|
||||
// AXI memory, AXI-Stream data, DMA descriptor, and DMA status channels are all
|
||||
// exposed through compact interfaces. The original Forencich core remains
|
||||
// untouched and is connected through local flat wires.
|
||||
|
||||
import dma_reg_pkg::*;
|
||||
import axi_pkg::*;
|
||||
|
||||
// DMA Specific wrappers & converters
|
||||
module axi_dma_wrapper #(
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0
|
||||
)(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
|
||||
axis_if.slave s_axis_read_desc,
|
||||
|
||||
axis_if.master m_axis_read_desc_status,
|
||||
|
||||
axis_if.master m_axis_read_data,
|
||||
|
||||
axis_if.slave s_axis_write_desc,
|
||||
|
||||
axis_if.master m_axis_write_desc_status,
|
||||
|
||||
axis_if.slave s_axis_write_data,
|
||||
|
||||
axi4_if.master m_axi
|
||||
);
|
||||
|
||||
dma_read_desc_t read_desc;
|
||||
assign read_desc = dma_read_desc_t'(s_axis_read_desc.req.t.data);
|
||||
|
||||
|
||||
dma_write_desc_t write_desc;
|
||||
assign write_desc = dma_write_desc_t'(s_axis_write_desc.req.t.data);
|
||||
|
||||
|
||||
dma_read_status_t read_status;
|
||||
assign m_axis_read_desc_status.req.t.data = read_status;
|
||||
logic m_axis_read_desc_status_valid;
|
||||
assign m_axis_read_desc_status.req.t.valid = m_axis_read_desc_status_valid;
|
||||
|
||||
|
||||
|
||||
dma_write_status_t write_status;
|
||||
assign m_axis_write_desc_status.req.t.data = write_status;
|
||||
logic m_axis_write_desc_status_valid;
|
||||
assign m_axis_write_desc_status.req.t.valid = m_axis_write_desc_status_valid;
|
||||
|
||||
logic [1:0] dma_awburst;
|
||||
logic [1:0] dma_arburst;
|
||||
logic [1:0] dma_bresp;
|
||||
logic [1:0] dma_rresp;
|
||||
|
||||
assign m_axi.req.aw.burst = axi_pkg::axi_burst_t'(dma_awburst);
|
||||
assign m_axi.req.ar.burst = axi_pkg::axi_burst_t'(dma_arburst);
|
||||
|
||||
assign dma_bresp = logic'(m_axi.resp.b.resp);
|
||||
assign dma_rresp = logic'(m_axi.resp.r.resp);
|
||||
|
||||
// Original DMA: flat ports only.
|
||||
axi_dma #(
|
||||
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
|
||||
.AXI_ADDR_WIDTH (dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.AXI_STRB_WIDTH (AXI_STRB_WIDTH),
|
||||
.AXI_ID_WIDTH (AXI_ID_WIDTH),
|
||||
.AXI_MAX_BURST_LEN (AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH (AXIS_DATA_WIDTH),
|
||||
.AXIS_KEEP_ENABLE (AXIS_KEEP_ENABLE),
|
||||
.AXIS_KEEP_WIDTH (AXIS_KEEP_WIDTH),
|
||||
.AXIS_LAST_ENABLE (AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE (AXIS_ID_ENABLE),
|
||||
.AXIS_ID_WIDTH (dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.AXIS_DEST_ENABLE (AXIS_DEST_ENABLE),
|
||||
.AXIS_DEST_WIDTH (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.AXIS_USER_ENABLE (AXIS_USER_ENABLE),
|
||||
.AXIS_USER_WIDTH (dma_reg_pkg::AXIS_USER_WIDTH),
|
||||
.LEN_WIDTH (dma_reg_pkg::LEN_WIDTH),
|
||||
.TAG_WIDTH (dma_reg_pkg::TAG_WIDTH),
|
||||
.ENABLE_SG (ENABLE_SG),
|
||||
.ENABLE_UNALIGNED (ENABLE_UNALIGNED)
|
||||
) i_axi_dma (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.s_axis_read_desc_addr (read_desc.addr),
|
||||
.s_axis_read_desc_len (read_desc.len),
|
||||
.s_axis_read_desc_tag (read_desc.tag),
|
||||
.s_axis_read_desc_id (read_desc.id),
|
||||
.s_axis_read_desc_dest (read_desc.dest),
|
||||
.s_axis_read_desc_user (read_desc.user),
|
||||
.s_axis_read_desc_valid (s_axis_read_desc.req.t.valid),
|
||||
.s_axis_read_desc_ready (s_axis_read_desc.resp.ready),
|
||||
|
||||
.m_axis_read_desc_status_tag (read_status.tag),
|
||||
.m_axis_read_desc_status_error (read_status.error),
|
||||
.m_axis_read_desc_status_valid (m_axis_read_desc_status_valid),
|
||||
|
||||
.m_axis_read_data_tdata (m_axis_read_data.req.t.data),
|
||||
.m_axis_read_data_tkeep (m_axis_read_data.req.t.keep),
|
||||
.m_axis_read_data_tvalid (m_axis_read_data.req.t.valid),
|
||||
.m_axis_read_data_tready (m_axis_read_data.resp.ready),
|
||||
.m_axis_read_data_tlast (m_axis_read_data.req.t.last),
|
||||
.m_axis_read_data_tid (m_axis_read_data.req.t.id),
|
||||
.m_axis_read_data_tdest (m_axis_read_data.req.t.dest),
|
||||
.m_axis_read_data_tuser (m_axis_read_data.req.t.user),
|
||||
|
||||
.s_axis_write_desc_addr (write_desc.addr),
|
||||
.s_axis_write_desc_len (write_desc.len),
|
||||
.s_axis_write_desc_tag (write_desc.tag),
|
||||
.s_axis_write_desc_valid (s_axis_write_desc.req.t.valid),
|
||||
.s_axis_write_desc_ready (s_axis_write_desc.resp.ready),
|
||||
|
||||
.m_axis_write_desc_status_len (write_status.len),
|
||||
.m_axis_write_desc_status_tag (write_status.tag),
|
||||
.m_axis_write_desc_status_id (write_status.id),
|
||||
.m_axis_write_desc_status_dest (write_status.dest),
|
||||
.m_axis_write_desc_status_user (write_status.user),
|
||||
.m_axis_write_desc_status_error (write_status.error),
|
||||
.m_axis_write_desc_status_valid (m_axis_write_desc_status_valid),
|
||||
|
||||
.s_axis_write_data_tdata (s_axis_write_data.req.t.data),
|
||||
.s_axis_write_data_tkeep (s_axis_write_data.req.t.keep),
|
||||
.s_axis_write_data_tvalid (s_axis_write_data.req.t.valid),
|
||||
.s_axis_write_data_tready (s_axis_write_data.resp.ready),
|
||||
.s_axis_write_data_tlast (s_axis_write_data.req.t.last),
|
||||
.s_axis_write_data_tid (s_axis_write_data.req.t.id),
|
||||
.s_axis_write_data_tdest (s_axis_write_data.req.t.dest),
|
||||
.s_axis_write_data_tuser (s_axis_write_data.req.t.user),
|
||||
|
||||
.m_axi_awid (m_axi.req.aw.id),
|
||||
.m_axi_awaddr (m_axi.req.aw.addr),
|
||||
.m_axi_awlen (m_axi.req.aw.len),
|
||||
.m_axi_awsize (m_axi.req.aw.size),
|
||||
.m_axi_awburst (dma_awburst),
|
||||
.m_axi_awlock (m_axi.req.aw.lock),
|
||||
.m_axi_awcache (m_axi.req.aw.cache),
|
||||
.m_axi_awprot (m_axi.req.aw.prot),
|
||||
.m_axi_awvalid (m_axi.req.aw.valid),
|
||||
.m_axi_awready (m_axi.resp.aw_ready),
|
||||
|
||||
.m_axi_wdata (m_axi.req.w.data),
|
||||
.m_axi_wstrb (m_axi.req.w.strb),
|
||||
.m_axi_wlast ( m_axi.req.w.last),
|
||||
.m_axi_wvalid (m_axi.req.w.valid),
|
||||
.m_axi_wready (m_axi.resp.w_ready),
|
||||
|
||||
.m_axi_bid (m_axi.resp.b.id),
|
||||
.m_axi_bresp (dma_bresp),
|
||||
.m_axi_bvalid (m_axi.resp.b.valid),
|
||||
.m_axi_bready (m_axi.req.b_ready),
|
||||
|
||||
.m_axi_arid (m_axi.req.ar.id),
|
||||
.m_axi_araddr (m_axi.req.ar.addr),
|
||||
.m_axi_arlen (m_axi.req.ar.len),
|
||||
.m_axi_arsize (m_axi.req.ar.size),
|
||||
.m_axi_arburst (dma_arburst),
|
||||
.m_axi_arlock (m_axi.req.ar.lock),
|
||||
.m_axi_arcache (m_axi.req.ar.cache),
|
||||
.m_axi_arprot (m_axi.req.ar.prot),
|
||||
.m_axi_arvalid (m_axi.req.ar.valid),
|
||||
.m_axi_arready (m_axi.resp.ar_ready),
|
||||
|
||||
.m_axi_rid (m_axi.resp.r.id),
|
||||
.m_axi_rdata (m_axi.resp.r.data),
|
||||
.m_axi_rresp (dma_rresp),
|
||||
.m_axi_rlast (m_axi.resp.r.last),
|
||||
.m_axi_rvalid (m_axi.resp.r.valid),
|
||||
.m_axi_rready (m_axi.req.r_ready),
|
||||
|
||||
.read_enable (1'b1),
|
||||
.write_enable (1'b1),
|
||||
.write_abort (1'b0)
|
||||
);
|
||||
|
||||
|
||||
endmodule : axi_dma_wrapper
|
||||
|
||||
`default_nettype wire
|
||||
@@ -0,0 +1,67 @@
|
||||
module axi_ram_wrapper
|
||||
#(
|
||||
parameter int unsigned DATA_WIDTH = 32,
|
||||
parameter int unsigned ADDR_WIDTH = 16,
|
||||
parameter int unsigned ID_WIDTH = 8,
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0
|
||||
)
|
||||
(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
axi4_if.slave s_axi
|
||||
);
|
||||
|
||||
logic [1:0] ram_bresp;
|
||||
logic [1:0] ram_rresp;
|
||||
|
||||
|
||||
assign s_axi.resp.b.resp = axi_pkg::axi_resp_t'(ram_bresp);
|
||||
assign s_axi.resp.r.resp = axi_pkg::axi_resp_t'(ram_rresp);
|
||||
|
||||
axi_ram
|
||||
#(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.ADDR_WIDTH(ADDR_WIDTH),
|
||||
.ID_WIDTH(ID_WIDTH),
|
||||
.PIPELINE_OUTPUT(PIPELINE_OUTPUT)
|
||||
) axi_ram_inst
|
||||
(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axi_awid(s_axi.req.aw.id),
|
||||
.s_axi_awaddr(s_axi.req.aw.addr),
|
||||
.s_axi_awlen(s_axi.req.aw.len),
|
||||
.s_axi_awsize(s_axi.req.aw.size),
|
||||
.s_axi_awburst(s_axi.req.aw.burst),
|
||||
.s_axi_awlock(s_axi.req.aw.lock),
|
||||
.s_axi_awcache(s_axi.req.aw.cache),
|
||||
.s_axi_awprot(s_axi.req.aw.prot),
|
||||
.s_axi_awvalid(s_axi.req.aw.valid),
|
||||
.s_axi_awready(s_axi.resp.aw_ready),
|
||||
.s_axi_wdata(s_axi.req.w.data),
|
||||
.s_axi_wstrb(s_axi.req.w.strb),
|
||||
.s_axi_wlast(s_axi.req.w.last),
|
||||
.s_axi_wvalid(s_axi.req.w.valid),
|
||||
.s_axi_wready(s_axi.resp.w_ready),
|
||||
.s_axi_bid(s_axi.resp.b.id),
|
||||
.s_axi_bresp(ram_bresp),
|
||||
.s_axi_bvalid(s_axi.resp.b.valid),
|
||||
.s_axi_bready(s_axi.req.b_ready),
|
||||
.s_axi_arid(s_axi.req.ar.id),
|
||||
.s_axi_araddr(s_axi.req.ar.addr),
|
||||
.s_axi_arlen(s_axi.req.ar.len),
|
||||
.s_axi_arsize(s_axi.req.ar.size),
|
||||
.s_axi_arburst(s_axi.req.ar.burst),
|
||||
.s_axi_arlock(s_axi.req.ar.lock),
|
||||
.s_axi_arcache(s_axi.req.ar.cache),
|
||||
.s_axi_arprot(s_axi.req.ar.prot),
|
||||
.s_axi_arvalid(s_axi.req.ar.valid),
|
||||
.s_axi_arready(s_axi.resp.ar_ready),
|
||||
.s_axi_rid(s_axi.resp.r.id),
|
||||
.s_axi_rdata(s_axi.resp.r.data),
|
||||
.s_axi_rresp(ram_rresp),
|
||||
.s_axi_rlast(s_axi.resp.r.last),
|
||||
.s_axi_rvalid(s_axi.resp.r.valid),
|
||||
.s_axi_rready(s_axi.req.r_ready)
|
||||
);
|
||||
endmodule
|
||||
@@ -0,0 +1,101 @@
|
||||
|
||||
// file: clk_wiz_0.v
|
||||
//
|
||||
// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
|
||||
//
|
||||
// This file contains confidential and proprietary information
|
||||
// of Xilinx, Inc. and is protected under U.S. and
|
||||
// international copyright and other intellectual property
|
||||
// laws.
|
||||
//
|
||||
// DISCLAIMER
|
||||
// This disclaimer is not a license and does not grant any
|
||||
// rights to the materials distributed herewith. Except as
|
||||
// otherwise provided in a valid license issued to you by
|
||||
// Xilinx, and to the maximum extent permitted by applicable
|
||||
// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
|
||||
// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
|
||||
// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
|
||||
// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
|
||||
// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
|
||||
// (2) Xilinx shall not be liable (whether in contract or tort,
|
||||
// including negligence, or under any other theory of
|
||||
// liability) for any loss or damage of any kind or nature
|
||||
// related to, arising under or in connection with these
|
||||
// materials, including for any direct, or any indirect,
|
||||
// special, incidental, or consequential loss or damage
|
||||
// (including loss of data, profits, goodwill, or any type of
|
||||
// loss or damage suffered as a result of any action brought
|
||||
// by a third party) even if such damage or loss was
|
||||
// reasonably foreseeable or Xilinx had been advised of the
|
||||
// possibility of the same.
|
||||
//
|
||||
// CRITICAL APPLICATIONS
|
||||
// Xilinx products are not designed or intended to be fail-
|
||||
// safe, or for use in any application requiring fail-safe
|
||||
// performance, such as life-support or safety devices or
|
||||
// systems, Class III medical devices, nuclear facilities,
|
||||
// applications related to the deployment of airbags, or any
|
||||
// other applications that could lead to death, personal
|
||||
// injury, or severe property or environmental damage
|
||||
// (individually and collectively, "Critical
|
||||
// Applications"). Customer assumes the sole risk and
|
||||
// liability of any use of Xilinx products in Critical
|
||||
// Applications, subject only to applicable laws and
|
||||
// regulations governing limitations on product liability.
|
||||
//
|
||||
// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
|
||||
// PART OF THIS FILE AT ALL TIMES.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// User entered comments
|
||||
//----------------------------------------------------------------------------
|
||||
// None
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Output Output Phase Duty Cycle Pk-to-Pk Phase
|
||||
// Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps)
|
||||
//----------------------------------------------------------------------------
|
||||
// clk_adc_65__65.00000______0.000______50.0______137.256____148.044
|
||||
// clk_adc_65_180__65.00000______0.000______50.0______137.256____148.044
|
||||
// clk_dac_125__124.09091______0.000______50.0______123.850____148.044
|
||||
// clk_dac_125_180__124.09091______0.000______50.0______123.850____148.044
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Input Clock Freq (MHz) Input Jitter (UI)
|
||||
//----------------------------------------------------------------------------
|
||||
// __primary_________200.000____________0.010
|
||||
|
||||
`timescale 1ps/1ps
|
||||
|
||||
(* CORE_GENERATION_INFO = "clk_wiz_0,clk_wiz_v6_0_9_0_0,{component_name=clk_wiz_0,use_phase_alignment=true,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,enable_axi=0,feedback_source=FDBK_AUTO,PRIMITIVE=MMCM,num_out_clk=4,clkin1_period=5.000,clkin2_period=10.000,use_power_down=false,use_reset=true,use_locked=true,use_inclk_stopped=false,feedback_type=SINGLE,CLOCK_MGR_TYPE=NA,manual_override=false}" *)
|
||||
|
||||
module clk_wiz_0
|
||||
(
|
||||
// Clock out ports
|
||||
output clk_adc_65,
|
||||
output clk_adc_65_180,
|
||||
output clk_dac_125,
|
||||
output clk_dac_125_180,
|
||||
// Status and control signals
|
||||
input reset,
|
||||
output locked,
|
||||
// Clock in ports
|
||||
input clk_200
|
||||
);
|
||||
|
||||
clk_wiz_0_clk_wiz inst
|
||||
(
|
||||
// Clock out ports
|
||||
.clk_adc_65(clk_adc_65),
|
||||
.clk_adc_65_180(clk_adc_65_180),
|
||||
.clk_dac_125(clk_dac_125),
|
||||
.clk_dac_125_180(clk_dac_125_180),
|
||||
// Status and control signals
|
||||
.reset(reset),
|
||||
.locked(locked),
|
||||
// Clock in ports
|
||||
.clk_200(clk_200)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
//
|
||||
// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
|
||||
//
|
||||
// This file contains confidential and proprietary information
|
||||
// of Xilinx, Inc. and is protected under U.S. and
|
||||
// international copyright and other intellectual property
|
||||
// laws.
|
||||
//
|
||||
// DISCLAIMER
|
||||
// This disclaimer is not a license and does not grant any
|
||||
// rights to the materials distributed herewith. Except as
|
||||
// otherwise provided in a valid license issued to you by
|
||||
// Xilinx, and to the maximum extent permitted by applicable
|
||||
// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
|
||||
// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
|
||||
// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
|
||||
// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
|
||||
// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
|
||||
// (2) Xilinx shall not be liable (whether in contract or tort,
|
||||
// including negligence, or under any other theory of
|
||||
// liability) for any loss or damage of any kind or nature
|
||||
// related to, arising under or in connection with these
|
||||
// materials, including for any direct, or any indirect,
|
||||
// special, incidental, or consequential loss or damage
|
||||
// (including loss of data, profits, goodwill, or any type of
|
||||
// loss or damage suffered as a result of any action brought
|
||||
// by a third party) even if such damage or loss was
|
||||
// reasonably foreseeable or Xilinx had been advised of the
|
||||
// possibility of the same.
|
||||
//
|
||||
// CRITICAL APPLICATIONS
|
||||
// Xilinx products are not designed or intended to be fail-
|
||||
// safe, or for use in any application requiring fail-safe
|
||||
// performance, such as life-support or safety devices or
|
||||
// systems, Class III medical devices, nuclear facilities,
|
||||
// applications related to the deployment of airbags, or any
|
||||
// other applications that could lead to death, personal
|
||||
// injury, or severe property or environmental damage
|
||||
// (individually and collectively, "Critical
|
||||
// Applications"). Customer assumes the sole risk and
|
||||
// liability of any use of Xilinx products in Critical
|
||||
// Applications, subject only to applicable laws and
|
||||
// regulations governing limitations on product liability.
|
||||
//
|
||||
// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
|
||||
// PART OF THIS FILE AT ALL TIMES.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// User entered comments
|
||||
//----------------------------------------------------------------------------
|
||||
// None
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Output Output Phase Duty Cycle Pk-to-Pk Phase
|
||||
// Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps)
|
||||
//----------------------------------------------------------------------------
|
||||
// clk_adc_65__65.00000______0.000______50.0______137.256____148.044
|
||||
// clk_adc_65_180__65.00000______0.000______50.0______137.256____148.044
|
||||
// clk_dac_125__124.09091______0.000______50.0______123.850____148.044
|
||||
// clk_dac_125_180__124.09091______0.000______50.0______123.850____148.044
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Input Clock Freq (MHz) Input Jitter (UI)
|
||||
//----------------------------------------------------------------------------
|
||||
// __primary_________200.000____________0.010
|
||||
|
||||
// The following must be inserted into your Verilog file for this
|
||||
// core to be instantiated. Change the instance name and port connections
|
||||
// (in parentheses) to your own signal names.
|
||||
|
||||
//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
|
||||
|
||||
clk_wiz_0 instance_name
|
||||
(
|
||||
// Clock out ports
|
||||
.clk_adc_65(clk_adc_65), // output clk_adc_65
|
||||
.clk_adc_65_180(clk_adc_65_180), // output clk_adc_65_180
|
||||
.clk_dac_125(clk_dac_125), // output clk_dac_125
|
||||
.clk_dac_125_180(clk_dac_125_180), // output clk_dac_125_180
|
||||
// Status and control signals
|
||||
.reset(reset), // input reset
|
||||
.locked(locked), // output locked
|
||||
// Clock in ports
|
||||
.clk_200(clk_200)); // input clk_200
|
||||
|
||||
// INST_TAG_END ------ End INSTANTIATION Template ---------
|
||||
@@ -0,0 +1,60 @@
|
||||
|
||||
# file: clk_wiz_0.xdc
|
||||
#
|
||||
# (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
|
||||
#
|
||||
# This file contains confidential and proprietary information
|
||||
# of Xilinx, Inc. and is protected under U.S. and
|
||||
# international copyright and other intellectual property
|
||||
# laws.
|
||||
#
|
||||
# DISCLAIMER
|
||||
# This disclaimer is not a license and does not grant any
|
||||
# rights to the materials distributed herewith. Except as
|
||||
# otherwise provided in a valid license issued to you by
|
||||
# Xilinx, and to the maximum extent permitted by applicable
|
||||
# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
|
||||
# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
|
||||
# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
|
||||
# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
|
||||
# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
|
||||
# (2) Xilinx shall not be liable (whether in contract or tort,
|
||||
# including negligence, or under any other theory of
|
||||
# liability) for any loss or damage of any kind or nature
|
||||
# related to, arising under or in connection with these
|
||||
# materials, including for any direct, or any indirect,
|
||||
# special, incidental, or consequential loss or damage
|
||||
# (including loss of data, profits, goodwill, or any type of
|
||||
# loss or damage suffered as a result of any action brought
|
||||
# by a third party) even if such damage or loss was
|
||||
# reasonably foreseeable or Xilinx had been advised of the
|
||||
# possibility of the same.
|
||||
#
|
||||
# CRITICAL APPLICATIONS
|
||||
# Xilinx products are not designed or intended to be fail-
|
||||
# safe, or for use in any application requiring fail-safe
|
||||
# performance, such as life-support or safety devices or
|
||||
# systems, Class III medical devices, nuclear facilities,
|
||||
# applications related to the deployment of airbags, or any
|
||||
# other applications that could lead to death, personal
|
||||
# injury, or severe property or environmental damage
|
||||
# (individually and collectively, "Critical
|
||||
# Applications"). Customer assumes the sole risk and
|
||||
# liability of any use of Xilinx products in Critical
|
||||
# Applications, subject only to applicable laws and
|
||||
# regulations governing limitations on product liability.
|
||||
#
|
||||
# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
|
||||
# PART OF THIS FILE AT ALL TIMES.
|
||||
#
|
||||
|
||||
# Input clock periods. These duplicate the values entered for the
|
||||
# input clocks. You can use these to time your system. If required
|
||||
# commented constraints can be used in the top level xdc
|
||||
#----------------------------------------------------------------
|
||||
# Connect to input port when clock capable pin is selected for input
|
||||
create_clock -period 5.000 [get_ports clk_200]
|
||||
set_input_jitter [get_clocks -of_objects [get_ports clk_200]] 0.050
|
||||
|
||||
|
||||
set_property PHASESHIFT_MODE WAVEFORM [get_cells -hierarchical *adv*]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
#--------------------Physical Constraints-----------------
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
|
||||
// file: clk_wiz_0.v
|
||||
//
|
||||
// (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
|
||||
//
|
||||
// This file contains confidential and proprietary information
|
||||
// of Xilinx, Inc. and is protected under U.S. and
|
||||
// international copyright and other intellectual property
|
||||
// laws.
|
||||
//
|
||||
// DISCLAIMER
|
||||
// This disclaimer is not a license and does not grant any
|
||||
// rights to the materials distributed herewith. Except as
|
||||
// otherwise provided in a valid license issued to you by
|
||||
// Xilinx, and to the maximum extent permitted by applicable
|
||||
// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
|
||||
// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
|
||||
// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
|
||||
// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
|
||||
// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
|
||||
// (2) Xilinx shall not be liable (whether in contract or tort,
|
||||
// including negligence, or under any other theory of
|
||||
// liability) for any loss or damage of any kind or nature
|
||||
// related to, arising under or in connection with these
|
||||
// materials, including for any direct, or any indirect,
|
||||
// special, incidental, or consequential loss or damage
|
||||
// (including loss of data, profits, goodwill, or any type of
|
||||
// loss or damage suffered as a result of any action brought
|
||||
// by a third party) even if such damage or loss was
|
||||
// reasonably foreseeable or Xilinx had been advised of the
|
||||
// possibility of the same.
|
||||
//
|
||||
// CRITICAL APPLICATIONS
|
||||
// Xilinx products are not designed or intended to be fail-
|
||||
// safe, or for use in any application requiring fail-safe
|
||||
// performance, such as life-support or safety devices or
|
||||
// systems, Class III medical devices, nuclear facilities,
|
||||
// applications related to the deployment of airbags, or any
|
||||
// other applications that could lead to death, personal
|
||||
// injury, or severe property or environmental damage
|
||||
// (individually and collectively, "Critical
|
||||
// Applications"). Customer assumes the sole risk and
|
||||
// liability of any use of Xilinx products in Critical
|
||||
// Applications, subject only to applicable laws and
|
||||
// regulations governing limitations on product liability.
|
||||
//
|
||||
// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
|
||||
// PART OF THIS FILE AT ALL TIMES.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// User entered comments
|
||||
//----------------------------------------------------------------------------
|
||||
// None
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Output Output Phase Duty Cycle Pk-to-Pk Phase
|
||||
// Clock Freq (MHz) (degrees) (%) Jitter (ps) Error (ps)
|
||||
//----------------------------------------------------------------------------
|
||||
// clk_adc_65__65.00000______0.000______50.0______137.256____148.044
|
||||
// clk_adc_65_180__65.00000______0.000______50.0______137.256____148.044
|
||||
// clk_dac_125__124.09091______0.000______50.0______123.850____148.044
|
||||
// clk_dac_125_180__124.09091______0.000______50.0______123.850____148.044
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Input Clock Freq (MHz) Input Jitter (UI)
|
||||
//----------------------------------------------------------------------------
|
||||
// __primary_________200.000____________0.010
|
||||
|
||||
`timescale 1ps/1ps
|
||||
|
||||
module clk_wiz_0_clk_wiz
|
||||
|
||||
(// Clock in ports
|
||||
// Clock out ports
|
||||
output clk_adc_65,
|
||||
output clk_adc_65_180,
|
||||
output clk_dac_125,
|
||||
output clk_dac_125_180,
|
||||
// Status and control signals
|
||||
input reset,
|
||||
output locked,
|
||||
input clk_200
|
||||
);
|
||||
// Input buffering
|
||||
//------------------------------------
|
||||
wire clk_200_clk_wiz_0;
|
||||
wire clk_in2_clk_wiz_0;
|
||||
IBUF clkin1_ibufg
|
||||
(.O (clk_200_clk_wiz_0),
|
||||
.I (clk_200));
|
||||
|
||||
|
||||
|
||||
|
||||
// Clocking PRIMITIVE
|
||||
//------------------------------------
|
||||
|
||||
// Instantiation of the MMCM PRIMITIVE
|
||||
// * Unused inputs are tied off
|
||||
// * Unused outputs are labeled unused
|
||||
|
||||
wire clk_adc_65_clk_wiz_0;
|
||||
wire clk_adc_65_180_clk_wiz_0;
|
||||
wire clk_dac_125_clk_wiz_0;
|
||||
wire clk_dac_125_180_clk_wiz_0;
|
||||
wire clk_out5_clk_wiz_0;
|
||||
wire clk_out6_clk_wiz_0;
|
||||
wire clk_out7_clk_wiz_0;
|
||||
|
||||
wire [15:0] do_unused;
|
||||
wire drdy_unused;
|
||||
wire psdone_unused;
|
||||
wire locked_int;
|
||||
wire clkfbout_clk_wiz_0;
|
||||
wire clkfbout_buf_clk_wiz_0;
|
||||
wire clkfboutb_unused;
|
||||
wire clkout0b_unused;
|
||||
wire clkout1b_unused;
|
||||
wire clkout2b_unused;
|
||||
wire clkout3b_unused;
|
||||
wire clkout4_unused;
|
||||
wire clkout5_unused;
|
||||
wire clkout6_unused;
|
||||
wire clkfbstopped_unused;
|
||||
wire clkinstopped_unused;
|
||||
wire reset_high;
|
||||
|
||||
MMCME2_ADV
|
||||
#(.BANDWIDTH ("OPTIMIZED"),
|
||||
.CLKOUT4_CASCADE ("FALSE"),
|
||||
.COMPENSATION ("ZHOLD"),
|
||||
.STARTUP_WAIT ("FALSE"),
|
||||
.DIVCLK_DIVIDE (5),
|
||||
.CLKFBOUT_MULT_F (34.125),
|
||||
.CLKFBOUT_PHASE (0.000),
|
||||
.CLKFBOUT_USE_FINE_PS ("FALSE"),
|
||||
.CLKOUT0_DIVIDE_F (21.000),
|
||||
.CLKOUT0_PHASE (0.000),
|
||||
.CLKOUT0_DUTY_CYCLE (0.500),
|
||||
.CLKOUT0_USE_FINE_PS ("FALSE"),
|
||||
.CLKOUT1_DIVIDE (21),
|
||||
.CLKOUT1_PHASE (0.000),
|
||||
.CLKOUT1_DUTY_CYCLE (0.500),
|
||||
.CLKOUT1_USE_FINE_PS ("FALSE"),
|
||||
.CLKOUT2_DIVIDE (11),
|
||||
.CLKOUT2_PHASE (0.000),
|
||||
.CLKOUT2_DUTY_CYCLE (0.500),
|
||||
.CLKOUT2_USE_FINE_PS ("FALSE"),
|
||||
.CLKOUT3_DIVIDE (11),
|
||||
.CLKOUT3_PHASE (0.000),
|
||||
.CLKOUT3_DUTY_CYCLE (0.500),
|
||||
.CLKOUT3_USE_FINE_PS ("FALSE"),
|
||||
.CLKIN1_PERIOD (5.000))
|
||||
mmcm_adv_inst
|
||||
// Output clocks
|
||||
(
|
||||
.CLKFBOUT (clkfbout_clk_wiz_0),
|
||||
.CLKFBOUTB (clkfboutb_unused),
|
||||
.CLKOUT0 (clk_adc_65_clk_wiz_0),
|
||||
.CLKOUT0B (clkout0b_unused),
|
||||
.CLKOUT1 (clk_adc_65_180_clk_wiz_0),
|
||||
.CLKOUT1B (clkout1b_unused),
|
||||
.CLKOUT2 (clk_dac_125_clk_wiz_0),
|
||||
.CLKOUT2B (clkout2b_unused),
|
||||
.CLKOUT3 (clk_dac_125_180_clk_wiz_0),
|
||||
.CLKOUT3B (clkout3b_unused),
|
||||
.CLKOUT4 (clkout4_unused),
|
||||
.CLKOUT5 (clkout5_unused),
|
||||
.CLKOUT6 (clkout6_unused),
|
||||
// Input clock control
|
||||
.CLKFBIN (clkfbout_buf_clk_wiz_0),
|
||||
.CLKIN1 (clk_200_clk_wiz_0),
|
||||
.CLKIN2 (1'b0),
|
||||
// Tied to always select the primary input clock
|
||||
.CLKINSEL (1'b1),
|
||||
// Ports for dynamic reconfiguration
|
||||
.DADDR (7'h0),
|
||||
.DCLK (1'b0),
|
||||
.DEN (1'b0),
|
||||
.DI (16'h0),
|
||||
.DO (do_unused),
|
||||
.DRDY (drdy_unused),
|
||||
.DWE (1'b0),
|
||||
// Ports for dynamic phase shift
|
||||
.PSCLK (1'b0),
|
||||
.PSEN (1'b0),
|
||||
.PSINCDEC (1'b0),
|
||||
.PSDONE (psdone_unused),
|
||||
// Other control and status signals
|
||||
.LOCKED (locked_int),
|
||||
.CLKINSTOPPED (clkinstopped_unused),
|
||||
.CLKFBSTOPPED (clkfbstopped_unused),
|
||||
.PWRDWN (1'b0),
|
||||
.RST (reset_high));
|
||||
assign reset_high = reset;
|
||||
|
||||
assign locked = locked_int;
|
||||
// Clock Monitor clock assigning
|
||||
//--------------------------------------
|
||||
// Output buffering
|
||||
//-----------------------------------
|
||||
|
||||
BUFG clkf_buf
|
||||
(.O (clkfbout_buf_clk_wiz_0),
|
||||
.I (clkfbout_clk_wiz_0));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BUFG clkout1_buf
|
||||
(.O (clk_adc_65),
|
||||
.I (clk_adc_65_clk_wiz_0));
|
||||
|
||||
|
||||
BUFG clkout2_buf
|
||||
(.O (clk_adc_65_180),
|
||||
.I (clk_adc_65_180_clk_wiz_0));
|
||||
|
||||
BUFG clkout3_buf
|
||||
(.O (clk_dac_125),
|
||||
.I (clk_dac_125_clk_wiz_0));
|
||||
|
||||
BUFG clkout4_buf
|
||||
(.O (clk_dac_125_180),
|
||||
.I (clk_dac_125_180_clk_wiz_0));
|
||||
|
||||
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
# file: clk_wiz_0_ooc.xdc
|
||||
#
|
||||
# (c) Copyright 2008 - 2013 Xilinx, Inc. All rights reserved.
|
||||
#
|
||||
# This file contains confidential and proprietary information
|
||||
# of Xilinx, Inc. and is protected under U.S. and
|
||||
# international copyright and other intellectual property
|
||||
# laws.
|
||||
#
|
||||
# DISCLAIMER
|
||||
# This disclaimer is not a license and does not grant any
|
||||
# rights to the materials distributed herewith. Except as
|
||||
# otherwise provided in a valid license issued to you by
|
||||
# Xilinx, and to the maximum extent permitted by applicable
|
||||
# law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
|
||||
# WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
|
||||
# AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
|
||||
# BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
|
||||
# INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
|
||||
# (2) Xilinx shall not be liable (whether in contract or tort,
|
||||
# including negligence, or under any other theory of
|
||||
# liability) for any loss or damage of any kind or nature
|
||||
# related to, arising under or in connection with these
|
||||
# materials, including for any direct, or any indirect,
|
||||
# special, incidental, or consequential loss or damage
|
||||
# (including loss of data, profits, goodwill, or any type of
|
||||
# loss or damage suffered as a result of any action brought
|
||||
# by a third party) even if such damage or loss was
|
||||
# reasonably foreseeable or Xilinx had been advised of the
|
||||
# possibility of the same.
|
||||
#
|
||||
# CRITICAL APPLICATIONS
|
||||
# Xilinx products are not designed or intended to be fail-
|
||||
# safe, or for use in any application requiring fail-safe
|
||||
# performance, such as life-support or safety devices or
|
||||
# systems, Class III medical devices, nuclear facilities,
|
||||
# applications related to the deployment of airbags, or any
|
||||
# other applications that could lead to death, personal
|
||||
# injury, or severe property or environmental damage
|
||||
# (individually and collectively, "Critical
|
||||
# Applications"). Customer assumes the sole risk and
|
||||
# liability of any use of Xilinx products in Critical
|
||||
# Applications, subject only to applicable laws and
|
||||
# regulations governing limitations on product liability.
|
||||
#
|
||||
# THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
|
||||
# PART OF THIS FILE AT ALL TIMES.
|
||||
#
|
||||
|
||||
#################
|
||||
#DEFAULT CLOCK CONSTRAINTS
|
||||
|
||||
############################################################
|
||||
# Clock Period Constraints #
|
||||
############################################################
|
||||
#create_clock -period 5.000 [get_ports clk_200]
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
// Copyright 1986-2021 Xilinx, Inc. All Rights Reserved.
|
||||
// --------------------------------------------------------------------------------
|
||||
// Tool Version: Vivado v.2021.2 (win64) Build 3367213 Tue Oct 19 02:48:09 MDT 2021
|
||||
// Date : Fri Aug 28 14:05:07 2026
|
||||
// Host : DESKTOP-K2G9PES running 64-bit major release (build 9200)
|
||||
// Command : write_verilog -force -mode funcsim
|
||||
// c:/Users/ASUS/FIZTEX/project/dma_process/dma_process.gen/sources_1/ip/clk_wiz_0/clk_wiz_0_sim_netlist.v
|
||||
// Design : clk_wiz_0
|
||||
// Purpose : This verilog netlist is a functional simulation representation of the design and should not be modified
|
||||
// or synthesized. This netlist cannot be used for SDF annotated simulation.
|
||||
// Device : xc7a100tfgg484-2
|
||||
// --------------------------------------------------------------------------------
|
||||
`timescale 1 ps / 1 ps
|
||||
|
||||
(* NotValidForBitStream *)
|
||||
module clk_wiz_0
|
||||
(clk_adc_65,
|
||||
clk_adc_65_180,
|
||||
clk_dac_125,
|
||||
clk_dac_125_180,
|
||||
reset,
|
||||
locked,
|
||||
clk_200);
|
||||
output clk_adc_65;
|
||||
output clk_adc_65_180;
|
||||
output clk_dac_125;
|
||||
output clk_dac_125_180;
|
||||
input reset;
|
||||
output locked;
|
||||
input clk_200;
|
||||
|
||||
(* IBUF_LOW_PWR *) wire clk_200;
|
||||
wire clk_adc_65;
|
||||
wire clk_adc_65_180;
|
||||
wire clk_dac_125;
|
||||
wire clk_dac_125_180;
|
||||
wire locked;
|
||||
wire reset;
|
||||
|
||||
clk_wiz_0_clk_wiz inst
|
||||
(.clk_200(clk_200),
|
||||
.clk_adc_65(clk_adc_65),
|
||||
.clk_adc_65_180(clk_adc_65_180),
|
||||
.clk_dac_125(clk_dac_125),
|
||||
.clk_dac_125_180(clk_dac_125_180),
|
||||
.locked(locked),
|
||||
.reset(reset));
|
||||
endmodule
|
||||
|
||||
module clk_wiz_0_clk_wiz
|
||||
(clk_adc_65,
|
||||
clk_adc_65_180,
|
||||
clk_dac_125,
|
||||
clk_dac_125_180,
|
||||
reset,
|
||||
locked,
|
||||
clk_200);
|
||||
output clk_adc_65;
|
||||
output clk_adc_65_180;
|
||||
output clk_dac_125;
|
||||
output clk_dac_125_180;
|
||||
input reset;
|
||||
output locked;
|
||||
input clk_200;
|
||||
|
||||
wire clk_200;
|
||||
wire clk_200_clk_wiz_0;
|
||||
wire clk_adc_65;
|
||||
wire clk_adc_65_180;
|
||||
wire clk_adc_65_180_clk_wiz_0;
|
||||
wire clk_adc_65_clk_wiz_0;
|
||||
wire clk_dac_125;
|
||||
wire clk_dac_125_180;
|
||||
wire clk_dac_125_180_clk_wiz_0;
|
||||
wire clk_dac_125_clk_wiz_0;
|
||||
wire clkfbout_buf_clk_wiz_0;
|
||||
wire clkfbout_clk_wiz_0;
|
||||
wire locked;
|
||||
wire reset;
|
||||
wire NLW_mmcm_adv_inst_CLKFBOUTB_UNCONNECTED;
|
||||
wire NLW_mmcm_adv_inst_CLKFBSTOPPED_UNCONNECTED;
|
||||
wire NLW_mmcm_adv_inst_CLKINSTOPPED_UNCONNECTED;
|
||||
wire NLW_mmcm_adv_inst_CLKOUT0B_UNCONNECTED;
|
||||
wire NLW_mmcm_adv_inst_CLKOUT1B_UNCONNECTED;
|
||||
wire NLW_mmcm_adv_inst_CLKOUT2B_UNCONNECTED;
|
||||
wire NLW_mmcm_adv_inst_CLKOUT3B_UNCONNECTED;
|
||||
wire NLW_mmcm_adv_inst_CLKOUT4_UNCONNECTED;
|
||||
wire NLW_mmcm_adv_inst_CLKOUT5_UNCONNECTED;
|
||||
wire NLW_mmcm_adv_inst_CLKOUT6_UNCONNECTED;
|
||||
wire NLW_mmcm_adv_inst_DRDY_UNCONNECTED;
|
||||
wire NLW_mmcm_adv_inst_PSDONE_UNCONNECTED;
|
||||
wire [15:0]NLW_mmcm_adv_inst_DO_UNCONNECTED;
|
||||
|
||||
(* BOX_TYPE = "PRIMITIVE" *)
|
||||
BUFG clkf_buf
|
||||
(.I(clkfbout_clk_wiz_0),
|
||||
.O(clkfbout_buf_clk_wiz_0));
|
||||
(* BOX_TYPE = "PRIMITIVE" *)
|
||||
(* CAPACITANCE = "DONT_CARE" *)
|
||||
(* IBUF_DELAY_VALUE = "0" *)
|
||||
(* IFD_DELAY_VALUE = "AUTO" *)
|
||||
IBUF #(
|
||||
.IOSTANDARD("DEFAULT"))
|
||||
clkin1_ibufg
|
||||
(.I(clk_200),
|
||||
.O(clk_200_clk_wiz_0));
|
||||
(* BOX_TYPE = "PRIMITIVE" *)
|
||||
BUFG clkout1_buf
|
||||
(.I(clk_adc_65_clk_wiz_0),
|
||||
.O(clk_adc_65));
|
||||
(* BOX_TYPE = "PRIMITIVE" *)
|
||||
BUFG clkout2_buf
|
||||
(.I(clk_adc_65_180_clk_wiz_0),
|
||||
.O(clk_adc_65_180));
|
||||
(* BOX_TYPE = "PRIMITIVE" *)
|
||||
BUFG clkout3_buf
|
||||
(.I(clk_dac_125_clk_wiz_0),
|
||||
.O(clk_dac_125));
|
||||
(* BOX_TYPE = "PRIMITIVE" *)
|
||||
BUFG clkout4_buf
|
||||
(.I(clk_dac_125_180_clk_wiz_0),
|
||||
.O(clk_dac_125_180));
|
||||
(* BOX_TYPE = "PRIMITIVE" *)
|
||||
MMCME2_ADV #(
|
||||
.BANDWIDTH("OPTIMIZED"),
|
||||
.CLKFBOUT_MULT_F(34.125000),
|
||||
.CLKFBOUT_PHASE(0.000000),
|
||||
.CLKFBOUT_USE_FINE_PS("FALSE"),
|
||||
.CLKIN1_PERIOD(5.000000),
|
||||
.CLKIN2_PERIOD(0.000000),
|
||||
.CLKOUT0_DIVIDE_F(21.000000),
|
||||
.CLKOUT0_DUTY_CYCLE(0.500000),
|
||||
.CLKOUT0_PHASE(0.000000),
|
||||
.CLKOUT0_USE_FINE_PS("FALSE"),
|
||||
.CLKOUT1_DIVIDE(21),
|
||||
.CLKOUT1_DUTY_CYCLE(0.500000),
|
||||
.CLKOUT1_PHASE(0.000000),
|
||||
.CLKOUT1_USE_FINE_PS("FALSE"),
|
||||
.CLKOUT2_DIVIDE(11),
|
||||
.CLKOUT2_DUTY_CYCLE(0.500000),
|
||||
.CLKOUT2_PHASE(0.000000),
|
||||
.CLKOUT2_USE_FINE_PS("FALSE"),
|
||||
.CLKOUT3_DIVIDE(11),
|
||||
.CLKOUT3_DUTY_CYCLE(0.500000),
|
||||
.CLKOUT3_PHASE(0.000000),
|
||||
.CLKOUT3_USE_FINE_PS("FALSE"),
|
||||
.CLKOUT4_CASCADE("FALSE"),
|
||||
.CLKOUT4_DIVIDE(1),
|
||||
.CLKOUT4_DUTY_CYCLE(0.500000),
|
||||
.CLKOUT4_PHASE(0.000000),
|
||||
.CLKOUT4_USE_FINE_PS("FALSE"),
|
||||
.CLKOUT5_DIVIDE(1),
|
||||
.CLKOUT5_DUTY_CYCLE(0.500000),
|
||||
.CLKOUT5_PHASE(0.000000),
|
||||
.CLKOUT5_USE_FINE_PS("FALSE"),
|
||||
.CLKOUT6_DIVIDE(1),
|
||||
.CLKOUT6_DUTY_CYCLE(0.500000),
|
||||
.CLKOUT6_PHASE(0.000000),
|
||||
.CLKOUT6_USE_FINE_PS("FALSE"),
|
||||
.COMPENSATION("ZHOLD"),
|
||||
.DIVCLK_DIVIDE(5),
|
||||
.IS_CLKINSEL_INVERTED(1'b0),
|
||||
.IS_PSEN_INVERTED(1'b0),
|
||||
.IS_PSINCDEC_INVERTED(1'b0),
|
||||
.IS_PWRDWN_INVERTED(1'b0),
|
||||
.IS_RST_INVERTED(1'b0),
|
||||
.REF_JITTER1(0.010000),
|
||||
.REF_JITTER2(0.010000),
|
||||
.SS_EN("FALSE"),
|
||||
.SS_MODE("CENTER_HIGH"),
|
||||
.SS_MOD_PERIOD(10000),
|
||||
.STARTUP_WAIT("FALSE"))
|
||||
mmcm_adv_inst
|
||||
(.CLKFBIN(clkfbout_buf_clk_wiz_0),
|
||||
.CLKFBOUT(clkfbout_clk_wiz_0),
|
||||
.CLKFBOUTB(NLW_mmcm_adv_inst_CLKFBOUTB_UNCONNECTED),
|
||||
.CLKFBSTOPPED(NLW_mmcm_adv_inst_CLKFBSTOPPED_UNCONNECTED),
|
||||
.CLKIN1(clk_200_clk_wiz_0),
|
||||
.CLKIN2(1'b0),
|
||||
.CLKINSEL(1'b1),
|
||||
.CLKINSTOPPED(NLW_mmcm_adv_inst_CLKINSTOPPED_UNCONNECTED),
|
||||
.CLKOUT0(clk_adc_65_clk_wiz_0),
|
||||
.CLKOUT0B(NLW_mmcm_adv_inst_CLKOUT0B_UNCONNECTED),
|
||||
.CLKOUT1(clk_adc_65_180_clk_wiz_0),
|
||||
.CLKOUT1B(NLW_mmcm_adv_inst_CLKOUT1B_UNCONNECTED),
|
||||
.CLKOUT2(clk_dac_125_clk_wiz_0),
|
||||
.CLKOUT2B(NLW_mmcm_adv_inst_CLKOUT2B_UNCONNECTED),
|
||||
.CLKOUT3(clk_dac_125_180_clk_wiz_0),
|
||||
.CLKOUT3B(NLW_mmcm_adv_inst_CLKOUT3B_UNCONNECTED),
|
||||
.CLKOUT4(NLW_mmcm_adv_inst_CLKOUT4_UNCONNECTED),
|
||||
.CLKOUT5(NLW_mmcm_adv_inst_CLKOUT5_UNCONNECTED),
|
||||
.CLKOUT6(NLW_mmcm_adv_inst_CLKOUT6_UNCONNECTED),
|
||||
.DADDR({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}),
|
||||
.DCLK(1'b0),
|
||||
.DEN(1'b0),
|
||||
.DI({1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0,1'b0}),
|
||||
.DO(NLW_mmcm_adv_inst_DO_UNCONNECTED[15:0]),
|
||||
.DRDY(NLW_mmcm_adv_inst_DRDY_UNCONNECTED),
|
||||
.DWE(1'b0),
|
||||
.LOCKED(locked),
|
||||
.PSCLK(1'b0),
|
||||
.PSDONE(NLW_mmcm_adv_inst_PSDONE_UNCONNECTED),
|
||||
.PSEN(1'b0),
|
||||
.PSINCDEC(1'b0),
|
||||
.PWRDWN(1'b0),
|
||||
.RST(reset));
|
||||
endmodule
|
||||
`ifndef GLBL
|
||||
`define GLBL
|
||||
`timescale 1 ps / 1 ps
|
||||
|
||||
module glbl ();
|
||||
|
||||
parameter ROC_WIDTH = 100000;
|
||||
parameter TOC_WIDTH = 0;
|
||||
parameter GRES_WIDTH = 10000;
|
||||
parameter GRES_START = 10000;
|
||||
|
||||
//-------- STARTUP Globals --------------
|
||||
wire GSR;
|
||||
wire GTS;
|
||||
wire GWE;
|
||||
wire PRLD;
|
||||
wire GRESTORE;
|
||||
tri1 p_up_tmp;
|
||||
tri (weak1, strong0) PLL_LOCKG = p_up_tmp;
|
||||
|
||||
wire PROGB_GLBL;
|
||||
wire CCLKO_GLBL;
|
||||
wire FCSBO_GLBL;
|
||||
wire [3:0] DO_GLBL;
|
||||
wire [3:0] DI_GLBL;
|
||||
|
||||
reg GSR_int;
|
||||
reg GTS_int;
|
||||
reg PRLD_int;
|
||||
reg GRESTORE_int;
|
||||
|
||||
//-------- JTAG Globals --------------
|
||||
wire JTAG_TDO_GLBL;
|
||||
wire JTAG_TCK_GLBL;
|
||||
wire JTAG_TDI_GLBL;
|
||||
wire JTAG_TMS_GLBL;
|
||||
wire JTAG_TRST_GLBL;
|
||||
|
||||
reg JTAG_CAPTURE_GLBL;
|
||||
reg JTAG_RESET_GLBL;
|
||||
reg JTAG_SHIFT_GLBL;
|
||||
reg JTAG_UPDATE_GLBL;
|
||||
reg JTAG_RUNTEST_GLBL;
|
||||
|
||||
reg JTAG_SEL1_GLBL = 0;
|
||||
reg JTAG_SEL2_GLBL = 0 ;
|
||||
reg JTAG_SEL3_GLBL = 0;
|
||||
reg JTAG_SEL4_GLBL = 0;
|
||||
|
||||
reg JTAG_USER_TDO1_GLBL = 1'bz;
|
||||
reg JTAG_USER_TDO2_GLBL = 1'bz;
|
||||
reg JTAG_USER_TDO3_GLBL = 1'bz;
|
||||
reg JTAG_USER_TDO4_GLBL = 1'bz;
|
||||
|
||||
assign (strong1, weak0) GSR = GSR_int;
|
||||
assign (strong1, weak0) GTS = GTS_int;
|
||||
assign (weak1, weak0) PRLD = PRLD_int;
|
||||
assign (strong1, weak0) GRESTORE = GRESTORE_int;
|
||||
|
||||
initial begin
|
||||
GSR_int = 1'b1;
|
||||
PRLD_int = 1'b1;
|
||||
#(ROC_WIDTH)
|
||||
GSR_int = 1'b0;
|
||||
PRLD_int = 1'b0;
|
||||
end
|
||||
|
||||
initial begin
|
||||
GTS_int = 1'b1;
|
||||
#(TOC_WIDTH)
|
||||
GTS_int = 1'b0;
|
||||
end
|
||||
|
||||
initial begin
|
||||
GRESTORE_int = 1'b0;
|
||||
#(GRES_START);
|
||||
GRESTORE_int = 1'b1;
|
||||
#(GRES_WIDTH);
|
||||
GRESTORE_int = 1'b0;
|
||||
end
|
||||
|
||||
endmodule
|
||||
`endif
|
||||
@@ -0,0 +1,215 @@
|
||||
-- Copyright 1986-2021 Xilinx, Inc. All Rights Reserved.
|
||||
-- --------------------------------------------------------------------------------
|
||||
-- Tool Version: Vivado v.2021.2 (win64) Build 3367213 Tue Oct 19 02:48:09 MDT 2021
|
||||
-- Date : Fri Aug 28 14:05:07 2026
|
||||
-- Host : DESKTOP-K2G9PES running 64-bit major release (build 9200)
|
||||
-- Command : write_vhdl -force -mode funcsim
|
||||
-- c:/Users/ASUS/FIZTEX/project/dma_process/dma_process.gen/sources_1/ip/clk_wiz_0/clk_wiz_0_sim_netlist.vhdl
|
||||
-- Design : clk_wiz_0
|
||||
-- Purpose : This VHDL netlist is a functional simulation representation of the design and should not be modified or
|
||||
-- synthesized. This netlist cannot be used for SDF annotated simulation.
|
||||
-- Device : xc7a100tfgg484-2
|
||||
-- --------------------------------------------------------------------------------
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
library UNISIM;
|
||||
use UNISIM.VCOMPONENTS.ALL;
|
||||
entity clk_wiz_0_clk_wiz is
|
||||
port (
|
||||
clk_adc_65 : out STD_LOGIC;
|
||||
clk_adc_65_180 : out STD_LOGIC;
|
||||
clk_dac_125 : out STD_LOGIC;
|
||||
clk_dac_125_180 : out STD_LOGIC;
|
||||
reset : in STD_LOGIC;
|
||||
locked : out STD_LOGIC;
|
||||
clk_200 : in STD_LOGIC
|
||||
);
|
||||
end clk_wiz_0_clk_wiz;
|
||||
|
||||
architecture STRUCTURE of clk_wiz_0_clk_wiz is
|
||||
signal clk_200_clk_wiz_0 : STD_LOGIC;
|
||||
signal clk_adc_65_180_clk_wiz_0 : STD_LOGIC;
|
||||
signal clk_adc_65_clk_wiz_0 : STD_LOGIC;
|
||||
signal clk_dac_125_180_clk_wiz_0 : STD_LOGIC;
|
||||
signal clk_dac_125_clk_wiz_0 : STD_LOGIC;
|
||||
signal clkfbout_buf_clk_wiz_0 : STD_LOGIC;
|
||||
signal clkfbout_clk_wiz_0 : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_CLKFBOUTB_UNCONNECTED : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_CLKFBSTOPPED_UNCONNECTED : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_CLKINSTOPPED_UNCONNECTED : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_CLKOUT0B_UNCONNECTED : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_CLKOUT1B_UNCONNECTED : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_CLKOUT2B_UNCONNECTED : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_CLKOUT3B_UNCONNECTED : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_CLKOUT4_UNCONNECTED : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_CLKOUT5_UNCONNECTED : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_CLKOUT6_UNCONNECTED : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_DRDY_UNCONNECTED : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_PSDONE_UNCONNECTED : STD_LOGIC;
|
||||
signal NLW_mmcm_adv_inst_DO_UNCONNECTED : STD_LOGIC_VECTOR ( 15 downto 0 );
|
||||
attribute BOX_TYPE : string;
|
||||
attribute BOX_TYPE of clkf_buf : label is "PRIMITIVE";
|
||||
attribute BOX_TYPE of clkin1_ibufg : label is "PRIMITIVE";
|
||||
attribute CAPACITANCE : string;
|
||||
attribute CAPACITANCE of clkin1_ibufg : label is "DONT_CARE";
|
||||
attribute IBUF_DELAY_VALUE : string;
|
||||
attribute IBUF_DELAY_VALUE of clkin1_ibufg : label is "0";
|
||||
attribute IFD_DELAY_VALUE : string;
|
||||
attribute IFD_DELAY_VALUE of clkin1_ibufg : label is "AUTO";
|
||||
attribute BOX_TYPE of clkout1_buf : label is "PRIMITIVE";
|
||||
attribute BOX_TYPE of clkout2_buf : label is "PRIMITIVE";
|
||||
attribute BOX_TYPE of clkout3_buf : label is "PRIMITIVE";
|
||||
attribute BOX_TYPE of clkout4_buf : label is "PRIMITIVE";
|
||||
attribute BOX_TYPE of mmcm_adv_inst : label is "PRIMITIVE";
|
||||
begin
|
||||
clkf_buf: unisim.vcomponents.BUFG
|
||||
port map (
|
||||
I => clkfbout_clk_wiz_0,
|
||||
O => clkfbout_buf_clk_wiz_0
|
||||
);
|
||||
clkin1_ibufg: unisim.vcomponents.IBUF
|
||||
generic map(
|
||||
IOSTANDARD => "DEFAULT"
|
||||
)
|
||||
port map (
|
||||
I => clk_200,
|
||||
O => clk_200_clk_wiz_0
|
||||
);
|
||||
clkout1_buf: unisim.vcomponents.BUFG
|
||||
port map (
|
||||
I => clk_adc_65_clk_wiz_0,
|
||||
O => clk_adc_65
|
||||
);
|
||||
clkout2_buf: unisim.vcomponents.BUFG
|
||||
port map (
|
||||
I => clk_adc_65_180_clk_wiz_0,
|
||||
O => clk_adc_65_180
|
||||
);
|
||||
clkout3_buf: unisim.vcomponents.BUFG
|
||||
port map (
|
||||
I => clk_dac_125_clk_wiz_0,
|
||||
O => clk_dac_125
|
||||
);
|
||||
clkout4_buf: unisim.vcomponents.BUFG
|
||||
port map (
|
||||
I => clk_dac_125_180_clk_wiz_0,
|
||||
O => clk_dac_125_180
|
||||
);
|
||||
mmcm_adv_inst: unisim.vcomponents.MMCME2_ADV
|
||||
generic map(
|
||||
BANDWIDTH => "OPTIMIZED",
|
||||
CLKFBOUT_MULT_F => 34.125000,
|
||||
CLKFBOUT_PHASE => 0.000000,
|
||||
CLKFBOUT_USE_FINE_PS => false,
|
||||
CLKIN1_PERIOD => 5.000000,
|
||||
CLKIN2_PERIOD => 0.000000,
|
||||
CLKOUT0_DIVIDE_F => 21.000000,
|
||||
CLKOUT0_DUTY_CYCLE => 0.500000,
|
||||
CLKOUT0_PHASE => 0.000000,
|
||||
CLKOUT0_USE_FINE_PS => false,
|
||||
CLKOUT1_DIVIDE => 21,
|
||||
CLKOUT1_DUTY_CYCLE => 0.500000,
|
||||
CLKOUT1_PHASE => 0.000000,
|
||||
CLKOUT1_USE_FINE_PS => false,
|
||||
CLKOUT2_DIVIDE => 11,
|
||||
CLKOUT2_DUTY_CYCLE => 0.500000,
|
||||
CLKOUT2_PHASE => 0.000000,
|
||||
CLKOUT2_USE_FINE_PS => false,
|
||||
CLKOUT3_DIVIDE => 11,
|
||||
CLKOUT3_DUTY_CYCLE => 0.500000,
|
||||
CLKOUT3_PHASE => 0.000000,
|
||||
CLKOUT3_USE_FINE_PS => false,
|
||||
CLKOUT4_CASCADE => false,
|
||||
CLKOUT4_DIVIDE => 1,
|
||||
CLKOUT4_DUTY_CYCLE => 0.500000,
|
||||
CLKOUT4_PHASE => 0.000000,
|
||||
CLKOUT4_USE_FINE_PS => false,
|
||||
CLKOUT5_DIVIDE => 1,
|
||||
CLKOUT5_DUTY_CYCLE => 0.500000,
|
||||
CLKOUT5_PHASE => 0.000000,
|
||||
CLKOUT5_USE_FINE_PS => false,
|
||||
CLKOUT6_DIVIDE => 1,
|
||||
CLKOUT6_DUTY_CYCLE => 0.500000,
|
||||
CLKOUT6_PHASE => 0.000000,
|
||||
CLKOUT6_USE_FINE_PS => false,
|
||||
COMPENSATION => "ZHOLD",
|
||||
DIVCLK_DIVIDE => 5,
|
||||
IS_CLKINSEL_INVERTED => '0',
|
||||
IS_PSEN_INVERTED => '0',
|
||||
IS_PSINCDEC_INVERTED => '0',
|
||||
IS_PWRDWN_INVERTED => '0',
|
||||
IS_RST_INVERTED => '0',
|
||||
REF_JITTER1 => 0.010000,
|
||||
REF_JITTER2 => 0.010000,
|
||||
SS_EN => "FALSE",
|
||||
SS_MODE => "CENTER_HIGH",
|
||||
SS_MOD_PERIOD => 10000,
|
||||
STARTUP_WAIT => false
|
||||
)
|
||||
port map (
|
||||
CLKFBIN => clkfbout_buf_clk_wiz_0,
|
||||
CLKFBOUT => clkfbout_clk_wiz_0,
|
||||
CLKFBOUTB => NLW_mmcm_adv_inst_CLKFBOUTB_UNCONNECTED,
|
||||
CLKFBSTOPPED => NLW_mmcm_adv_inst_CLKFBSTOPPED_UNCONNECTED,
|
||||
CLKIN1 => clk_200_clk_wiz_0,
|
||||
CLKIN2 => '0',
|
||||
CLKINSEL => '1',
|
||||
CLKINSTOPPED => NLW_mmcm_adv_inst_CLKINSTOPPED_UNCONNECTED,
|
||||
CLKOUT0 => clk_adc_65_clk_wiz_0,
|
||||
CLKOUT0B => NLW_mmcm_adv_inst_CLKOUT0B_UNCONNECTED,
|
||||
CLKOUT1 => clk_adc_65_180_clk_wiz_0,
|
||||
CLKOUT1B => NLW_mmcm_adv_inst_CLKOUT1B_UNCONNECTED,
|
||||
CLKOUT2 => clk_dac_125_clk_wiz_0,
|
||||
CLKOUT2B => NLW_mmcm_adv_inst_CLKOUT2B_UNCONNECTED,
|
||||
CLKOUT3 => clk_dac_125_180_clk_wiz_0,
|
||||
CLKOUT3B => NLW_mmcm_adv_inst_CLKOUT3B_UNCONNECTED,
|
||||
CLKOUT4 => NLW_mmcm_adv_inst_CLKOUT4_UNCONNECTED,
|
||||
CLKOUT5 => NLW_mmcm_adv_inst_CLKOUT5_UNCONNECTED,
|
||||
CLKOUT6 => NLW_mmcm_adv_inst_CLKOUT6_UNCONNECTED,
|
||||
DADDR(6 downto 0) => B"0000000",
|
||||
DCLK => '0',
|
||||
DEN => '0',
|
||||
DI(15 downto 0) => B"0000000000000000",
|
||||
DO(15 downto 0) => NLW_mmcm_adv_inst_DO_UNCONNECTED(15 downto 0),
|
||||
DRDY => NLW_mmcm_adv_inst_DRDY_UNCONNECTED,
|
||||
DWE => '0',
|
||||
LOCKED => locked,
|
||||
PSCLK => '0',
|
||||
PSDONE => NLW_mmcm_adv_inst_PSDONE_UNCONNECTED,
|
||||
PSEN => '0',
|
||||
PSINCDEC => '0',
|
||||
PWRDWN => '0',
|
||||
RST => reset
|
||||
);
|
||||
end STRUCTURE;
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
library UNISIM;
|
||||
use UNISIM.VCOMPONENTS.ALL;
|
||||
entity clk_wiz_0 is
|
||||
port (
|
||||
clk_adc_65 : out STD_LOGIC;
|
||||
clk_adc_65_180 : out STD_LOGIC;
|
||||
clk_dac_125 : out STD_LOGIC;
|
||||
clk_dac_125_180 : out STD_LOGIC;
|
||||
reset : in STD_LOGIC;
|
||||
locked : out STD_LOGIC;
|
||||
clk_200 : in STD_LOGIC
|
||||
);
|
||||
attribute NotValidForBitStream : boolean;
|
||||
attribute NotValidForBitStream of clk_wiz_0 : entity is true;
|
||||
end clk_wiz_0;
|
||||
|
||||
architecture STRUCTURE of clk_wiz_0 is
|
||||
begin
|
||||
inst: entity work.clk_wiz_0_clk_wiz
|
||||
port map (
|
||||
clk_200 => clk_200,
|
||||
clk_adc_65 => clk_adc_65,
|
||||
clk_adc_65_180 => clk_adc_65_180,
|
||||
clk_dac_125 => clk_dac_125,
|
||||
clk_dac_125_180 => clk_dac_125_180,
|
||||
locked => locked,
|
||||
reset => reset
|
||||
);
|
||||
end STRUCTURE;
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 1986-2021 Xilinx, Inc. All Rights Reserved.
|
||||
// --------------------------------------------------------------------------------
|
||||
// Tool Version: Vivado v.2021.2 (win64) Build 3367213 Tue Oct 19 02:48:09 MDT 2021
|
||||
// Date : Fri Aug 28 14:05:07 2026
|
||||
// Host : DESKTOP-K2G9PES running 64-bit major release (build 9200)
|
||||
// Command : write_verilog -force -mode synth_stub
|
||||
// c:/Users/ASUS/FIZTEX/project/dma_process/dma_process.gen/sources_1/ip/clk_wiz_0/clk_wiz_0_stub.v
|
||||
// Design : clk_wiz_0
|
||||
// Purpose : Stub declaration of top-level module interface
|
||||
// Device : xc7a100tfgg484-2
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// This empty module with port declaration file causes synthesis tools to infer a black box for IP.
|
||||
// The synthesis directives are for Synopsys Synplify support to prevent IO buffer insertion.
|
||||
// Please paste the declaration into a Verilog source file or add the file as an additional source.
|
||||
module clk_wiz_0(clk_adc_65, clk_adc_65_180, clk_dac_125,
|
||||
clk_dac_125_180, reset, locked, clk_200)
|
||||
/* synthesis syn_black_box black_box_pad_pin="clk_adc_65,clk_adc_65_180,clk_dac_125,clk_dac_125_180,reset,locked,clk_200" */;
|
||||
output clk_adc_65;
|
||||
output clk_adc_65_180;
|
||||
output clk_dac_125;
|
||||
output clk_dac_125_180;
|
||||
input reset;
|
||||
output locked;
|
||||
input clk_200;
|
||||
endmodule
|
||||
@@ -0,0 +1,34 @@
|
||||
-- Copyright 1986-2021 Xilinx, Inc. All Rights Reserved.
|
||||
-- --------------------------------------------------------------------------------
|
||||
-- Tool Version: Vivado v.2021.2 (win64) Build 3367213 Tue Oct 19 02:48:09 MDT 2021
|
||||
-- Date : Fri Aug 28 14:05:07 2026
|
||||
-- Host : DESKTOP-K2G9PES running 64-bit major release (build 9200)
|
||||
-- Command : write_vhdl -force -mode synth_stub
|
||||
-- c:/Users/ASUS/FIZTEX/project/dma_process/dma_process.gen/sources_1/ip/clk_wiz_0/clk_wiz_0_stub.vhdl
|
||||
-- Design : clk_wiz_0
|
||||
-- Purpose : Stub declaration of top-level module interface
|
||||
-- Device : xc7a100tfgg484-2
|
||||
-- --------------------------------------------------------------------------------
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
|
||||
entity clk_wiz_0 is
|
||||
Port (
|
||||
clk_adc_65 : out STD_LOGIC;
|
||||
clk_adc_65_180 : out STD_LOGIC;
|
||||
clk_dac_125 : out STD_LOGIC;
|
||||
clk_dac_125_180 : out STD_LOGIC;
|
||||
reset : in STD_LOGIC;
|
||||
locked : out STD_LOGIC;
|
||||
clk_200 : in STD_LOGIC
|
||||
);
|
||||
|
||||
end clk_wiz_0;
|
||||
|
||||
architecture stub of clk_wiz_0 is
|
||||
attribute syn_black_box : boolean;
|
||||
attribute black_box_pad_pin : string;
|
||||
attribute syn_black_box of stub : architecture is true;
|
||||
attribute black_box_pad_pin of stub : architecture is "clk_adc_65,clk_adc_65_180,clk_dac_125,clk_dac_125_180,reset,locked,clk_200";
|
||||
begin
|
||||
end;
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
2021.2:
|
||||
* Version 6.0 (Rev. 9)
|
||||
* Bug Fix: CR Fixes
|
||||
* Other: CR Fixes
|
||||
|
||||
2021.1.1:
|
||||
* Version 6.0 (Rev. 8)
|
||||
* No changes
|
||||
|
||||
2021.1:
|
||||
* Version 6.0 (Rev. 8)
|
||||
* Bug Fix: Internal GUI fixes
|
||||
* Other: CR Fixes
|
||||
|
||||
2020.3:
|
||||
* Version 6.0 (Rev. 7)
|
||||
* Bug Fix: Internal GUI fixes
|
||||
* Other: CR Fixes
|
||||
|
||||
2020.2.2:
|
||||
* Version 6.0 (Rev. 6)
|
||||
* No changes
|
||||
|
||||
2020.2.1:
|
||||
* Version 6.0 (Rev. 6)
|
||||
* No changes
|
||||
|
||||
2020.2:
|
||||
* Version 6.0 (Rev. 6)
|
||||
* Bug Fix: Internal GUI fixes
|
||||
* Other: CR Fixes
|
||||
|
||||
2020.1.1:
|
||||
* Version 6.0 (Rev. 5)
|
||||
* No changes
|
||||
|
||||
2020.1:
|
||||
* Version 6.0 (Rev. 5)
|
||||
* Bug Fix: Internal GUI fixes
|
||||
* Other: CR Fixes
|
||||
|
||||
2019.2.2:
|
||||
* Version 6.0 (Rev. 4)
|
||||
* No changes
|
||||
|
||||
2019.2.1:
|
||||
* Version 6.0 (Rev. 4)
|
||||
* No changes
|
||||
|
||||
2019.2:
|
||||
* Version 6.0 (Rev. 4)
|
||||
* Bug Fix: Internal GUI fixes
|
||||
* Other: CR Fixes
|
||||
|
||||
2019.1.3:
|
||||
* Version 6.0 (Rev. 3)
|
||||
* No changes
|
||||
|
||||
2019.1.2:
|
||||
* Version 6.0 (Rev. 3)
|
||||
* No changes
|
||||
|
||||
2019.1.1:
|
||||
* Version 6.0 (Rev. 3)
|
||||
* No changes
|
||||
|
||||
2019.1:
|
||||
* Version 6.0 (Rev. 3)
|
||||
* Bug Fix: Internal GUI fixes
|
||||
* Other: New family support added
|
||||
|
||||
2018.3.1:
|
||||
* Version 6.0 (Rev. 2)
|
||||
* No changes
|
||||
|
||||
2018.3:
|
||||
* Version 6.0 (Rev. 2)
|
||||
* Bug Fix: Made input source independent for primary and secondary clock
|
||||
* Other: New family support added
|
||||
|
||||
2018.2:
|
||||
* Version 6.0 (Rev. 1)
|
||||
* Bug Fix: Removed vco freq check when Primitive is None
|
||||
* Other: New family support added
|
||||
|
||||
2018.1:
|
||||
* Version 6.0
|
||||
* Bug Fix: Bug fixes in Dynamic Reconfiguration feature and Write DRP feature
|
||||
* Bug Fix: Bug fixes for connection issue for s_axi_aresetn pin in IPI
|
||||
* Feature Enhancement: The default value of USE_PHASE_ALIGMENT is updated to false for UltraScale and UltraScale+ devices. Phase Alignment feature uses extra clock routes in UltraScale and UltraScale+ designs when MMCMs are used. These routing resources are wasted when user do not understand when phase alignment is really needed. Now, implementation tools can use these extra clock routing resources for high fanout signals.
|
||||
* Feature Enhancement: A column "Max. freq of buffer" is added in the Output Clock table which shows the maximum frequency that the selected output buffer can support
|
||||
* Other: DRCs added for invalid input values in Override mode
|
||||
|
||||
2017.4:
|
||||
* Version 5.4 (Rev. 3)
|
||||
* Bug Fix: Internal GUI issues are fixed for COMPENSATION mode as INTERNAL
|
||||
* Bug Fix: Fixed issue in dynamic reconfiguration of fractional values of M in MMCME3, MMCME4
|
||||
|
||||
2017.3:
|
||||
* Version 5.4 (Rev. 2)
|
||||
* General: Internal GUI changes. No effect on the customer design. Added support for aspartan7 devices
|
||||
|
||||
2017.2:
|
||||
* Version 5.4 (Rev. 1)
|
||||
* General: Internal GUI changes. No effect on the customer design.
|
||||
|
||||
2017.1:
|
||||
* Version 5.4
|
||||
* Port Change: Minor version upgrade. CLR pins are added to the pin list when selected buffer is BUFGCEDIV for ultrascale and ultrascale plus devices.
|
||||
* Other: Added support for new zynq ultrascale plus devices.
|
||||
|
||||
2016.4:
|
||||
* Version 5.3 (Rev. 3)
|
||||
* Bug Fix: Internal GUI issues are fixed.
|
||||
|
||||
2016.3:
|
||||
* Version 5.3 (Rev. 2)
|
||||
* Feature Enhancement: Added new option "Auto" under PRIMITIVE selection for ultrascale and above devices. This option allows the Wizard to instantiate appropriate primitive for the user inputs.
|
||||
* Feature Enhancement: Added Matched Routing Option for better timing solutions.
|
||||
* Feature Enhancement: Options 'Buffer' and 'Buffer_with_CE' are added to the buffer selection list.
|
||||
* Other: Source HDL files are concatenated into a single file to speed up synthesis and simulation. No changes required by the user
|
||||
* Other: Added support for Spartan7 devices.
|
||||
|
||||
2016.2:
|
||||
* Version 5.3 (Rev. 1)
|
||||
* Internal register bit update, no effect on customer designs.
|
||||
|
||||
2016.1:
|
||||
* Version 5.3
|
||||
* Added Clock Monitor Feature as part of clocking wizard
|
||||
* DRP registers can be directly written through AXI without resource utilization
|
||||
* Changes to HDL library management to support Vivado IP simulation library
|
||||
|
||||
2015.4.2:
|
||||
* Version 5.2 (Rev. 1)
|
||||
* No changes
|
||||
|
||||
2015.4.1:
|
||||
* Version 5.2 (Rev. 1)
|
||||
* No changes
|
||||
|
||||
2015.4:
|
||||
* Version 5.2 (Rev. 1)
|
||||
* Internal device family change, no functional changes
|
||||
|
||||
2015.3:
|
||||
* Version 5.2
|
||||
* IP revision number added to HDL module, library, and include file names, to support designs with both locked and upgraded IP instances
|
||||
* Port Renaming tab is hidden in the GUI in IP Integrator as this feature is not supported
|
||||
* Phase alignment feature is removed for ultrascale PLL as primitve has limited capabilities of supporting this feature
|
||||
* When clocking wizard is targetted on a board part, the frequency values that gets propagated to primary and secondary clocks are displayed in floating number format
|
||||
* Example design and simulation files are delivered in verilog only
|
||||
|
||||
2015.2.1:
|
||||
* Version 5.1 (Rev. 6)
|
||||
* No changes
|
||||
|
||||
2015.2:
|
||||
* Version 5.1 (Rev. 6)
|
||||
* No changes
|
||||
|
||||
2015.1:
|
||||
* Version 5.1 (Rev. 6)
|
||||
* Updated mmcm_pll_filter_lookup and mmcm_pll_lock_lookup functions in the header file for 7-Series and UltraScale devices
|
||||
* Supported devices and production status are now determined automatically, to simplify support for future devices
|
||||
|
||||
2014.4.1:
|
||||
* Version 5.1 (Rev. 5)
|
||||
* No changes
|
||||
|
||||
2014.4:
|
||||
* Version 5.1 (Rev. 5)
|
||||
* Internal device family change, no functional changes
|
||||
* updates related to the source selection based on board interface for zed board
|
||||
|
||||
2014.3:
|
||||
* Version 5.1 (Rev. 4)
|
||||
* Option added to enable dynamic phase and duty cycle for resource optimization in AXI4-Lite interface
|
||||
|
||||
2014.2:
|
||||
* Version 5.1 (Rev. 3)
|
||||
* Updated for AXI4-Lite interface locked status register address and bit mapping to align with the pg065
|
||||
|
||||
2014.1:
|
||||
* Version 5.1 (Rev. 2)
|
||||
* Updated to use inverted output CLKOUTB 0-3 of Clocking Primitive based on requested 180 phase w.r.t. previous clock
|
||||
* Internal device family name change, no functional changes
|
||||
|
||||
2013.4:
|
||||
* Version 5.1 (Rev. 1)
|
||||
* Added support for Ultrascale devices
|
||||
* Updated Board Flow GUI to select the clock interfaces
|
||||
* Fixed issue with Stub file parameter error for BUFR output driver
|
||||
|
||||
2013.3:
|
||||
* Version 5.1
|
||||
* Added AXI4-Lite interface to dynamically reconfigure MMCM/PLL
|
||||
* Improved safe clock logic to remove glitches on clock outputs for odd multiples of input clock frequencies
|
||||
* Fixed precision issues between displayed and actual frequencies
|
||||
* Added tool tips to GUI
|
||||
* Added Jitter and Phase error values to IP properties
|
||||
* Added support for Cadence IES and Synopsys VCS simulators
|
||||
* Reduced warnings in synthesis and simulation
|
||||
* Enhanced support for IP Integrator
|
||||
|
||||
2013.2:
|
||||
* Version 5.0 (Rev. 1)
|
||||
* Fixed issue with clock constraints for multiple instances of clocking wizard
|
||||
* Updated Life-Cycle status of devices
|
||||
|
||||
2013.1:
|
||||
* Version 5.0
|
||||
* Lower case ports for Verilog
|
||||
* Added Safe Clock Startup and Clock Sequencing
|
||||
|
||||
(c) Copyright 2008 - 2021 Xilinx, Inc. All rights reserved.
|
||||
|
||||
This file contains confidential and proprietary information
|
||||
of Xilinx, Inc. and is protected under U.S. and
|
||||
international copyright and other intellectual property
|
||||
laws.
|
||||
|
||||
DISCLAIMER
|
||||
This disclaimer is not a license and does not grant any
|
||||
rights to the materials distributed herewith. Except as
|
||||
otherwise provided in a valid license issued to you by
|
||||
Xilinx, and to the maximum extent permitted by applicable
|
||||
law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
|
||||
WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
|
||||
AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
|
||||
BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
|
||||
INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
|
||||
(2) Xilinx shall not be liable (whether in contract or tort,
|
||||
including negligence, or under any other theory of
|
||||
liability) for any loss or damage of any kind or nature
|
||||
related to, arising under or in connection with these
|
||||
materials, including for any direct, or any indirect,
|
||||
special, incidental, or consequential loss or damage
|
||||
(including loss of data, profits, goodwill, or any type of
|
||||
loss or damage suffered as a result of any action brought
|
||||
by a third party) even if such damage or loss was
|
||||
reasonably foreseeable or Xilinx had been advised of the
|
||||
possibility of the same.
|
||||
|
||||
CRITICAL APPLICATIONS
|
||||
Xilinx products are not designed or intended to be fail-
|
||||
safe, or for use in any application requiring fail-safe
|
||||
performance, such as life-support or safety devices or
|
||||
systems, Class III medical devices, nuclear facilities,
|
||||
applications related to the deployment of airbags, or any
|
||||
other applications that could lead to death, personal
|
||||
injury, or severe property or environmental damage
|
||||
(individually and collectively, "Critical
|
||||
Applications"). Customer assumes the sole risk and
|
||||
liability of any use of Xilinx products in Critical
|
||||
Applications, subject only to applicable laws and
|
||||
regulations governing limitations on product liability.
|
||||
|
||||
THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
|
||||
PART OF THIS FILE AT ALL TIMES.
|
||||
+671
@@ -0,0 +1,671 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Company: Xilinx
|
||||
// Engineer: Jim Tatsukawa, Karl Kurbjun and Carl Ribbing
|
||||
// Date: 7/30/2014
|
||||
// Design Name: MMCME2 DRP
|
||||
// Module Name: mmcme2_drp_func.h
|
||||
// Version: 1.04
|
||||
// Target Devices: 7 Series || MMCM
|
||||
// Tool versions: 2014.3
|
||||
// Description: This header provides the functions necessary to
|
||||
// calculate the DRP register values for the V6 MMCM.
|
||||
//
|
||||
// Revision Notes: 3/12 - Updating lookup_low/lookup_high (CR)
|
||||
// 4/13 - Fractional divide function in mmcm_frac_count_calc function. CRS610807
|
||||
//
|
||||
// Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
|
||||
// INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
|
||||
// PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
|
||||
// PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
// ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
||||
// APPLICATION OR STANDARD, XILINX IS MAKING NO
|
||||
// REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
|
||||
// FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
|
||||
// RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
|
||||
// REQUIRE FOR YOUR IMPLEMENTATION. XILINX
|
||||
// EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
|
||||
// RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
|
||||
// INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
||||
// REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
|
||||
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE.
|
||||
//
|
||||
// (c) Copyright 2009-2010 Xilinx, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// These are user functions that should not be modified. Changes to the defines
|
||||
// or code within the functions may alter the accuracy of the calculations.
|
||||
|
||||
// Define debug to provide extra messages durring elaboration
|
||||
//`define DEBUG 1
|
||||
|
||||
// FRAC_PRECISION describes the width of the fractional portion of the fixed
|
||||
// point numbers. These should not be modified, they are for development
|
||||
// only
|
||||
`define FRAC_PRECISION 10
|
||||
// FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
|
||||
// Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
|
||||
// greater than 32
|
||||
`define FIXED_WIDTH 32
|
||||
|
||||
// This function takes a fixed point number and rounds it to the nearest
|
||||
// fractional precision bit.
|
||||
function [`FIXED_WIDTH:1] round_frac
|
||||
(
|
||||
// Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
|
||||
input [`FIXED_WIDTH:1] decimal,
|
||||
|
||||
// This describes the precision of the fraction, for example a value
|
||||
// of 1 would modify the fractional so that instead of being a .16
|
||||
// fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
|
||||
input [`FIXED_WIDTH:1] precision
|
||||
);
|
||||
|
||||
begin
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("round_frac - decimal: %h, precision: %h", decimal, precision);
|
||||
`endif
|
||||
// If the fractional precision bit is high then round up
|
||||
if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
|
||||
round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
|
||||
end else begin
|
||||
round_frac = decimal;
|
||||
end
|
||||
`ifdef DEBUG
|
||||
$display("round_frac: %h", round_frac);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function calculates high_time, low_time, w_edge, and no_count
|
||||
// of a non-fractional counter based on the divide and duty cycle
|
||||
//
|
||||
// NOTE: high_time and low_time are returned as integers between 0 and 63
|
||||
// inclusive. 64 should equal 6'b000000 (in other words it is okay to
|
||||
// ignore the overflow)
|
||||
function [13:0] mmcm_pll_divider
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
|
||||
);
|
||||
|
||||
reg [`FIXED_WIDTH:1] duty_cycle_fix;
|
||||
|
||||
// High/Low time is initially calculated with a wider integer to prevent a
|
||||
// calculation error when it overflows to 64.
|
||||
reg [6:0] high_time;
|
||||
reg [6:0] low_time;
|
||||
reg w_edge;
|
||||
reg no_count;
|
||||
|
||||
reg [`FIXED_WIDTH:1] temp;
|
||||
|
||||
begin
|
||||
// Duty Cycle must be between 0 and 1,000
|
||||
if(duty_cycle <=0 || duty_cycle >= 100000) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: duty_cycle: %d is invalid", duty_cycle);
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
// Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
|
||||
duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("duty_cycle_fix: %h", duty_cycle_fix);
|
||||
`endif
|
||||
|
||||
// If the divide is 1 nothing needs to be set except the no_count bit.
|
||||
// Other values are dummies
|
||||
if(divide == 7'h01) begin
|
||||
high_time = 7'h01;
|
||||
w_edge = 1'b0;
|
||||
low_time = 7'h01;
|
||||
no_count = 1'b1;
|
||||
end else begin
|
||||
temp = round_frac(duty_cycle_fix*divide, 1);
|
||||
|
||||
// comes from above round_frac
|
||||
high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
|
||||
// If the duty cycle * divide rounded is .5 or greater then this bit
|
||||
// is set.
|
||||
w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
|
||||
|
||||
// If the high time comes out to 0, it needs to be set to at least 1
|
||||
// and w_edge set to 0
|
||||
if(high_time == 7'h00) begin
|
||||
high_time = 7'h01;
|
||||
w_edge = 1'b0;
|
||||
end
|
||||
|
||||
if(high_time == divide) begin
|
||||
high_time = divide - 1;
|
||||
w_edge = 1'b1;
|
||||
end
|
||||
|
||||
// Calculate low_time based on the divide setting and set no_count to
|
||||
// 0 as it is only used when divide is 1.
|
||||
low_time = divide - high_time;
|
||||
no_count = 1'b0;
|
||||
end
|
||||
|
||||
// Set the return value.
|
||||
mmcm_pll_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function calculates mx, delay_time, and phase_mux
|
||||
// of a non-fractional counter based on the divide and phase
|
||||
//
|
||||
// NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
|
||||
// is used.
|
||||
function [10:0] mmcm_pll_phase
|
||||
(
|
||||
// divide must be an integer (use fractional if not)
|
||||
// assumed that divide already checked to be valid
|
||||
input [7:0] divide, // Max divide is 128
|
||||
|
||||
// Phase is given in degrees (-360,000 to 360,000)
|
||||
input signed [31:0] phase
|
||||
);
|
||||
|
||||
reg [`FIXED_WIDTH:1] phase_in_cycles;
|
||||
reg [`FIXED_WIDTH:1] phase_fixed;
|
||||
reg [1:0] mx;
|
||||
reg [5:0] delay_time;
|
||||
reg [2:0] phase_mux;
|
||||
|
||||
reg [`FIXED_WIDTH:1] temp;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_pll_phase-divide:%d,phase:%d",
|
||||
divide, phase);
|
||||
`endif
|
||||
|
||||
if ((phase < -360000) || (phase > 360000)) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: phase of $phase is not between -360000 and 360000");
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
// If phase is less than 0, convert it to a positive phase shift
|
||||
// Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
|
||||
if(phase < 0) begin
|
||||
phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
|
||||
end else begin
|
||||
phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
|
||||
end
|
||||
|
||||
// Put phase in terms of decimal number of vco clock cycles
|
||||
phase_in_cycles = ( phase_fixed * divide ) / 360;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("phase_in_cycles: %h", phase_in_cycles);
|
||||
`endif
|
||||
|
||||
|
||||
temp = round_frac(phase_in_cycles, 3);
|
||||
|
||||
// set mx to 2'b00 that the phase mux from the VCO is enabled
|
||||
mx = 2'b00;
|
||||
phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
|
||||
delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("temp: %h", temp);
|
||||
`endif
|
||||
|
||||
// Setup the return value
|
||||
mmcm_pll_phase={mx, phase_mux, delay_time};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes the divide value and outputs the necessary lock values
|
||||
function [39:0] mmcm_pll_lock_lookup
|
||||
(
|
||||
input [6:0] divide // Max divide is 64
|
||||
);
|
||||
|
||||
reg [2559:0] lookup;
|
||||
|
||||
begin
|
||||
lookup = {
|
||||
// This table is composed of:
|
||||
// LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
|
||||
40'b00110_00110_1111101000_1111101001_0000000001,
|
||||
40'b00110_00110_1111101000_1111101001_0000000001,
|
||||
40'b01000_01000_1111101000_1111101001_0000000001,
|
||||
40'b01011_01011_1111101000_1111101001_0000000001,
|
||||
40'b01110_01110_1111101000_1111101001_0000000001,
|
||||
40'b10001_10001_1111101000_1111101001_0000000001,
|
||||
40'b10011_10011_1111101000_1111101001_0000000001,
|
||||
40'b10110_10110_1111101000_1111101001_0000000001,
|
||||
40'b11001_11001_1111101000_1111101001_0000000001,
|
||||
40'b11100_11100_1111101000_1111101001_0000000001,
|
||||
40'b11111_11111_1110000100_1111101001_0000000001,
|
||||
40'b11111_11111_1100111001_1111101001_0000000001,
|
||||
40'b11111_11111_1011101110_1111101001_0000000001,
|
||||
40'b11111_11111_1010111100_1111101001_0000000001,
|
||||
40'b11111_11111_1010001010_1111101001_0000000001,
|
||||
40'b11111_11111_1001110001_1111101001_0000000001,
|
||||
40'b11111_11111_1000111111_1111101001_0000000001,
|
||||
40'b11111_11111_1000100110_1111101001_0000000001,
|
||||
40'b11111_11111_1000001101_1111101001_0000000001,
|
||||
40'b11111_11111_0111110100_1111101001_0000000001,
|
||||
40'b11111_11111_0111011011_1111101001_0000000001,
|
||||
40'b11111_11111_0111000010_1111101001_0000000001,
|
||||
40'b11111_11111_0110101001_1111101001_0000000001,
|
||||
40'b11111_11111_0110010000_1111101001_0000000001,
|
||||
40'b11111_11111_0110010000_1111101001_0000000001,
|
||||
40'b11111_11111_0101110111_1111101001_0000000001,
|
||||
40'b11111_11111_0101011110_1111101001_0000000001,
|
||||
40'b11111_11111_0101011110_1111101001_0000000001,
|
||||
40'b11111_11111_0101000101_1111101001_0000000001,
|
||||
40'b11111_11111_0101000101_1111101001_0000000001,
|
||||
40'b11111_11111_0100101100_1111101001_0000000001,
|
||||
40'b11111_11111_0100101100_1111101001_0000000001,
|
||||
40'b11111_11111_0100101100_1111101001_0000000001,
|
||||
40'b11111_11111_0100010011_1111101001_0000000001,
|
||||
40'b11111_11111_0100010011_1111101001_0000000001,
|
||||
40'b11111_11111_0100010011_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001
|
||||
};
|
||||
|
||||
// Set lookup_entry with the explicit bits from lookup with a part select
|
||||
mmcm_pll_lock_lookup = lookup[ ((64-divide)*40) +: 40];
|
||||
`ifdef DEBUG
|
||||
$display("lock_lookup: %b", mmcm_pll_lock_lookup);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes the divide value and the bandwidth setting of the MMCM
|
||||
// and outputs the digital filter settings necessary.
|
||||
function [9:0] mmcm_pll_filter_lookup
|
||||
(
|
||||
input [6:0] divide, // Max divide is 64
|
||||
input [8*9:0] BANDWIDTH
|
||||
);
|
||||
|
||||
reg [639:0] lookup_low;
|
||||
reg [639:0] lookup_high;
|
||||
|
||||
reg [9:0] lookup_entry;
|
||||
|
||||
begin
|
||||
lookup_low = {
|
||||
// CP_RES_LFHF
|
||||
10'b0010_1111_00,
|
||||
10'b0010_1111_00,
|
||||
10'b0010_1111_00,
|
||||
10'b0010_1111_00,
|
||||
10'b0010_0111_00,
|
||||
10'b0010_1011_00,
|
||||
10'b0010_1101_00,
|
||||
10'b0010_0011_00,
|
||||
10'b0010_0101_00,
|
||||
10'b0010_0101_00,
|
||||
10'b0010_1001_00,
|
||||
10'b0010_1110_00,
|
||||
10'b0010_1110_00,
|
||||
10'b0010_1110_00,
|
||||
10'b0010_1110_00,
|
||||
10'b0010_0001_00,
|
||||
10'b0010_0001_00,
|
||||
10'b0010_0001_00,
|
||||
10'b0010_0110_00,
|
||||
10'b0010_0110_00,
|
||||
10'b0010_0110_00,
|
||||
10'b0010_0110_00,
|
||||
10'b0010_0110_00,
|
||||
10'b0010_0110_00,
|
||||
10'b0010_0110_00,
|
||||
10'b0010_1010_00,
|
||||
10'b0010_1010_00,
|
||||
10'b0010_1010_00,
|
||||
10'b0010_1010_00,
|
||||
10'b0010_1010_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00
|
||||
};
|
||||
|
||||
lookup_high = {
|
||||
// CP_RES_LFHF
|
||||
10'b0010_1111_00,
|
||||
10'b0100_1111_00,
|
||||
10'b0101_1011_00,
|
||||
10'b0111_0111_00,
|
||||
10'b1101_0111_00,
|
||||
10'b1110_1011_00,
|
||||
10'b1110_1101_00,
|
||||
10'b1111_0011_00,
|
||||
10'b1110_0101_00,
|
||||
10'b1111_0101_00,
|
||||
10'b1111_1001_00,
|
||||
10'b1101_0001_00,
|
||||
10'b1111_1001_00,
|
||||
10'b1111_1001_00,
|
||||
10'b1111_1001_00,
|
||||
10'b1111_1001_00,
|
||||
10'b1111_0101_00,
|
||||
10'b1111_0101_00,
|
||||
10'b1100_0001_00,
|
||||
10'b1100_0001_00,
|
||||
10'b1100_0001_00,
|
||||
10'b0101_1100_00,
|
||||
10'b0101_1100_00,
|
||||
10'b0101_1100_00,
|
||||
10'b0101_1100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0111_0001_00,
|
||||
10'b0111_0001_00,
|
||||
10'b0100_1100_00,
|
||||
10'b0100_1100_00,
|
||||
10'b0100_1100_00,
|
||||
10'b0100_1100_00,
|
||||
10'b0110_0001_00,
|
||||
10'b0110_0001_00,
|
||||
10'b0101_0110_00,
|
||||
10'b0101_0110_00,
|
||||
10'b0101_0110_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0100_1010_00,
|
||||
10'b0011_1100_00,
|
||||
10'b0011_1100_00
|
||||
};
|
||||
|
||||
// Set lookup_entry with the explicit bits from lookup with a part select
|
||||
if(BANDWIDTH == "LOW") begin
|
||||
// Low Bandwidth
|
||||
mmcm_pll_filter_lookup = lookup_low[ ((64-divide)*10) +: 10];
|
||||
end else begin
|
||||
// High or optimized bandwidth
|
||||
mmcm_pll_filter_lookup = lookup_high[ ((64-divide)*10) +: 10];
|
||||
end
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("filter_lookup: %b", mmcm_pll_filter_lookup);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes in the divide, phase, and duty cycle
|
||||
// setting to calculate the upper and lower counter registers.
|
||||
function [37:0] mmcm_pll_count_calc
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input signed [31:0] phase,
|
||||
input [31:0] duty_cycle // Multiplied by 100,000
|
||||
);
|
||||
|
||||
reg [13:0] div_calc;
|
||||
reg [16:0] phase_calc;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_pll_count_calc- divide:%h, phase:%d, duty_cycle:%d",
|
||||
divide, phase, duty_cycle);
|
||||
`endif
|
||||
|
||||
// w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
|
||||
div_calc = mmcm_pll_divider(divide, duty_cycle);
|
||||
// mx[10:9], pm[8:6], dt[5:0]
|
||||
phase_calc = mmcm_pll_phase(divide, phase);
|
||||
|
||||
// Return value is the upper and lower address of counter
|
||||
// Upper address is:
|
||||
// RESERVED [31:26]
|
||||
// MX [25:24]
|
||||
// EDGE [23]
|
||||
// NOCOUNT [22]
|
||||
// DELAY_TIME [21:16]
|
||||
// Lower Address is:
|
||||
// PHASE_MUX [15:13]
|
||||
// RESERVED [12]
|
||||
// HIGH_TIME [11:6]
|
||||
// LOW_TIME [5:0]
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
|
||||
divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
|
||||
div_calc[13], div_calc[12],
|
||||
phase_calc[16:15], phase_calc[5:0], phase_calc[14:12]);
|
||||
`endif
|
||||
|
||||
mmcm_pll_count_calc =
|
||||
{
|
||||
// Upper Address
|
||||
6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
|
||||
// Lower Address
|
||||
phase_calc[8:6], 1'b0, div_calc[11:0]
|
||||
};
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
// This function takes in the divide, phase, and duty cycle
|
||||
// setting to calculate the upper and lower counter registers.
|
||||
// for fractional multiply/divide functions.
|
||||
//
|
||||
//
|
||||
function [37:0] mmcm_frac_count_calc
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input signed [31:0] phase,
|
||||
input [31:0] duty_cycle, // Multiplied by 1,000
|
||||
input [9:0] frac // Multiplied by 1000
|
||||
);
|
||||
|
||||
//Required for fractional divide calculations
|
||||
reg [7:0] lt_frac;
|
||||
reg [7:0] ht_frac;
|
||||
|
||||
reg /*[7:0]*/ wf_fall_frac;
|
||||
reg /*[7:0]*/ wf_rise_frac;
|
||||
|
||||
reg [31:0] a;
|
||||
reg [7:0] pm_rise_frac_filtered ;
|
||||
reg [7:0] pm_fall_frac_filtered ;
|
||||
reg [7:0] clkout0_divide_int;
|
||||
reg [2:0] clkout0_divide_frac;
|
||||
reg [7:0] even_part_high;
|
||||
reg [7:0] even_part_low;
|
||||
|
||||
reg [7:0] odd;
|
||||
reg [7:0] odd_and_frac;
|
||||
|
||||
reg [7:0] pm_fall;
|
||||
reg [7:0] pm_rise;
|
||||
reg [7:0] dt;
|
||||
reg [7:0] dt_int;
|
||||
reg [63:0] dt_calc;
|
||||
|
||||
reg [7:0] pm_rise_frac;
|
||||
reg [7:0] pm_fall_frac;
|
||||
|
||||
reg [31:0] a_per_in_octets;
|
||||
reg [31:0] a_phase_in_cycles;
|
||||
|
||||
parameter precision = 0.125;
|
||||
|
||||
reg [31:0] phase_fixed; // changed to 31:0 from 32:1 jt 5/2/11
|
||||
reg [31: 0] phase_pos;
|
||||
reg [31: 0] phase_vco;
|
||||
reg [31:0] temp;// changed to 31:0 from 32:1 jt 5/2/11
|
||||
reg [13:0] div_calc;
|
||||
reg [16:0] phase_calc;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_frac_count_calc- divide:%h, phase:%d, duty_cycle:%d",
|
||||
divide, phase, duty_cycle);
|
||||
`endif
|
||||
|
||||
//convert phase to fixed
|
||||
if ((phase < -360000) || (phase > 360000)) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: phase of $phase is not between -360000 and 360000");
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
|
||||
// Return value is
|
||||
// Transfer data
|
||||
// RESERVED [37:36]
|
||||
// FRAC_TIME [35:33]
|
||||
// FRAC_WF_FALL [32]
|
||||
// Upper address is:
|
||||
// RESERVED [31:26]
|
||||
// MX [25:24]
|
||||
// EDGE [23]
|
||||
// NOCOUNT [22]
|
||||
// DELAY_TIME [21:16]
|
||||
// Lower Address is:
|
||||
// PHASE_MUX [15:13]
|
||||
// RESERVED [12]
|
||||
// HIGH_TIME [11:6]
|
||||
// LOW_TIME [5:0]
|
||||
|
||||
|
||||
|
||||
clkout0_divide_frac = frac / 125;
|
||||
clkout0_divide_int = divide;
|
||||
|
||||
even_part_high = clkout0_divide_int >> 1;//$rtoi(clkout0_divide_int / 2);
|
||||
even_part_low = even_part_high;
|
||||
|
||||
odd = clkout0_divide_int - even_part_high - even_part_low;
|
||||
odd_and_frac = (8*odd) + clkout0_divide_frac;
|
||||
|
||||
lt_frac = even_part_high - (odd_and_frac <= 9);//IF(odd_and_frac>9,even_part_high, even_part_high - 1)
|
||||
ht_frac = even_part_low - (odd_and_frac <= 8);//IF(odd_and_frac>8,even_part_low, even_part_low- 1)
|
||||
|
||||
pm_fall = {odd[6:0],2'b00} + {6'h00, clkout0_divide_frac[2:1]}; // using >> instead of clkout0_divide_frac / 2
|
||||
pm_rise = 0; //0
|
||||
|
||||
wf_fall_frac = ((odd_and_frac >=2) && (odd_and_frac <=9)) || ((clkout0_divide_frac == 1) && (clkout0_divide_int == 2));//CRS610807
|
||||
wf_rise_frac = (odd_and_frac >=1) && (odd_and_frac <=8);//IF(odd_and_frac>=1,IF(odd_and_frac <= 8,1,0),0)
|
||||
|
||||
|
||||
|
||||
//Calculate phase in fractional cycles
|
||||
a_per_in_octets = (8 * divide) + (frac / 125) ;
|
||||
a_phase_in_cycles = (phase+10) * a_per_in_octets / 360000 ;//Adding 1 due to rounding errors
|
||||
pm_rise_frac = (a_phase_in_cycles[7:0] ==8'h00)?8'h00:a_phase_in_cycles[7:0] - {a_phase_in_cycles[7:3],3'b000};
|
||||
|
||||
dt_calc = ((phase+10) * a_per_in_octets / 8 )/360000 ;//TRUNC(phase* divide / 360); //or_simply (a_per_in_octets / 8)
|
||||
dt = dt_calc[7:0];
|
||||
|
||||
pm_rise_frac_filtered = (pm_rise_frac >=8) ? (pm_rise_frac ) - 8: pm_rise_frac ; //((phase_fixed * (divide + frac / 1000)) / 360) - {pm_rise_frac[7:3],3'b000};//$rtoi(clkout0_phase * clkout0_divide / 45);//a;
|
||||
|
||||
dt_int = dt + (& pm_rise_frac[7:4]); //IF(pm_rise_overwriting>7,dt+1,dt)
|
||||
pm_fall_frac = pm_fall + pm_rise_frac;
|
||||
pm_fall_frac_filtered = pm_fall + pm_rise_frac - {pm_fall_frac[7:3], 3'b000};
|
||||
|
||||
div_calc = mmcm_pll_divider(divide, duty_cycle); //Use to determine edge[7], no count[6]
|
||||
phase_calc = mmcm_pll_phase(divide, phase);// returns{mx[1:0], phase_mux[2:0], delay_time[5:0]}
|
||||
|
||||
mmcm_frac_count_calc[37:0] =
|
||||
{ 2'b00, pm_fall_frac_filtered[2:0], wf_fall_frac,
|
||||
1'b0, clkout0_divide_frac[2:0], 1'b1, wf_rise_frac, phase_calc[10:9], div_calc[13:12], dt[5:0],
|
||||
pm_rise_frac_filtered[2], pm_rise_frac_filtered[1], pm_rise_frac_filtered[0], 1'b0, ht_frac[5:0], lt_frac[5:0]
|
||||
} ;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("-%d.%d p%d>> :DADDR_9_15 frac30to28.frac_en.wf_r_frac.dt:%b%d%d_%b:DADDR_7_13 pm_f_frac_filtered_29to27.wf_f_frac_26:%b%d:DADDR_8_14.pm_r_frac_filt_15to13.ht_frac.lt_frac:%b%b%b:", divide, frac, phase, clkout0_divide_frac, 1, wf_rise_frac, dt, pm_fall_frac_filtered, wf_fall_frac, pm_rise_frac_filtered, ht_frac, lt_frac);
|
||||
`endif
|
||||
|
||||
end
|
||||
endfunction
|
||||
|
||||
+531
@@ -0,0 +1,531 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Company: Xilinx
|
||||
// Engineer: Jim Tatsukawa, Karl Kurbjun and Carl Ribbing
|
||||
// Date: 7/30/2014
|
||||
// Design Name: PLLE2 DRP
|
||||
// Module Name: plle2_drp_func.h
|
||||
// Version: 2.00
|
||||
// Target Devices: 7 Series || PLL
|
||||
// Tool versions: 2014.3
|
||||
// Description: This header provides the functions necessary to
|
||||
// calculate the DRP register values for the V6 PLL.
|
||||
// Updated for CR663854.
|
||||
//
|
||||
// Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
|
||||
// INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
|
||||
// PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
|
||||
// PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
// ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
||||
// APPLICATION OR STANDARD, XILINX IS MAKING NO
|
||||
// REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
|
||||
// FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
|
||||
// RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
|
||||
// REQUIRE FOR YOUR IMPLEMENTATION. XILINX
|
||||
// EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
|
||||
// RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
|
||||
// INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
||||
// REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
|
||||
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE.
|
||||
//
|
||||
// (c) Copyright 2009-2010 Xilinx, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// These are user functions that should not be modified. Changes to the defines
|
||||
// or code within the functions may alter the accuracy of the calculations.
|
||||
|
||||
// Define debug to provide extra messages durring elaboration
|
||||
//`define DEBUG 1
|
||||
|
||||
// FRAC_PRECISION describes the width of the fractional portion of the fixed
|
||||
// point numbers. These should not be modified, they are for development
|
||||
// only
|
||||
`define FRAC_PRECISION 10
|
||||
// FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
|
||||
// Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
|
||||
// greater than 32
|
||||
`define FIXED_WIDTH 32
|
||||
|
||||
// This function takes a fixed point number and rounds it to the nearest
|
||||
// fractional precision bit.
|
||||
function [`FIXED_WIDTH:1] round_frac
|
||||
(
|
||||
// Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
|
||||
input [`FIXED_WIDTH:1] decimal,
|
||||
|
||||
// This describes the precision of the fraction, for example a value
|
||||
// of 1 would modify the fractional so that instead of being a .16
|
||||
// fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
|
||||
input [`FIXED_WIDTH:1] precision
|
||||
);
|
||||
|
||||
begin
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("round_frac - decimal: %h, precision: %h", decimal, precision);
|
||||
`endif
|
||||
// If the fractional precision bit is high then round up
|
||||
if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
|
||||
round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
|
||||
end else begin
|
||||
round_frac = decimal;
|
||||
end
|
||||
`ifdef DEBUG
|
||||
$display("round_frac: %h", round_frac);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function calculates high_time, low_time, w_edge, and no_count
|
||||
// of a non-fractional counter based on the divide and duty cycle
|
||||
//
|
||||
// NOTE: high_time and low_time are returned as integers between 0 and 63
|
||||
// inclusive. 64 should equal 6'b000000 (in other words it is okay to
|
||||
// ignore the overflow)
|
||||
function [13:0] mmcm_pll_divider
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
|
||||
);
|
||||
|
||||
reg [`FIXED_WIDTH:1] duty_cycle_fix;
|
||||
|
||||
// High/Low time is initially calculated with a wider integer to prevent a
|
||||
// calculation error when it overflows to 64.
|
||||
reg [6:0] high_time;
|
||||
reg [6:0] low_time;
|
||||
reg w_edge;
|
||||
reg no_count;
|
||||
|
||||
reg [`FIXED_WIDTH:1] temp;
|
||||
|
||||
begin
|
||||
// Duty Cycle must be between 0 and 1,000
|
||||
if(duty_cycle <=0 || duty_cycle >= 100000) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: duty_cycle: %d is invalid", duty_cycle);
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
// Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
|
||||
duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("duty_cycle_fix: %h", duty_cycle_fix);
|
||||
`endif
|
||||
|
||||
// If the divide is 1 nothing needs to be set except the no_count bit.
|
||||
// Other values are dummies
|
||||
if(divide == 7'h01) begin
|
||||
high_time = 7'h01;
|
||||
w_edge = 1'b0;
|
||||
low_time = 7'h01;
|
||||
no_count = 1'b1;
|
||||
end else begin
|
||||
temp = round_frac(duty_cycle_fix*divide, 1);
|
||||
|
||||
// comes from above round_frac
|
||||
high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
|
||||
// If the duty cycle * divide rounded is .5 or greater then this bit
|
||||
// is set.
|
||||
w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
|
||||
|
||||
// If the high time comes out to 0, it needs to be set to at least 1
|
||||
// and w_edge set to 0
|
||||
if(high_time == 7'h00) begin
|
||||
high_time = 7'h01;
|
||||
w_edge = 1'b0;
|
||||
end
|
||||
|
||||
if(high_time == divide) begin
|
||||
high_time = divide - 1;
|
||||
w_edge = 1'b1;
|
||||
end
|
||||
|
||||
// Calculate low_time based on the divide setting and set no_count to
|
||||
// 0 as it is only used when divide is 1.
|
||||
low_time = divide - high_time;
|
||||
no_count = 1'b0;
|
||||
end
|
||||
|
||||
// Set the return value.
|
||||
mmcm_pll_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function calculates mx, delay_time, and phase_mux
|
||||
// of a non-fractional counter based on the divide and phase
|
||||
//
|
||||
// NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
|
||||
// is used.
|
||||
function [10:0] mmcm_pll_phase
|
||||
(
|
||||
// divide must be an integer (use fractional if not)
|
||||
// assumed that divide already checked to be valid
|
||||
input [7:0] divide, // Max divide is 128
|
||||
|
||||
// Phase is given in degrees (-360,000 to 360,000)
|
||||
input signed [31:0] phase
|
||||
);
|
||||
|
||||
reg [`FIXED_WIDTH:1] phase_in_cycles;
|
||||
reg [`FIXED_WIDTH:1] phase_fixed;
|
||||
reg [1:0] mx;
|
||||
reg [5:0] delay_time;
|
||||
reg [2:0] phase_mux;
|
||||
|
||||
reg [`FIXED_WIDTH:1] temp;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_pll_phase-divide:%d,phase:%d",
|
||||
divide, phase);
|
||||
`endif
|
||||
|
||||
if ((phase < -360000) || (phase > 360000)) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: phase of $phase is not between -360000 and 360000");
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
// If phase is less than 0, convert it to a positive phase shift
|
||||
// Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
|
||||
if(phase < 0) begin
|
||||
phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
|
||||
end else begin
|
||||
phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
|
||||
end
|
||||
|
||||
// Put phase in terms of decimal number of vco clock cycles
|
||||
phase_in_cycles = ( phase_fixed * divide ) / 360;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("phase_in_cycles: %h", phase_in_cycles);
|
||||
`endif
|
||||
|
||||
|
||||
temp = round_frac(phase_in_cycles, 3);
|
||||
|
||||
// set mx to 2'b00 that the phase mux from the VCO is enabled
|
||||
mx = 2'b00;
|
||||
phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
|
||||
delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("temp: %h", temp);
|
||||
`endif
|
||||
|
||||
// Setup the return value
|
||||
mmcm_pll_phase={mx, phase_mux, delay_time};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes the divide value and outputs the necessary lock values
|
||||
function [39:0] mmcm_pll_lock_lookup
|
||||
(
|
||||
input [6:0] divide // Max divide is 64
|
||||
);
|
||||
|
||||
reg [2559:0] lookup;
|
||||
|
||||
begin
|
||||
lookup = {
|
||||
// This table is composed of:
|
||||
// LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
|
||||
40'b00110_00110_1111101000_1111101001_0000000001,
|
||||
40'b00110_00110_1111101000_1111101001_0000000001,
|
||||
40'b01000_01000_1111101000_1111101001_0000000001,
|
||||
40'b01011_01011_1111101000_1111101001_0000000001,
|
||||
40'b01110_01110_1111101000_1111101001_0000000001,
|
||||
40'b10001_10001_1111101000_1111101001_0000000001,
|
||||
40'b10011_10011_1111101000_1111101001_0000000001,
|
||||
40'b10110_10110_1111101000_1111101001_0000000001,
|
||||
40'b11001_11001_1111101000_1111101001_0000000001,
|
||||
40'b11100_11100_1111101000_1111101001_0000000001,
|
||||
40'b11111_11111_1110000100_1111101001_0000000001,
|
||||
40'b11111_11111_1100111001_1111101001_0000000001,
|
||||
40'b11111_11111_1011101110_1111101001_0000000001,
|
||||
40'b11111_11111_1010111100_1111101001_0000000001,
|
||||
40'b11111_11111_1010001010_1111101001_0000000001,
|
||||
40'b11111_11111_1001110001_1111101001_0000000001,
|
||||
40'b11111_11111_1000111111_1111101001_0000000001,
|
||||
40'b11111_11111_1000100110_1111101001_0000000001,
|
||||
40'b11111_11111_1000001101_1111101001_0000000001,
|
||||
40'b11111_11111_0111110100_1111101001_0000000001,
|
||||
40'b11111_11111_0111011011_1111101001_0000000001,
|
||||
40'b11111_11111_0111000010_1111101001_0000000001,
|
||||
40'b11111_11111_0110101001_1111101001_0000000001,
|
||||
40'b11111_11111_0110010000_1111101001_0000000001,
|
||||
40'b11111_11111_0110010000_1111101001_0000000001,
|
||||
40'b11111_11111_0101110111_1111101001_0000000001,
|
||||
40'b11111_11111_0101011110_1111101001_0000000001,
|
||||
40'b11111_11111_0101011110_1111101001_0000000001,
|
||||
40'b11111_11111_0101000101_1111101001_0000000001,
|
||||
40'b11111_11111_0101000101_1111101001_0000000001,
|
||||
40'b11111_11111_0100101100_1111101001_0000000001,
|
||||
40'b11111_11111_0100101100_1111101001_0000000001,
|
||||
40'b11111_11111_0100101100_1111101001_0000000001,
|
||||
40'b11111_11111_0100010011_1111101001_0000000001,
|
||||
40'b11111_11111_0100010011_1111101001_0000000001,
|
||||
40'b11111_11111_0100010011_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001
|
||||
};
|
||||
|
||||
// Set lookup_entry with the explicit bits from lookup with a part select
|
||||
mmcm_pll_lock_lookup = lookup[ ((64-divide)*40) +: 40];
|
||||
`ifdef DEBUG
|
||||
$display("lock_lookup: %b", mmcm_pll_lock_lookup);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes the divide value and the bandwidth setting of the PLL
|
||||
// and outputs the digital filter settings necessary.
|
||||
function [9:0] mmcm_pll_filter_lookup
|
||||
(
|
||||
input [6:0] divide, // Max divide is 64
|
||||
input [8*9:0] BANDWIDTH
|
||||
);
|
||||
|
||||
reg [639:0] lookup_low;
|
||||
reg [639:0] lookup_high;
|
||||
|
||||
reg [9:0] lookup_entry;
|
||||
|
||||
begin
|
||||
lookup_low = {
|
||||
// CP_RES_LFHF
|
||||
10'b0010_1111_00,
|
||||
10'b0010_1111_00,
|
||||
10'b0010_0111_00,
|
||||
10'b0010_1101_00,
|
||||
10'b0010_0101_00,
|
||||
10'b0010_0101_00,
|
||||
10'b0010_1001_00,
|
||||
10'b0010_1110_00,
|
||||
10'b0010_1110_00,
|
||||
10'b0010_0001_00,
|
||||
10'b0010_0001_00,
|
||||
10'b0010_0110_00,
|
||||
10'b0010_0110_00,
|
||||
10'b0010_0110_00,
|
||||
10'b0010_0110_00,
|
||||
10'b0010_1010_00,
|
||||
10'b0010_1010_00,
|
||||
10'b0010_1010_00,
|
||||
10'b0010_1010_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_1100_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0010_0010_00,
|
||||
10'b0011_1100_00,
|
||||
10'b0011_1100_00,
|
||||
10'b0011_1100_00,
|
||||
10'b0011_1100_00,
|
||||
10'b0011_1100_00,
|
||||
10'b0011_1100_00,
|
||||
10'b0011_1100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00
|
||||
};
|
||||
|
||||
lookup_high = {
|
||||
// CP_RES_LFHF
|
||||
10'b0011_0111_00,
|
||||
10'b0011_0111_00,
|
||||
10'b0101_1111_00,
|
||||
10'b0111_1111_00,
|
||||
10'b0111_1011_00,
|
||||
10'b1101_0111_00,
|
||||
10'b1110_1011_00,
|
||||
10'b1110_1101_00,
|
||||
10'b1111_1101_00,
|
||||
10'b1111_0111_00,
|
||||
10'b1111_1011_00,
|
||||
10'b1111_1101_00,
|
||||
10'b1111_0011_00,
|
||||
10'b1110_0101_00,
|
||||
10'b1111_0101_00,
|
||||
10'b1111_0101_00,
|
||||
10'b1111_0101_00,
|
||||
10'b1111_0101_00,
|
||||
10'b0111_0110_00,
|
||||
10'b0111_0110_00,
|
||||
10'b0111_0110_00,
|
||||
10'b0111_0110_00,
|
||||
10'b0101_1100_00,
|
||||
10'b0101_1100_00,
|
||||
10'b0101_1100_00,
|
||||
10'b1100_0001_00,
|
||||
10'b1100_0001_00,
|
||||
10'b1100_0001_00,
|
||||
10'b1100_0001_00,
|
||||
10'b1100_0001_00,
|
||||
10'b1100_0001_00,
|
||||
10'b1100_0001_00,
|
||||
10'b1100_0001_00,
|
||||
10'b0100_0010_00,
|
||||
10'b0100_0010_00,
|
||||
10'b0100_0010_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0011_0100_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0010_1000_00,
|
||||
10'b0100_1100_00,
|
||||
10'b0100_1100_00,
|
||||
10'b0100_1100_00,
|
||||
10'b0100_1100_00,
|
||||
10'b0100_1100_00,
|
||||
10'b0100_1100_00,
|
||||
10'b0100_1100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00,
|
||||
10'b0010_0100_00
|
||||
};
|
||||
|
||||
// Set lookup_entry with the explicit bits from lookup with a part select
|
||||
if(BANDWIDTH == "LOW") begin
|
||||
// Low Bandwidth
|
||||
mmcm_pll_filter_lookup = lookup_low[ ((64-divide)*10) +: 10];
|
||||
end else begin
|
||||
// High or optimized bandwidth
|
||||
mmcm_pll_filter_lookup = lookup_high[ ((64-divide)*10) +: 10];
|
||||
end
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("filter_lookup: %b", mmcm_pll_filter_lookup);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes in the divide, phase, and duty cycle
|
||||
// setting to calculate the upper and lower counter registers.
|
||||
function [37:0] mmcm_pll_count_calc
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input signed [31:0] phase,
|
||||
input [31:0] duty_cycle // Multiplied by 100,000
|
||||
);
|
||||
|
||||
reg [13:0] div_calc;
|
||||
reg [16:0] phase_calc;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_pll_count_calc- divide:%h, phase:%d, duty_cycle:%d",
|
||||
divide, phase, duty_cycle);
|
||||
`endif
|
||||
|
||||
// w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
|
||||
div_calc = mmcm_pll_divider(divide, duty_cycle);
|
||||
// mx[10:9], pm[8:6], dt[5:0]
|
||||
phase_calc = mmcm_pll_phase(divide, phase);
|
||||
|
||||
// Return value is the upper and lower address of counter
|
||||
// Upper address is:
|
||||
// RESERVED [31:26]
|
||||
// MX [25:24]
|
||||
// EDGE [23]
|
||||
// NOCOUNT [22]
|
||||
// DELAY_TIME [21:16]
|
||||
// Lower Address is:
|
||||
// PHASE_MUX [15:13]
|
||||
// RESERVED [12]
|
||||
// HIGH_TIME [11:6]
|
||||
// LOW_TIME [5:0]
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
|
||||
divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
|
||||
div_calc[13], div_calc[12],
|
||||
phase_calc[16:15], phase_calc[5:0], phase_calc[14:12]);
|
||||
`endif
|
||||
|
||||
mmcm_pll_count_calc =
|
||||
{
|
||||
// Upper Address
|
||||
6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
|
||||
// Lower Address
|
||||
phase_calc[8:6], 1'b0, div_calc[11:0]
|
||||
};
|
||||
end
|
||||
endfunction
|
||||
+671
@@ -0,0 +1,671 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Company: Xilinx
|
||||
// Engineer: Jim Tatsukawa
|
||||
// Date: 7/30/2014
|
||||
// Design Name: MMCME2 DRP
|
||||
// Module Name: mmcme2_drp_func.h
|
||||
// Version: 1.04
|
||||
// Target Devices: UltraScale Architecture || MMCM
|
||||
// Tool versions: 2014.3
|
||||
// Description: This header provides the functions necessary to
|
||||
// calculate the DRP register values for the V6 MMCM.
|
||||
//
|
||||
// Revision Notes: 3/22 - Updating lookup_low/lookup_high (CR)
|
||||
// 4/13 - Fractional divide function in mmcm_frac_count_calc function. CRS610807
|
||||
//
|
||||
// Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
|
||||
// INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
|
||||
// PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
|
||||
// PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
// ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
||||
// APPLICATION OR STANDARD, XILINX IS MAKING NO
|
||||
// REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
|
||||
// FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
|
||||
// RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
|
||||
// REQUIRE FOR YOUR IMPLEMENTATION. XILINX
|
||||
// EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
|
||||
// RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
|
||||
// INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
||||
// REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
|
||||
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE.
|
||||
//
|
||||
// (c) Copyright 2009-2010 Xilinx, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// These are user functions that should not be modified. Changes to the defines
|
||||
// or code within the functions may alter the accuracy of the calculations.
|
||||
|
||||
// Define debug to provide extra messages durring elaboration
|
||||
//`define DEBUG 1
|
||||
|
||||
// FRAC_PRECISION describes the width of the fractional portion of the fixed
|
||||
// point numbers. These should not be modified, they are for development
|
||||
// only
|
||||
`define FRAC_PRECISION 10
|
||||
// FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
|
||||
// Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
|
||||
// greater than 32
|
||||
`define FIXED_WIDTH 32
|
||||
|
||||
// This function takes a fixed point number and rounds it to the nearest
|
||||
// fractional precision bit.
|
||||
function [`FIXED_WIDTH:1] round_frac
|
||||
(
|
||||
// Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
|
||||
input [`FIXED_WIDTH:1] decimal,
|
||||
|
||||
// This describes the precision of the fraction, for example a value
|
||||
// of 1 would modify the fractional so that instead of being a .16
|
||||
// fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
|
||||
input [`FIXED_WIDTH:1] precision
|
||||
);
|
||||
|
||||
begin
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("round_frac - decimal: %h, precision: %h", decimal, precision);
|
||||
`endif
|
||||
// If the fractional precision bit is high then round up
|
||||
if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
|
||||
round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
|
||||
end else begin
|
||||
round_frac = decimal;
|
||||
end
|
||||
`ifdef DEBUG
|
||||
$display("round_frac: %h", round_frac);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function calculates high_time, low_time, w_edge, and no_count
|
||||
// of a non-fractional counter based on the divide and duty cycle
|
||||
//
|
||||
// NOTE: high_time and low_time are returned as integers between 0 and 63
|
||||
// inclusive. 64 should equal 6'b000000 (in other words it is okay to
|
||||
// ignore the overflow)
|
||||
function [13:0] mmcm_pll_divider
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
|
||||
);
|
||||
|
||||
reg [`FIXED_WIDTH:1] duty_cycle_fix;
|
||||
|
||||
// High/Low time is initially calculated with a wider integer to prevent a
|
||||
// calculation error when it overflows to 64.
|
||||
reg [6:0] high_time;
|
||||
reg [6:0] low_time;
|
||||
reg w_edge;
|
||||
reg no_count;
|
||||
|
||||
reg [`FIXED_WIDTH:1] temp;
|
||||
|
||||
begin
|
||||
// Duty Cycle must be between 0 and 1,000
|
||||
if(duty_cycle <=0 || duty_cycle >= 100000) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: duty_cycle: %d is invalid", duty_cycle);
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
// Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
|
||||
duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("duty_cycle_fix: %h", duty_cycle_fix);
|
||||
`endif
|
||||
|
||||
// If the divide is 1 nothing needs to be set except the no_count bit.
|
||||
// Other values are dummies
|
||||
if(divide == 7'h01) begin
|
||||
high_time = 7'h01;
|
||||
w_edge = 1'b0;
|
||||
low_time = 7'h01;
|
||||
no_count = 1'b1;
|
||||
end else begin
|
||||
temp = round_frac(duty_cycle_fix*divide, 1);
|
||||
|
||||
// comes from above round_frac
|
||||
high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
|
||||
// If the duty cycle * divide rounded is .5 or greater then this bit
|
||||
// is set.
|
||||
w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
|
||||
|
||||
// If the high time comes out to 0, it needs to be set to at least 1
|
||||
// and w_edge set to 0
|
||||
if(high_time == 7'h00) begin
|
||||
high_time = 7'h01;
|
||||
w_edge = 1'b0;
|
||||
end
|
||||
|
||||
if(high_time == divide) begin
|
||||
high_time = divide - 1;
|
||||
w_edge = 1'b1;
|
||||
end
|
||||
|
||||
// Calculate low_time based on the divide setting and set no_count to
|
||||
// 0 as it is only used when divide is 1.
|
||||
low_time = divide - high_time;
|
||||
no_count = 1'b0;
|
||||
end
|
||||
|
||||
// Set the return value.
|
||||
mmcm_pll_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function calculates mx, delay_time, and phase_mux
|
||||
// of a non-fractional counter based on the divide and phase
|
||||
//
|
||||
// NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
|
||||
// is used.
|
||||
function [10:0] mmcm_pll_phase
|
||||
(
|
||||
// divide must be an integer (use fractional if not)
|
||||
// assumed that divide already checked to be valid
|
||||
input [7:0] divide, // Max divide is 128
|
||||
|
||||
// Phase is given in degrees (-360,000 to 360,000)
|
||||
input signed [31:0] phase
|
||||
);
|
||||
|
||||
reg [`FIXED_WIDTH:1] phase_in_cycles;
|
||||
reg [`FIXED_WIDTH:1] phase_fixed;
|
||||
reg [1:0] mx;
|
||||
reg [5:0] delay_time;
|
||||
reg [2:0] phase_mux;
|
||||
|
||||
reg [`FIXED_WIDTH:1] temp;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_pll_phase-divide:%d,phase:%d",
|
||||
divide, phase);
|
||||
`endif
|
||||
|
||||
if ((phase < -360000) || (phase > 360000)) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: phase of $phase is not between -360000 and 360000");
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
// If phase is less than 0, convert it to a positive phase shift
|
||||
// Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
|
||||
if(phase < 0) begin
|
||||
phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
|
||||
end else begin
|
||||
phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
|
||||
end
|
||||
|
||||
// Put phase in terms of decimal number of vco clock cycles
|
||||
phase_in_cycles = ( phase_fixed * divide ) / 360;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("phase_in_cycles: %h", phase_in_cycles);
|
||||
`endif
|
||||
|
||||
|
||||
temp = round_frac(phase_in_cycles, 3);
|
||||
|
||||
// set mx to 2'b00 that the phase mux from the VCO is enabled
|
||||
mx = 2'b00;
|
||||
phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
|
||||
delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("temp: %h", temp);
|
||||
`endif
|
||||
|
||||
// Setup the return value
|
||||
mmcm_pll_phase={mx, phase_mux, delay_time};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes the divide value and outputs the necessary lock values
|
||||
function [39:0] mmcm_pll_lock_lookup
|
||||
(
|
||||
input [6:0] divide // Max divide is 64
|
||||
);
|
||||
|
||||
reg [2559:0] lookup;
|
||||
|
||||
begin
|
||||
lookup = {
|
||||
// This table is composed of:
|
||||
// LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
|
||||
40'b00110_00110_1111101000_1111101001_0000000001,
|
||||
40'b00110_00110_1111101000_1111101001_0000000001,
|
||||
40'b01000_01000_1111101000_1111101001_0000000001,
|
||||
40'b01011_01011_1111101000_1111101001_0000000001,
|
||||
40'b01110_01110_1111101000_1111101001_0000000001,
|
||||
40'b10001_10001_1111101000_1111101001_0000000001,
|
||||
40'b10011_10011_1111101000_1111101001_0000000001,
|
||||
40'b10110_10110_1111101000_1111101001_0000000001,
|
||||
40'b11001_11001_1111101000_1111101001_0000000001,
|
||||
40'b11100_11100_1111101000_1111101001_0000000001,
|
||||
40'b11111_11111_1110000100_1111101001_0000000001,
|
||||
40'b11111_11111_1100111001_1111101001_0000000001,
|
||||
40'b11111_11111_1011101110_1111101001_0000000001,
|
||||
40'b11111_11111_1010111100_1111101001_0000000001,
|
||||
40'b11111_11111_1010001010_1111101001_0000000001,
|
||||
40'b11111_11111_1001110001_1111101001_0000000001,
|
||||
40'b11111_11111_1000111111_1111101001_0000000001,
|
||||
40'b11111_11111_1000100110_1111101001_0000000001,
|
||||
40'b11111_11111_1000001101_1111101001_0000000001,
|
||||
40'b11111_11111_0111110100_1111101001_0000000001,
|
||||
40'b11111_11111_0111011011_1111101001_0000000001,
|
||||
40'b11111_11111_0111000010_1111101001_0000000001,
|
||||
40'b11111_11111_0110101001_1111101001_0000000001,
|
||||
40'b11111_11111_0110010000_1111101001_0000000001,
|
||||
40'b11111_11111_0110010000_1111101001_0000000001,
|
||||
40'b11111_11111_0101110111_1111101001_0000000001,
|
||||
40'b11111_11111_0101011110_1111101001_0000000001,
|
||||
40'b11111_11111_0101011110_1111101001_0000000001,
|
||||
40'b11111_11111_0101000101_1111101001_0000000001,
|
||||
40'b11111_11111_0101000101_1111101001_0000000001,
|
||||
40'b11111_11111_0100101100_1111101001_0000000001,
|
||||
40'b11111_11111_0100101100_1111101001_0000000001,
|
||||
40'b11111_11111_0100101100_1111101001_0000000001,
|
||||
40'b11111_11111_0100010011_1111101001_0000000001,
|
||||
40'b11111_11111_0100010011_1111101001_0000000001,
|
||||
40'b11111_11111_0100010011_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001
|
||||
};
|
||||
|
||||
// Set lookup_entry with the explicit bits from lookup with a part select
|
||||
mmcm_pll_lock_lookup = lookup[ ((64-divide)*40) +: 40];
|
||||
`ifdef DEBUG
|
||||
$display("lock_lookup: %b", mmcm_pll_lock_lookup);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes the divide value and the bandwidth setting of the MMCM
|
||||
// and outputs the digital filter settings necessary.
|
||||
function [9:0] mmcm_pll_filter_lookup
|
||||
(
|
||||
input [6:0] divide, // Max divide is 64
|
||||
input [8*9:0] BANDWIDTH
|
||||
);
|
||||
|
||||
reg [639:0] lookup_low;
|
||||
reg [639:0] lookup_high;
|
||||
|
||||
reg [9:0] lookup_entry;
|
||||
|
||||
begin
|
||||
lookup_low = {
|
||||
// CP_RES_LFHF
|
||||
10'b0010_1111_11,
|
||||
10'b0010_1111_11,
|
||||
10'b0010_1111_11,
|
||||
10'b0010_1111_11,
|
||||
10'b0010_1111_11,
|
||||
10'b0010_1111_11,
|
||||
10'b0010_0111_11,
|
||||
10'b0010_0111_11,
|
||||
10'b0010_0111_11,
|
||||
10'b0010_1101_11,
|
||||
10'b0010_1101_11,
|
||||
10'b0010_1101_11,
|
||||
10'b0010_0011_11,
|
||||
10'b0010_0101_11,
|
||||
10'b0010_0101_11,
|
||||
10'b0010_0101_11,
|
||||
10'b0010_1001_11,
|
||||
10'b0010_1001_11,
|
||||
10'b0010_1110_11,
|
||||
10'b0010_1110_11,
|
||||
10'b0010_1110_11,
|
||||
10'b0010_1110_11,
|
||||
10'b0010_1110_11,
|
||||
10'b0010_1110_11,
|
||||
10'b0010_0001_11,
|
||||
10'b0010_0001_11,
|
||||
10'b0010_0001_11,
|
||||
10'b0010_0001_11,
|
||||
10'b0010_0001_11,
|
||||
10'b0010_0110_11,
|
||||
10'b0010_0110_11,
|
||||
10'b0010_0110_11,
|
||||
10'b0010_0110_11,
|
||||
10'b0010_0110_11,
|
||||
10'b0010_0110_11,
|
||||
10'b0010_0110_11,
|
||||
10'b0010_0110_11,
|
||||
10'b0010_0110_11,
|
||||
10'b0010_0110_11,
|
||||
10'b0010_1010_11,
|
||||
10'b0010_1010_11,
|
||||
10'b0010_1010_11,
|
||||
10'b0010_1010_11,
|
||||
10'b0010_1010_11,
|
||||
10'b0010_1010_11,
|
||||
10'b0010_1010_11,
|
||||
10'b0010_1010_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11,
|
||||
10'b0010_1100_11
|
||||
};
|
||||
|
||||
lookup_high = {
|
||||
// CP_RES_LFHF
|
||||
10'b0010_1111_11,
|
||||
10'b0010_1111_11,
|
||||
10'b0010_1011_11,
|
||||
10'b0011_1111_11,
|
||||
10'b0100_1111_11,
|
||||
10'b0100_1111_11,
|
||||
10'b0101_1111_11,
|
||||
10'b0110_1111_11,
|
||||
10'b0111_1111_11,
|
||||
10'b0111_1111_11,
|
||||
10'b1100_1111_11,
|
||||
10'b1101_1111_11,
|
||||
10'b1110_1111_11,
|
||||
10'b1111_1111_11,
|
||||
10'b1111_1111_11,
|
||||
10'b1110_0111_11,
|
||||
10'b1110_1011_11,
|
||||
10'b1111_0111_11,
|
||||
10'b1111_1011_11,
|
||||
10'b1111_1011_11,
|
||||
10'b1110_1101_11,
|
||||
10'b1111_1101_11,
|
||||
10'b1111_1101_11,
|
||||
10'b1111_0011_11,
|
||||
10'b1111_0011_11,
|
||||
10'b1111_0011_11,
|
||||
10'b1110_0101_11,
|
||||
10'b1110_0101_11,
|
||||
10'b1110_0101_11,
|
||||
10'b1111_0101_11,
|
||||
10'b1111_0101_11,
|
||||
10'b1111_0101_11,
|
||||
10'b1111_1001_11,
|
||||
10'b1111_1001_11,
|
||||
10'b1111_1001_11,
|
||||
10'b1111_1001_11,
|
||||
10'b1111_1001_11,
|
||||
10'b1110_1110_11,
|
||||
10'b1110_1110_11,
|
||||
10'b1110_1110_11,
|
||||
10'b1110_1110_11,
|
||||
10'b1111_1110_11,
|
||||
10'b1111_1110_11,
|
||||
10'b1111_1110_11,
|
||||
10'b1111_1110_11,
|
||||
10'b1111_1110_11,
|
||||
10'b1111_1110_11,
|
||||
10'b1111_1110_11,
|
||||
10'b1110_0001_11,
|
||||
10'b1110_0001_11,
|
||||
10'b1110_0001_11,
|
||||
10'b1110_0001_11,
|
||||
10'b1110_0001_11,
|
||||
10'b1100_0110_11,
|
||||
10'b1100_0110_11,
|
||||
10'b1100_0110_11,
|
||||
10'b1100_0110_11,
|
||||
10'b1100_0110_11,
|
||||
10'b1100_0110_11,
|
||||
10'b1100_0110_11,
|
||||
10'b1100_1010_11,
|
||||
10'b1100_1010_11,
|
||||
10'b1100_1010_11,
|
||||
10'b1100_1010_11
|
||||
};
|
||||
|
||||
// Set lookup_entry with the explicit bits from lookup with a part select
|
||||
if(BANDWIDTH == "LOW") begin
|
||||
// Low Bandwidth
|
||||
mmcm_pll_filter_lookup = lookup_low[ ((64-divide)*10) +: 10];
|
||||
end else begin
|
||||
// High or optimized bandwidth
|
||||
mmcm_pll_filter_lookup = lookup_high[ ((64-divide)*10) +: 10];
|
||||
end
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("filter_lookup: %b", mmcm_pll_filter_lookup);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes in the divide, phase, and duty cycle
|
||||
// setting to calculate the upper and lower counter registers.
|
||||
function [37:0] mmcm_pll_count_calc
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input signed [31:0] phase,
|
||||
input [31:0] duty_cycle // Multiplied by 100,000
|
||||
);
|
||||
|
||||
reg [13:0] div_calc;
|
||||
reg [16:0] phase_calc;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_pll_count_calc- divide:%h, phase:%d, duty_cycle:%d",
|
||||
divide, phase, duty_cycle);
|
||||
`endif
|
||||
|
||||
// w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
|
||||
div_calc = mmcm_pll_divider(divide, duty_cycle);
|
||||
// mx[10:9], pm[8:6], dt[5:0]
|
||||
phase_calc = mmcm_pll_phase(divide, phase);
|
||||
|
||||
// Return value is the upper and lower address of counter
|
||||
// Upper address is:
|
||||
// RESERVED [31:26]
|
||||
// MX [25:24]
|
||||
// EDGE [23]
|
||||
// NOCOUNT [22]
|
||||
// DELAY_TIME [21:16]
|
||||
// Lower Address is:
|
||||
// PHASE_MUX [15:13]
|
||||
// RESERVED [12]
|
||||
// HIGH_TIME [11:6]
|
||||
// LOW_TIME [5:0]
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
|
||||
divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
|
||||
div_calc[13], div_calc[12],
|
||||
phase_calc[16:15], phase_calc[5:0], phase_calc[14:12]);
|
||||
`endif
|
||||
|
||||
mmcm_pll_count_calc =
|
||||
{
|
||||
// Upper Address
|
||||
6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
|
||||
// Lower Address
|
||||
phase_calc[8:6], 1'b0, div_calc[11:0]
|
||||
};
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
// This function takes in the divide, phase, and duty cycle
|
||||
// setting to calculate the upper and lower counter registers.
|
||||
// for fractional multiply/divide functions.
|
||||
//
|
||||
//
|
||||
function [37:0] mmcm_frac_count_calc
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input signed [31:0] phase,
|
||||
input [31:0] duty_cycle, // Multiplied by 1,000
|
||||
input [9:0] frac // Multiplied by 1000
|
||||
);
|
||||
|
||||
//Required for fractional divide calculations
|
||||
reg [7:0] lt_frac;
|
||||
reg [7:0] ht_frac;
|
||||
|
||||
reg /*[7:0]*/ wf_fall_frac;
|
||||
reg /*[7:0]*/ wf_rise_frac;
|
||||
|
||||
reg [31:0] a;
|
||||
reg [7:0] pm_rise_frac_filtered ;
|
||||
reg [7:0] pm_fall_frac_filtered ;
|
||||
reg [7:0] clkout0_divide_int;
|
||||
reg [2:0] clkout0_divide_frac;
|
||||
reg [7:0] even_part_high;
|
||||
reg [7:0] even_part_low;
|
||||
|
||||
reg [7:0] odd;
|
||||
reg [7:0] odd_and_frac;
|
||||
|
||||
reg [7:0] pm_fall;
|
||||
reg [7:0] pm_rise;
|
||||
reg [7:0] dt;
|
||||
reg [7:0] dt_int;
|
||||
reg [63:0] dt_calc;
|
||||
|
||||
reg [7:0] pm_rise_frac;
|
||||
reg [7:0] pm_fall_frac;
|
||||
|
||||
reg [31:0] a_per_in_octets;
|
||||
reg [31:0] a_phase_in_cycles;
|
||||
|
||||
parameter precision = 0.125;
|
||||
|
||||
reg [31:0] phase_fixed; // changed to 31:0 from 32:1 jt 5/2/11
|
||||
reg [31: 0] phase_pos;
|
||||
reg [31: 0] phase_vco;
|
||||
reg [31:0] temp;// changed to 31:0 from 32:1 jt 5/2/11
|
||||
reg [13:0] div_calc;
|
||||
reg [16:0] phase_calc;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_frac_count_calc- divide:%h, phase:%d, duty_cycle:%d",
|
||||
divide, phase, duty_cycle);
|
||||
`endif
|
||||
|
||||
//convert phase to fixed
|
||||
if ((phase < -360000) || (phase > 360000)) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: phase of $phase is not between -360000 and 360000");
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
|
||||
// Return value is
|
||||
// Transfer data
|
||||
// RESERVED [37:36]
|
||||
// FRAC_TIME [35:33]
|
||||
// FRAC_WF_FALL [32]
|
||||
// Upper address is:
|
||||
// RESERVED [31:26]
|
||||
// MX [25:24]
|
||||
// EDGE [23]
|
||||
// NOCOUNT [22]
|
||||
// DELAY_TIME [21:16]
|
||||
// Lower Address is:
|
||||
// PHASE_MUX [15:13]
|
||||
// RESERVED [12]
|
||||
// HIGH_TIME [11:6]
|
||||
// LOW_TIME [5:0]
|
||||
|
||||
|
||||
|
||||
clkout0_divide_frac = frac / 125;
|
||||
clkout0_divide_int = divide;
|
||||
|
||||
even_part_high = clkout0_divide_int >> 1;//$rtoi(clkout0_divide_int / 2);
|
||||
even_part_low = even_part_high;
|
||||
|
||||
odd = clkout0_divide_int - even_part_high - even_part_low;
|
||||
odd_and_frac = (8*odd) + clkout0_divide_frac;
|
||||
|
||||
lt_frac = even_part_high - (odd_and_frac <= 9);//IF(odd_and_frac>9,even_part_high, even_part_high - 1)
|
||||
ht_frac = even_part_low - (odd_and_frac <= 8);//IF(odd_and_frac>8,even_part_low, even_part_low- 1)
|
||||
|
||||
pm_fall = {odd[6:0],2'b00} + {6'h00, clkout0_divide_frac[2:1]}; // using >> instead of clkout0_divide_frac / 2
|
||||
pm_rise = 0; //0
|
||||
|
||||
wf_fall_frac = ((odd_and_frac >=2) && (odd_and_frac <=9)) || ((clkout0_divide_frac == 1) && (clkout0_divide_int == 2));//CRS610807
|
||||
wf_rise_frac = (odd_and_frac >=1) && (odd_and_frac <=8);//IF(odd_and_frac>=1,IF(odd_and_frac <= 8,1,0),0)
|
||||
|
||||
|
||||
|
||||
//Calculate phase in fractional cycles
|
||||
a_per_in_octets = (8 * divide) + (frac / 125) ;
|
||||
a_phase_in_cycles = (phase+10) * a_per_in_octets / 360000 ;//Adding 1 due to rounding errors
|
||||
pm_rise_frac = (a_phase_in_cycles[7:0] ==8'h00)?8'h00:a_phase_in_cycles[7:0] - {a_phase_in_cycles[7:3],3'b000};
|
||||
|
||||
dt_calc = ((phase+10) * a_per_in_octets / 8 )/360000 ;//TRUNC(phase* divide / 360); //or_simply (a_per_in_octets / 8)
|
||||
dt = dt_calc[7:0];
|
||||
|
||||
pm_rise_frac_filtered = (pm_rise_frac >=8) ? (pm_rise_frac ) - 8: pm_rise_frac ; //((phase_fixed * (divide + frac / 1000)) / 360) - {pm_rise_frac[7:3],3'b000};//$rtoi(clkout0_phase * clkout0_divide / 45);//a;
|
||||
|
||||
dt_int = dt + (& pm_rise_frac[7:4]); //IF(pm_rise_overwriting>7,dt+1,dt)
|
||||
pm_fall_frac = pm_fall + pm_rise_frac;
|
||||
pm_fall_frac_filtered = pm_fall + pm_rise_frac - {pm_fall_frac[7:3], 3'b000};
|
||||
|
||||
div_calc = mmcm_pll_divider(divide, duty_cycle); //Use to determine edge[7], no count[6]
|
||||
phase_calc = mmcm_pll_phase(divide, phase);// returns{mx[1:0], phase_mux[2:0], delay_time[5:0]}
|
||||
|
||||
mmcm_frac_count_calc[37:0] =
|
||||
{ 2'b00, pm_fall_frac_filtered[2:0], wf_fall_frac,
|
||||
1'b0, clkout0_divide_frac[2:0], 1'b1, wf_rise_frac, phase_calc[10:9], div_calc[13:12], dt[5:0],
|
||||
pm_rise_frac_filtered[2], pm_rise_frac_filtered[1], pm_rise_frac_filtered[0], 1'b0, ht_frac[5:0], lt_frac[5:0]
|
||||
} ;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("-%d.%d p%d>> :DADDR_9_15 frac30to28.frac_en.wf_r_frac.dt:%b%d%d_%b:DADDR_7_13 pm_f_frac_filtered_29to27.wf_f_frac_26:%b%d:DADDR_8_14.pm_r_frac_filt_15to13.ht_frac.lt_frac:%b%b%b:", divide, frac, phase, clkout0_divide_frac, 1, wf_rise_frac, dt, pm_fall_frac_filtered, wf_fall_frac, pm_rise_frac_filtered, ht_frac, lt_frac);
|
||||
`endif
|
||||
|
||||
end
|
||||
endfunction
|
||||
|
||||
+530
@@ -0,0 +1,530 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Company: Xilinx
|
||||
// Engineer: Jim Tatsukawa
|
||||
// Date: 6/15/2015
|
||||
// Design Name: PLLE3 DRP
|
||||
// Module Name: plle3_drp_func.h
|
||||
// Version: 1.10
|
||||
// Target Devices: UltraScale Architecture
|
||||
// Tool versions: 2015.1
|
||||
// Description: This header provides the functions necessary to
|
||||
// calculate the DRP register values for the V6 PLL.
|
||||
//
|
||||
// Revision Notes: 8/11 - PLLE3 updated for PLLE3 file 4564419
|
||||
// Revision Notes: 6/15 - pll_filter_lookup fixed for max M of 19
|
||||
// PM_Rise bits have been removed for PLLE3
|
||||
//
|
||||
// Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
|
||||
// INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
|
||||
// PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
|
||||
// PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
// ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
||||
// APPLICATION OR STANDARD, XILINX IS MAKING NO
|
||||
// REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
|
||||
// FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
|
||||
// RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
|
||||
// REQUIRE FOR YOUR IMPLEMENTATION. XILINX
|
||||
// EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
|
||||
// RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
|
||||
// INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
||||
// REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
|
||||
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE.
|
||||
//
|
||||
// (c) Copyright 2009-2010 Xilinx, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// These are user functions that should not be modified. Changes to the defines
|
||||
// or code within the functions may alter the accuracy of the calculations.
|
||||
|
||||
// Define debug to provide extra messages durring elaboration
|
||||
//`define DEBUG 1
|
||||
|
||||
// FRAC_PRECISION describes the width of the fractional portion of the fixed
|
||||
// point numbers. These should not be modified, they are for development
|
||||
// only
|
||||
`define FRAC_PRECISION 10
|
||||
// FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
|
||||
// Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
|
||||
// greater than 32
|
||||
`define FIXED_WIDTH 32
|
||||
|
||||
// This function takes a fixed point number and rounds it to the nearest
|
||||
// fractional precision bit.
|
||||
function [`FIXED_WIDTH:1] round_frac
|
||||
(
|
||||
// Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
|
||||
input [`FIXED_WIDTH:1] decimal,
|
||||
|
||||
// This describes the precision of the fraction, for example a value
|
||||
// of 1 would modify the fractional so that instead of being a .16
|
||||
// fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
|
||||
input [`FIXED_WIDTH:1] precision
|
||||
);
|
||||
|
||||
begin
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("round_frac - decimal: %h, precision: %h", decimal, precision);
|
||||
`endif
|
||||
// If the fractional precision bit is high then round up
|
||||
if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
|
||||
round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
|
||||
end else begin
|
||||
round_frac = decimal;
|
||||
end
|
||||
`ifdef DEBUG
|
||||
$display("round_frac: %h", round_frac);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function calculates high_time, low_time, w_edge, and no_count
|
||||
// of a non-fractional counter based on the divide and duty cycle
|
||||
//
|
||||
// NOTE: high_time and low_time are returned as integers between 0 and 63
|
||||
// inclusive. 64 should equal 6'b000000 (in other words it is okay to
|
||||
// ignore the overflow)
|
||||
function [13:0] mmcm_pll_divider
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
|
||||
);
|
||||
|
||||
reg [`FIXED_WIDTH:1] duty_cycle_fix;
|
||||
|
||||
// High/Low time is initially calculated with a wider integer to prevent a
|
||||
// calculation error when it overflows to 64.
|
||||
reg [6:0] high_time;
|
||||
reg [6:0] low_time;
|
||||
reg w_edge;
|
||||
reg no_count;
|
||||
|
||||
reg [`FIXED_WIDTH:1] temp;
|
||||
|
||||
begin
|
||||
// Duty Cycle must be between 0 and 1,000
|
||||
if(duty_cycle <=0 || duty_cycle >= 100000) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: duty_cycle: %d is invalid", duty_cycle);
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
// Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
|
||||
duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("duty_cycle_fix: %h", duty_cycle_fix);
|
||||
`endif
|
||||
|
||||
// If the divide is 1 nothing needs to be set except the no_count bit.
|
||||
// Other values are dummies
|
||||
if(divide == 7'h01) begin
|
||||
high_time = 7'h01;
|
||||
w_edge = 1'b0;
|
||||
low_time = 7'h01;
|
||||
no_count = 1'b1;
|
||||
end else begin
|
||||
temp = round_frac(duty_cycle_fix*divide, 1);
|
||||
|
||||
// comes from above round_frac
|
||||
high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
|
||||
// If the duty cycle * divide rounded is .5 or greater then this bit
|
||||
// is set.
|
||||
w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
|
||||
|
||||
// If the high time comes out to 0, it needs to be set to at least 1
|
||||
// and w_edge set to 0
|
||||
if(high_time == 7'h00) begin
|
||||
high_time = 7'h01;
|
||||
w_edge = 1'b0;
|
||||
end
|
||||
|
||||
if(high_time == divide) begin
|
||||
high_time = divide - 1;
|
||||
w_edge = 1'b1;
|
||||
end
|
||||
|
||||
// Calculate low_time based on the divide setting and set no_count to
|
||||
// 0 as it is only used when divide is 1.
|
||||
low_time = divide - high_time;
|
||||
no_count = 1'b0;
|
||||
end
|
||||
|
||||
// Set the return value.
|
||||
mmcm_pll_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function calculates mx, delay_time, and phase_mux
|
||||
// of a non-fractional counter based on the divide and phase
|
||||
//
|
||||
// NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
|
||||
// is used.
|
||||
function [10:0] mmcm_pll_phase
|
||||
(
|
||||
// divide must be an integer (use fractional if not)
|
||||
// assumed that divide already checked to be valid
|
||||
input [7:0] divide, // Max divide is 128
|
||||
|
||||
// Phase is given in degrees (-360,000 to 360,000)
|
||||
input signed [31:0] phase
|
||||
);
|
||||
|
||||
reg [`FIXED_WIDTH:1] phase_in_cycles;
|
||||
reg [`FIXED_WIDTH:1] phase_fixed;
|
||||
reg [1:0] mx;
|
||||
reg [5:0] delay_time;
|
||||
reg [2:0] phase_mux;
|
||||
|
||||
reg [`FIXED_WIDTH:1] temp;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_pll_phase-divide:%d,phase:%d",
|
||||
divide, phase);
|
||||
`endif
|
||||
|
||||
if ((phase < -360000) || (phase > 360000)) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: phase of $phase is not between -360000 and 360000");
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
// If phase is less than 0, convert it to a positive phase shift
|
||||
// Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
|
||||
if(phase < 0) begin
|
||||
phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
|
||||
end else begin
|
||||
phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
|
||||
end
|
||||
|
||||
// Put phase in terms of decimal number of vco clock cycles
|
||||
phase_in_cycles = ( phase_fixed * divide ) / 360;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("phase_in_cycles: %h", phase_in_cycles);
|
||||
`endif
|
||||
|
||||
|
||||
temp = round_frac(phase_in_cycles, 3);
|
||||
|
||||
// set mx to 2'b00 that the phase mux from the VCO is enabled
|
||||
mx = 2'b00;
|
||||
phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
|
||||
delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("temp: %h", temp);
|
||||
`endif
|
||||
|
||||
// Setup the return value
|
||||
mmcm_pll_phase={mx, phase_mux, delay_time};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes the divide value and outputs the necessary lock values
|
||||
function [39:0] mmcm_pll_lock_lookup
|
||||
(
|
||||
input [6:0] divide // Max divide is 64
|
||||
);
|
||||
|
||||
reg [759:0] lookup;
|
||||
|
||||
begin
|
||||
lookup = {
|
||||
// This table is composed of:
|
||||
// LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
|
||||
40'b00110_00110_1111101000_1111101001_0000000001, //1
|
||||
40'b00110_00110_1111101000_1111101001_0000000001, //2
|
||||
40'b01000_01000_1111101000_1111101001_0000000001, //3
|
||||
40'b01011_01011_1111101000_1111101001_0000000001, //4
|
||||
40'b01110_01110_1111101000_1111101001_0000000001, //5
|
||||
40'b10001_10001_1111101000_1111101001_0000000001, //6
|
||||
40'b10011_10011_1111101000_1111101001_0000000001, //7
|
||||
40'b10110_10110_1111101000_1111101001_0000000001, //8
|
||||
40'b11001_11001_1111101000_1111101001_0000000001, //9
|
||||
40'b11100_11100_1111101000_1111101001_0000000001, //10
|
||||
40'b11111_11111_1110000100_1111101001_0000000001, //11
|
||||
40'b11111_11111_1100111001_1111101001_0000000001, //12
|
||||
40'b11111_11111_1011101110_1111101001_0000000001, //13
|
||||
40'b11111_11111_1010111100_1111101001_0000000001, //14
|
||||
40'b11111_11111_1010001010_1111101001_0000000001, //15
|
||||
40'b11111_11111_1001110001_1111101001_0000000001, //16
|
||||
40'b11111_11111_1000111111_1111101001_0000000001, //17
|
||||
40'b11111_11111_1000100110_1111101001_0000000001, //18
|
||||
40'b11111_11111_1000001101_1111101001_0000000001 //19
|
||||
|
||||
};
|
||||
|
||||
// Set lookup_entry with the explicit bits from lookup with a part select
|
||||
mmcm_pll_lock_lookup = lookup[ ((19-divide)*40) +: 40];
|
||||
`ifdef DEBUG
|
||||
$display("lock_lookup: %b", mmcm_pll_lock_lookup);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes the divide value and the bandwidth setting of the PLL
|
||||
// and outputs the digital filter settings necessary. Removing bandwidth setting for PLLE3.
|
||||
function [9:0] mmcm_pll_filter_lookup
|
||||
(
|
||||
input [6:0] divide // Max divide is 19
|
||||
);
|
||||
|
||||
reg [639:0] lookup;
|
||||
reg [9:0] lookup_entry;
|
||||
|
||||
begin
|
||||
|
||||
lookup = {
|
||||
// CP_RES_LFHF
|
||||
10'b0010_1111_01, //1
|
||||
10'b0010_0011_11, //2
|
||||
10'b0011_0011_11, //3
|
||||
10'b0010_0001_11, //4
|
||||
10'b0010_0110_11, //5
|
||||
10'b0010_1010_11, //6
|
||||
10'b0010_1010_11, //7
|
||||
10'b0011_0110_11, //8
|
||||
10'b0010_1100_11, //9
|
||||
10'b0010_1100_11, //10
|
||||
10'b0010_1100_11, //11
|
||||
10'b0010_0010_11, //12
|
||||
10'b0011_1100_11, //13
|
||||
10'b0011_1100_11, //14
|
||||
10'b0011_1100_11, //15
|
||||
10'b0011_1100_11, //16
|
||||
10'b0011_0010_11, //17
|
||||
10'b0011_0010_11, //18
|
||||
10'b0011_0010_11 //19
|
||||
};
|
||||
|
||||
mmcm_pll_filter_lookup = lookup [ ((19-divide)*10) +: 10];
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("filter_lookup: %b", mmcm_pll_filter_lookup);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function set the CLKOUTPHY divide settings to match
|
||||
// the desired CLKOUTPHY_MODE setting. To create VCO_X2, then
|
||||
// the CLKOUTPHY will be set to 2'b00 since the VCO is internally
|
||||
// doubled and 2'b00 will represent divide by 1. Similarly "VCO" // will need to divide the doubled clock VCO clock frequency by // 2 therefore 2'b01 will match a divide by 2.And VCO_HALF will // need to divide the doubled VCO by 4, therefore 2'b10
|
||||
function [9:0] mmcm_pll_clkoutphy_calc
|
||||
(
|
||||
input [8*9:0] CLKOUTPHY_MODE
|
||||
);
|
||||
|
||||
if(CLKOUTPHY_MODE == "VCO_X2") begin
|
||||
mmcm_pll_clkoutphy_calc= 2'b00;
|
||||
end else if(CLKOUTPHY_MODE == "VCO") begin
|
||||
mmcm_pll_clkoutphy_calc= 2'b01;
|
||||
end else if(CLKOUTPHY_MODE == "CLKIN") begin
|
||||
mmcm_pll_clkoutphy_calc= 2'b11;
|
||||
end else begin // Assume "VCO_HALF"
|
||||
mmcm_pll_clkoutphy_calc= 2'b10;
|
||||
end
|
||||
|
||||
endfunction
|
||||
|
||||
|
||||
// This function takes in the divide, phase, and duty cycle
|
||||
// setting to calculate the upper and lower counter registers.
|
||||
function [37:0] mmcm_pll_count_calc
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input signed [31:0] phase,
|
||||
input [31:0] duty_cycle // Multiplied by 100,000
|
||||
);
|
||||
|
||||
reg [13:0] div_calc;
|
||||
reg [16:0] phase_calc;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_pll_count_calc- divide:%h, phase:%d, duty_cycle:%d",
|
||||
divide, phase, duty_cycle);
|
||||
`endif
|
||||
|
||||
// w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
|
||||
div_calc = mmcm_pll_divider(divide, duty_cycle);
|
||||
// mx[10:9], pm[8:6], dt[5:0]
|
||||
phase_calc = mmcm_pll_phase(divide, phase);
|
||||
|
||||
// Return value is the upper and lower address of counter
|
||||
// Upper address is:
|
||||
// RESERVED [31:26]
|
||||
// MX [25:24]
|
||||
// EDGE [23]
|
||||
// NOCOUNT [22]
|
||||
// DELAY_TIME [21:16]
|
||||
// Lower Address is:
|
||||
// PHASE_MUX [15:13]
|
||||
// RESERVED [12]
|
||||
// HIGH_TIME [11:6]
|
||||
// LOW_TIME [5:0]
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
|
||||
divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
|
||||
div_calc[13], div_calc[12],
|
||||
phase_calc[16:15], phase_calc[5:0], 3'b000);//Removed PM_Rise bits
|
||||
`endif
|
||||
|
||||
mmcm_pll_count_calc =
|
||||
{
|
||||
// Upper Address
|
||||
6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
|
||||
// Lower Address
|
||||
phase_calc[8:6], 1'b0, div_calc[11:0]
|
||||
};
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
// This function takes in the divide, phase, and duty cycle
|
||||
// setting to calculate the upper and lower counter registers.
|
||||
// for fractional multiply/divide functions.
|
||||
//
|
||||
//
|
||||
function [37:0] mmcm_pll_frac_count_calc
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input signed [31:0] phase,
|
||||
input [31:0] duty_cycle, // Multiplied by 1,000
|
||||
input [9:0] frac // Multiplied by 1000
|
||||
);
|
||||
|
||||
//Required for fractional divide calculations
|
||||
reg [7:0] lt_frac;
|
||||
reg [7:0] ht_frac;
|
||||
|
||||
reg /*[7:0]*/ wf_fall_frac;
|
||||
reg /*[7:0]*/ wf_rise_frac;
|
||||
|
||||
reg [31:0] a;
|
||||
reg [7:0] pm_rise_frac_filtered ;
|
||||
reg [7:0] pm_fall_frac_filtered ;
|
||||
reg [7:0] clkout0_divide_int;
|
||||
reg [2:0] clkout0_divide_frac;
|
||||
reg [7:0] even_part_high;
|
||||
reg [7:0] even_part_low;
|
||||
|
||||
reg [7:0] odd;
|
||||
reg [7:0] odd_and_frac;
|
||||
|
||||
reg [7:0] pm_fall;
|
||||
reg [7:0] pm_rise;
|
||||
reg [7:0] dt;
|
||||
reg [7:0] dt_int;
|
||||
reg [63:0] dt_calc;
|
||||
|
||||
reg [7:0] pm_rise_frac;
|
||||
reg [7:0] pm_fall_frac;
|
||||
|
||||
reg [31:0] a_per_in_octets;
|
||||
reg [31:0] a_phase_in_cycles;
|
||||
|
||||
parameter precision = 0.125;
|
||||
|
||||
reg [31:0] phase_fixed; // changed to 31:0 from 32:1 jt 5/2/11
|
||||
reg [31: 0] phase_pos;
|
||||
reg [31: 0] phase_vco;
|
||||
reg [31:0] temp;// changed to 31:0 from 32:1 jt 5/2/11
|
||||
reg [13:0] div_calc;
|
||||
reg [16:0] phase_calc;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_pll_frac_count_calc- divide:%h, phase:%d, duty_cycle:%d",
|
||||
divide, phase, duty_cycle);
|
||||
`endif
|
||||
|
||||
//convert phase to fixed
|
||||
if ((phase < -360000) || (phase > 360000)) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: phase of $phase is not between -360000 and 360000");
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
|
||||
// Return value is
|
||||
// Transfer data
|
||||
// RESERVED [37:36]
|
||||
// FRAC_TIME [35:33]
|
||||
// FRAC_WF_FALL [32]
|
||||
// Upper address is:
|
||||
// RESERVED [31:26]
|
||||
// MX [25:24]
|
||||
// EDGE [23]
|
||||
// NOCOUNT [22]
|
||||
// DELAY_TIME [21:16]
|
||||
// Lower Address is:
|
||||
// PHASE_MUX [15:13]
|
||||
// RESERVED [12]
|
||||
// HIGH_TIME [11:6]
|
||||
// LOW_TIME [5:0]
|
||||
|
||||
|
||||
|
||||
clkout0_divide_frac = frac / 125;
|
||||
clkout0_divide_int = divide;
|
||||
|
||||
even_part_high = clkout0_divide_int >> 1;//$rtoi(clkout0_divide_int / 2);
|
||||
even_part_low = even_part_high;
|
||||
|
||||
odd = clkout0_divide_int - even_part_high - even_part_low;
|
||||
odd_and_frac = (8*odd) + clkout0_divide_frac;
|
||||
|
||||
lt_frac = even_part_high - (odd_and_frac <= 9);//IF(odd_and_frac>9,even_part_high, even_part_high - 1)
|
||||
ht_frac = even_part_low - (odd_and_frac <= 8);//IF(odd_and_frac>8,even_part_low, even_part_low- 1)
|
||||
|
||||
pm_fall = {odd[6:0],2'b00} + {6'h00, clkout0_divide_frac[2:1]}; // using >> instead of clkout0_divide_frac / 2
|
||||
pm_rise = 0; //0
|
||||
|
||||
wf_fall_frac = (odd_and_frac >=2) && (odd_and_frac <=9);//IF(odd_and_frac>=2,IF(odd_and_frac <= 9,1,0),0)
|
||||
wf_rise_frac = (odd_and_frac >=1) && (odd_and_frac <=8);//IF(odd_and_frac>=1,IF(odd_and_frac <= 8,1,0),0)
|
||||
|
||||
|
||||
|
||||
//Calculate phase in fractional cycles
|
||||
a_per_in_octets = (8 * divide) + (frac / 125) ;
|
||||
a_phase_in_cycles = (phase+10) * a_per_in_octets / 360000 ;//Adding 1 due to rounding errors
|
||||
pm_rise_frac = (a_phase_in_cycles[7:0] ==8'h00)?8'h00:a_phase_in_cycles[7:0] - {a_phase_in_cycles[7:3],3'b000};
|
||||
|
||||
dt_calc = ((phase+10) * a_per_in_octets / 8 )/360000 ;//TRUNC(phase* divide / 360); //or_simply (a_per_in_octets / 8)
|
||||
dt = dt_calc[7:0];
|
||||
|
||||
pm_rise_frac_filtered = (pm_rise_frac >=8) ? (pm_rise_frac ) - 8: pm_rise_frac ; //((phase_fixed * (divide + frac / 1000)) / 360) - {pm_rise_frac[7:3],3'b000};//$rtoi(clkout0_phase * clkout0_divide / 45);//a;
|
||||
|
||||
dt_int = dt + (& pm_rise_frac[7:4]); //IF(pm_rise_overwriting>7,dt+1,dt)
|
||||
pm_fall_frac = pm_fall + pm_rise_frac;
|
||||
pm_fall_frac_filtered = pm_fall + pm_rise_frac - {pm_fall_frac[7:3], 3'b000};
|
||||
|
||||
div_calc = mmcm_pll_divider(divide, duty_cycle); //Use to determine edge[7], no count[6]
|
||||
phase_calc = mmcm_pll_phase(divide, phase);// returns{mx[1:0], phase_mux[2:0], delay_time[5:0]}
|
||||
|
||||
mmcm_pll_frac_count_calc[37:0] =
|
||||
{ 2'b00, pm_fall_frac_filtered[2:0], wf_fall_frac,
|
||||
1'b0, clkout0_divide_frac[2:0], 1'b1, wf_rise_frac, phase_calc[10:9], div_calc[13:12], dt[5:0],
|
||||
3'b000, 1'b0, ht_frac[5:0], lt_frac[5:0] //Removed PM_Rise bits
|
||||
// pm_rise_frac_filtered[2], pm_rise_frac_filtered[1], pm_rise_frac_filtered[0], 1'b0, ht_frac[5:0], lt_frac[5:0]
|
||||
} ;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("-%d.%d p%d>> :DADDR_9_15 frac30to28.frac_en.wf_r_frac.dt:%b%d%d_%b:DADDR_7_13 pm_f_frac_filtered_29to27.wf_f_frac_26:%b%d:DADDR_8_14.pm_r_frac_filt_15to13.ht_frac.lt_frac:%b%b%b:", divide, frac, phase, clkout0_divide_frac, 1, wf_rise_frac, dt, pm_fall_frac_filtered, wf_fall_frac, 3'b000, ht_frac, lt_frac);
|
||||
`endif
|
||||
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
+861
@@ -0,0 +1,861 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Company: Xilinx
|
||||
// Engineer: Jim Tatsukawa. Updated by Ralf Krueger
|
||||
// Date: 7/30/2014
|
||||
// Design Name: MMCME4 DRP
|
||||
// Module Name: mmcme4_drp_func.h
|
||||
// Version: 1.31
|
||||
// Target Devices: UltraScale Plus Architecture
|
||||
// Tool versions: 2017.1
|
||||
// Description: This header provides the functions necessary to
|
||||
// calculate the DRP register values for UltraScal+ MMCM.
|
||||
//
|
||||
// Revision Notes: 3/22 - Updating lookup_low/lookup_high (CR)
|
||||
// 4/13 - Fractional divide function in mmcm_frac_count_calc function
|
||||
// 2/28/17 - Updated for Ultrascale Plus
|
||||
//
|
||||
// Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
|
||||
// INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
|
||||
// PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
|
||||
// PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
// ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
||||
// APPLICATION OR STANDARD, XILINX IS MAKING NO
|
||||
// REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
|
||||
// FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
|
||||
// RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
|
||||
// REQUIRE FOR YOUR IMPLEMENTATION. XILINX
|
||||
// EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
|
||||
// RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
|
||||
// INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
||||
// REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
|
||||
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE.
|
||||
//
|
||||
// (c) Copyright 2009-2017 Xilinx, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// These are user functions that should not be modified. Changes to the defines
|
||||
// or code within the functions may alter the accuracy of the calculations.
|
||||
|
||||
// Define debug to provide extra messages during elaboration
|
||||
//`define DEBUG 1
|
||||
|
||||
// FRAC_PRECISION describes the width of the fractional portion of the fixed
|
||||
// point numbers. These should not be modified, they are for development only
|
||||
`define FRAC_PRECISION 10
|
||||
// FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
|
||||
// Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
|
||||
// greater than 32
|
||||
`define FIXED_WIDTH 32
|
||||
|
||||
// This function takes a fixed point number and rounds it to the nearest
|
||||
// fractional precision bit.
|
||||
function [`FIXED_WIDTH:1] round_frac
|
||||
(
|
||||
// Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
|
||||
input [`FIXED_WIDTH:1] decimal,
|
||||
|
||||
// This describes the precision of the fraction, for example a value
|
||||
// of 1 would modify the fractional so that instead of being a .16
|
||||
// fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
|
||||
input [`FIXED_WIDTH:1] precision
|
||||
);
|
||||
|
||||
begin
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("round_frac - decimal: %h, precision: %h", decimal, precision);
|
||||
`endif
|
||||
// If the fractional precision bit is high then round up
|
||||
if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
|
||||
round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
|
||||
end else begin
|
||||
round_frac = decimal;
|
||||
end
|
||||
`ifdef DEBUG
|
||||
$display("round_frac: %h", round_frac);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function calculates high_time, low_time, w_edge, and no_count
|
||||
// of a non-fractional counter based on the divide and duty cycle
|
||||
//
|
||||
// NOTE: high_time and low_time are returned as integers between 0 and 63
|
||||
// inclusive. 64 should equal 6'b000000 (in other words it is okay to
|
||||
// ignore the overflow)
|
||||
function [13:0] mmcm_pll_divider
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
|
||||
);
|
||||
|
||||
reg [`FIXED_WIDTH:1] duty_cycle_fix;
|
||||
|
||||
// High/Low time is initially calculated with a wider integer to prevent a
|
||||
// calculation error when it overflows to 64.
|
||||
reg [6:0] high_time;
|
||||
reg [6:0] low_time;
|
||||
reg w_edge;
|
||||
reg no_count;
|
||||
|
||||
reg [`FIXED_WIDTH:1] temp;
|
||||
|
||||
begin
|
||||
// Duty Cycle must be between 0 and 1,000
|
||||
if(duty_cycle <=0 || duty_cycle >= 100000) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: duty_cycle: %d is invalid", duty_cycle);
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
// Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
|
||||
duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("duty_cycle_fix: %h", duty_cycle_fix);
|
||||
`endif
|
||||
|
||||
// If the divide is 1 nothing needs to be set except the no_count bit.
|
||||
// Other values are dummies
|
||||
if(divide == 7'h01) begin
|
||||
high_time = 7'h01;
|
||||
w_edge = 1'b0;
|
||||
low_time = 7'h01;
|
||||
no_count = 1'b1;
|
||||
end else begin
|
||||
temp = round_frac(duty_cycle_fix*divide, 1);
|
||||
|
||||
// comes from above round_frac
|
||||
high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
|
||||
// If the duty cycle * divide rounded is .5 or greater then this bit
|
||||
// is set.
|
||||
w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
|
||||
|
||||
// If the high time comes out to 0, it needs to be set to at least 1
|
||||
// and w_edge set to 0
|
||||
if(high_time == 7'h00) begin
|
||||
high_time = 7'h01;
|
||||
w_edge = 1'b0;
|
||||
end
|
||||
|
||||
if(high_time == divide) begin
|
||||
high_time = divide - 1;
|
||||
w_edge = 1'b1;
|
||||
end
|
||||
|
||||
// Calculate low_time based on the divide setting and set no_count to
|
||||
// 0 as it is only used when divide is 1.
|
||||
low_time = divide - high_time;
|
||||
no_count = 1'b0;
|
||||
end
|
||||
|
||||
// Set the return value.
|
||||
mmcm_pll_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function calculates mx, delay_time, and phase_mux
|
||||
// of a non-fractional counter based on the divide and phase
|
||||
//
|
||||
// NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
|
||||
// is used.
|
||||
function [10:0] mmcm_pll_phase
|
||||
(
|
||||
// divide must be an integer (use fractional if not)
|
||||
// assumed that divide already checked to be valid
|
||||
input [7:0] divide, // Max divide is 128
|
||||
|
||||
// Phase is given in degrees (-360,000 to 360,000)
|
||||
input signed [31:0] phase
|
||||
);
|
||||
|
||||
reg [`FIXED_WIDTH:1] phase_in_cycles;
|
||||
reg [`FIXED_WIDTH:1] phase_fixed;
|
||||
reg [1:0] mx;
|
||||
reg [5:0] delay_time;
|
||||
reg [2:0] phase_mux;
|
||||
|
||||
reg [`FIXED_WIDTH:1] temp;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_phase-divide:%d,phase:%d", divide, phase);
|
||||
`endif
|
||||
|
||||
if ((phase < -360000) || (phase > 360000)) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: phase of $phase is not between -360000 and 360000");
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
// If phase is less than 0, convert it to a positive phase shift
|
||||
// Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
|
||||
if(phase < 0) begin
|
||||
phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
|
||||
end else begin
|
||||
phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
|
||||
end
|
||||
|
||||
// Put phase in terms of decimal number of vco clock cycles
|
||||
phase_in_cycles = ( phase_fixed * divide ) / 360;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("phase_in_cycles: %h", phase_in_cycles);
|
||||
`endif
|
||||
|
||||
temp = round_frac(phase_in_cycles, 3);
|
||||
|
||||
// set mx to 2'b00 that the phase mux from the VCO is enabled
|
||||
mx = 2'b00;
|
||||
phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
|
||||
delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("temp: %h", temp);
|
||||
`endif
|
||||
|
||||
// Setup the return value
|
||||
mmcm_pll_phase={mx, phase_mux, delay_time};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes the divide value and outputs the necessary lock values
|
||||
function [39:0] mmcm_pll_lock_lookup
|
||||
(
|
||||
input [7:0] divide // Max M divide is 128 in UltrascalePlus
|
||||
);
|
||||
|
||||
reg [5119:0] lookup;
|
||||
|
||||
begin
|
||||
lookup = {
|
||||
// This table is composed of:
|
||||
// LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
|
||||
40'b00110_00110_1111101000_1111101001_0000000001, // M=1 (not allowed)
|
||||
40'b00110_00110_1111101000_1111101001_0000000001, // M=2
|
||||
40'b01000_01000_1111101000_1111101001_0000000001, // M=3
|
||||
40'b01011_01011_1111101000_1111101001_0000000001, // M=4
|
||||
40'b01110_01110_1111101000_1111101001_0000000001, // M=5
|
||||
40'b10001_10001_1111101000_1111101001_0000000001, // M=6
|
||||
40'b10011_10011_1111101000_1111101001_0000000001, // M=7
|
||||
40'b10110_10110_1111101000_1111101001_0000000001,
|
||||
40'b11001_11001_1111101000_1111101001_0000000001,
|
||||
40'b11100_11100_1111101000_1111101001_0000000001,
|
||||
40'b11111_11111_1110000100_1111101001_0000000001,
|
||||
40'b11111_11111_1100111001_1111101001_0000000001,
|
||||
40'b11111_11111_1011101110_1111101001_0000000001,
|
||||
40'b11111_11111_1010111100_1111101001_0000000001,
|
||||
40'b11111_11111_1010001010_1111101001_0000000001,
|
||||
40'b11111_11111_1001110001_1111101001_0000000001,
|
||||
40'b11111_11111_1000111111_1111101001_0000000001,
|
||||
40'b11111_11111_1000100110_1111101001_0000000001,
|
||||
40'b11111_11111_1000001101_1111101001_0000000001,
|
||||
40'b11111_11111_0111110100_1111101001_0000000001,
|
||||
40'b11111_11111_0111011011_1111101001_0000000001,
|
||||
40'b11111_11111_0111000010_1111101001_0000000001,
|
||||
40'b11111_11111_0110101001_1111101001_0000000001,
|
||||
40'b11111_11111_0110010000_1111101001_0000000001,
|
||||
40'b11111_11111_0110010000_1111101001_0000000001,
|
||||
40'b11111_11111_0101110111_1111101001_0000000001,
|
||||
40'b11111_11111_0101011110_1111101001_0000000001,
|
||||
40'b11111_11111_0101011110_1111101001_0000000001,
|
||||
40'b11111_11111_0101000101_1111101001_0000000001,
|
||||
40'b11111_11111_0101000101_1111101001_0000000001,
|
||||
40'b11111_11111_0100101100_1111101001_0000000001,
|
||||
40'b11111_11111_0100101100_1111101001_0000000001,
|
||||
40'b11111_11111_0100101100_1111101001_0000000001,
|
||||
40'b11111_11111_0100010011_1111101001_0000000001,
|
||||
40'b11111_11111_0100010011_1111101001_0000000001,
|
||||
40'b11111_11111_0100010011_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001,
|
||||
40'b11111_11111_0011111010_1111101001_0000000001, // M=127
|
||||
40'b11111_11111_0011111010_1111101001_0000000001 // M=128
|
||||
};
|
||||
|
||||
// Set lookup_entry with the explicit bits from lookup with a part select
|
||||
mmcm_pll_lock_lookup = lookup[ ((128-divide)*40) +: 40];
|
||||
`ifdef DEBUG
|
||||
$display("lock_lookup: %b", mmcm_pll_lock_lookup);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes the divide value and the bandwidth setting of the MMCM
|
||||
// and outputs the digital filter settings necessary.
|
||||
function [9:0] mmcm_pll_filter_lookup
|
||||
(
|
||||
input [7:0] divide, // input [7:0] divide // Max M divide is 128 in UltraScalePlus
|
||||
input [8*9:0] BANDWIDTH
|
||||
);
|
||||
|
||||
reg [1279:0] lookup_low;
|
||||
reg [1279:0] lookup_high;
|
||||
|
||||
reg [9:0] lookup_entry;
|
||||
|
||||
begin
|
||||
lookup_low = {
|
||||
// CP_RES_LFHF
|
||||
10'b0011_1111_11, // M=1 - not legal
|
||||
10'b0011_1111_11, // M=2
|
||||
10'b0011_1101_11, // M=3
|
||||
10'b0011_0101_11, // M=4
|
||||
10'b0011_1001_11, // M=5
|
||||
10'b0011_1110_11, // M=6
|
||||
10'b0011_1110_11, // M=7
|
||||
10'b0011_0001_11,
|
||||
10'b0011_0110_11,
|
||||
10'b0011_0110_11,
|
||||
10'b0011_0110_11,
|
||||
10'b0011_1010_11,
|
||||
10'b0011_1010_11,
|
||||
10'b0011_1010_11,
|
||||
10'b0100_0110_11,
|
||||
10'b0011_1100_11,
|
||||
10'b1110_0110_11,
|
||||
10'b1111_0110_11,
|
||||
10'b1110_1010_11,
|
||||
10'b1110_1010_11,
|
||||
10'b1111_1010_11,
|
||||
10'b1111_1010_11,
|
||||
10'b1111_1010_11,
|
||||
10'b1111_1010_11,
|
||||
10'b1111_1010_11,
|
||||
10'b1101_1100_11,
|
||||
10'b1101_1100_11,
|
||||
10'b1101_1100_11,
|
||||
10'b1110_1100_11,
|
||||
10'b1110_1100_11,
|
||||
10'b1110_1100_11,
|
||||
10'b1111_1100_11,
|
||||
10'b1111_1100_11,
|
||||
10'b1111_1100_11,
|
||||
10'b1111_1100_11,
|
||||
10'b1111_1100_11,
|
||||
10'b1111_1100_11,
|
||||
10'b1110_0010_11,
|
||||
10'b1110_0010_11,
|
||||
10'b1110_0010_11,
|
||||
10'b1110_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11, // M=127
|
||||
10'b1101_1000_11 // M=128
|
||||
};
|
||||
|
||||
lookup_high = {
|
||||
// CP_RES_LFHF
|
||||
10'b0111_1111_11, // M=1 - not legal
|
||||
10'b0111_1111_11, // M=2
|
||||
10'b1110_1111_11, // M=3
|
||||
10'b1111_1111_11, // M=4
|
||||
10'b1111_1011_11, // M=5
|
||||
10'b1111_1101_11, // M=6
|
||||
10'b1111_0011_11, // M=7
|
||||
10'b1110_0101_11,
|
||||
10'b1111_1001_11,
|
||||
10'b1111_1001_11,
|
||||
10'b1110_1110_11,
|
||||
10'b1111_1110_11,
|
||||
10'b1111_0001_11,
|
||||
10'b1111_0001_11,
|
||||
10'b1111_0001_11,
|
||||
10'b1110_0110_11,
|
||||
10'b1110_0110_11,
|
||||
10'b1111_0110_11,
|
||||
10'b1110_1010_11,
|
||||
10'b1110_1010_11,
|
||||
10'b1111_1010_11,
|
||||
10'b1111_1010_11,
|
||||
10'b1111_1010_11,
|
||||
10'b1111_1010_11,
|
||||
10'b1111_1010_11,
|
||||
10'b1101_1100_11,
|
||||
10'b1101_1100_11,
|
||||
10'b1101_1100_11,
|
||||
10'b1110_1100_11,
|
||||
10'b1110_1100_11,
|
||||
10'b1110_1100_11,
|
||||
10'b1111_1100_11,
|
||||
10'b1111_1100_11,
|
||||
10'b1111_1100_11,
|
||||
10'b1111_1100_11,
|
||||
10'b1111_1100_11,
|
||||
10'b1111_1100_11,
|
||||
10'b1110_0010_11,
|
||||
10'b1110_0010_11,
|
||||
10'b1110_0010_11,
|
||||
10'b1110_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1111_0010_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1100_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1101_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1110_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1111_0100_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11,
|
||||
10'b1101_1000_11 // M=128
|
||||
};
|
||||
|
||||
// Set lookup_entry with the explicit bits from lookup with a part select
|
||||
if(BANDWIDTH == "LOW") begin
|
||||
// Low Bandwidth
|
||||
mmcm_pll_filter_lookup = lookup_low[ ((128-divide)*10) +: 10];
|
||||
end else begin
|
||||
// High or optimized bandwidth
|
||||
mmcm_pll_filter_lookup = lookup_high[ ((128-divide)*10) +: 10];
|
||||
end
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("filter_lookup: %b", mmcm_pll_filter_lookup);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes in the divide, phase, and duty cycle
|
||||
// setting to calculate the upper and lower counter registers.
|
||||
function [37:0] mmcm_pll_count_calc
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input signed [31:0] phase,
|
||||
input [31:0] duty_cycle // Multiplied by 100,000
|
||||
);
|
||||
|
||||
reg [13:0] div_calc;
|
||||
reg [16:0] phase_calc;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_pll_count_calc- divide:%h, phase:%d, duty_cycle:%d",
|
||||
divide, phase, duty_cycle);
|
||||
`endif
|
||||
|
||||
// w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
|
||||
div_calc = mmcm_pll_divider(divide, duty_cycle);
|
||||
// mx[10:9], pm[8:6], dt[5:0]
|
||||
phase_calc = mmcm_pll_phase(divide, phase);
|
||||
|
||||
// Return value is the upper and lower address of counter
|
||||
// Upper address is:
|
||||
// RESERVED [31:26]
|
||||
// MX [25:24]
|
||||
// EDGE [23]
|
||||
// NOCOUNT [22]
|
||||
// DELAY_TIME [21:16]
|
||||
// Lower Address is:
|
||||
// PHASE_MUX [15:13]
|
||||
// RESERVED [12]
|
||||
// HIGH_TIME [11:6]
|
||||
// LOW_TIME [5:0]
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
|
||||
divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
|
||||
div_calc[13], div_calc[12],
|
||||
phase_calc[16:15], phase_calc[5:0], phase_calc[14:12]);
|
||||
`endif
|
||||
|
||||
mmcm_pll_count_calc =
|
||||
{
|
||||
// Upper Address
|
||||
6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
|
||||
// Lower Address
|
||||
phase_calc[8:6], 1'b0, div_calc[11:0]
|
||||
};
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
// This function takes in the divide, phase, and duty cycle
|
||||
// setting to calculate the upper and lower counter registers.
|
||||
// for fractional multiply/divide functions.
|
||||
//
|
||||
//
|
||||
function [37:0] mmcm_frac_count_calc
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input signed [31:0] phase,
|
||||
input [31:0] duty_cycle, // Multiplied by 100,000. Not programmable in fractional
|
||||
input [9:0] frac // Multiplied by 1000
|
||||
);
|
||||
|
||||
//Required for fractional divide calculations
|
||||
reg [7:0] lt_frac;
|
||||
reg [7:0] ht_frac;
|
||||
|
||||
reg /*[7:0]*/ wf_fall_frac;
|
||||
reg /*[7:0]*/ wf_rise_frac;
|
||||
|
||||
reg [31:0] a;
|
||||
reg [7:0] pm_rise_frac_filtered ;
|
||||
reg [7:0] pm_fall_frac_filtered ;
|
||||
reg [7:0] clkout0_divide_int;
|
||||
reg [2:0] clkout0_divide_frac;
|
||||
reg [7:0] even_part_high;
|
||||
reg [7:0] even_part_low;
|
||||
|
||||
reg [7:0] odd;
|
||||
reg [7:0] odd_and_frac;
|
||||
|
||||
reg [7:0] pm_fall;
|
||||
reg [7:0] pm_rise;
|
||||
reg [7:0] dt;
|
||||
reg [7:0] dt_int;
|
||||
reg [63:0] dt_calc;
|
||||
|
||||
reg [7:0] pm_rise_frac;
|
||||
reg [7:0] pm_fall_frac;
|
||||
|
||||
reg [31:0] a_per_in_octets;
|
||||
reg [31:0] a_phase_in_cycles;
|
||||
|
||||
parameter precision = 0.125;
|
||||
|
||||
reg [31:0] phase_fixed; // changed to 31:0 from 32:1 jt 5/2/11
|
||||
reg [31: 0] phase_pos;
|
||||
reg [31: 0] phase_vco;
|
||||
reg [31:0] temp;// changed to 31:0 from 32:1 jt 5/2/11
|
||||
reg [13:0] div_calc;
|
||||
reg [16:0] phase_calc;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("mmcm_frac_count_calc- divide:%h, phase:%d, duty_cycle:%d",
|
||||
divide, phase, duty_cycle);
|
||||
`endif
|
||||
|
||||
//convert phase to fixed
|
||||
if ((phase < -360000) || (phase > 360000)) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: phase of $phase is not between -360000 and 360000");
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
|
||||
// Return value is
|
||||
// Transfer data
|
||||
// RESERVED [37:36]
|
||||
// FRAC_TIME [35:33]
|
||||
// FRAC_WF_FALL [32]
|
||||
// Upper address is:
|
||||
// RESERVED [31:26]
|
||||
// MX [25:24]
|
||||
// EDGE [23]
|
||||
// NOCOUNT [22]
|
||||
// DELAY_TIME [21:16]
|
||||
// Lower Address is:
|
||||
// PHASE_MUX [15:13]
|
||||
// RESERVED [12]
|
||||
// HIGH_TIME [11:6]
|
||||
// LOW_TIME [5:0]
|
||||
|
||||
|
||||
|
||||
clkout0_divide_frac = frac / 125;
|
||||
clkout0_divide_int = divide;
|
||||
|
||||
even_part_high = clkout0_divide_int >> 1;//$rtoi(clkout0_divide_int / 2);
|
||||
even_part_low = even_part_high;
|
||||
|
||||
odd = clkout0_divide_int - even_part_high - even_part_low;
|
||||
odd_and_frac = (8*odd) + clkout0_divide_frac;
|
||||
|
||||
lt_frac = even_part_high - (odd_and_frac <= 9);//IF(odd_and_frac>9,even_part_high, even_part_high - 1)
|
||||
ht_frac = even_part_low - (odd_and_frac <= 8);//IF(odd_and_frac>8,even_part_low, even_part_low- 1)
|
||||
|
||||
pm_fall = {odd[6:0],2'b00} + {6'h00, clkout0_divide_frac[2:1]}; // using >> instead of clkout0_divide_frac / 2
|
||||
pm_rise = 0; //0
|
||||
|
||||
wf_fall_frac = ((odd_and_frac >=2) && (odd_and_frac <=9)) || (clkout0_divide_int == 2 && clkout0_divide_frac == 1); //IF(odd_and_frac>=2,IF(odd_and_frac <= 9,1,0),0)
|
||||
wf_rise_frac = (odd_and_frac >=1) && (odd_and_frac <=8); //IF(odd_and_frac>=1,IF(odd_and_frac <= 8,1,0),0)
|
||||
|
||||
|
||||
|
||||
//Calculate phase in fractional cycles
|
||||
a_per_in_octets = (8 * divide) + (frac / 125) ;
|
||||
a_phase_in_cycles = (phase+10) * a_per_in_octets / 360000 ;//Adding 1 due to rounding errors
|
||||
pm_rise_frac = (a_phase_in_cycles[7:0] ==8'h00)?8'h00:a_phase_in_cycles[7:0] - {a_phase_in_cycles[7:3],3'b000};
|
||||
|
||||
dt_calc = ((phase+10) * a_per_in_octets / 8 )/360000 ;//TRUNC(phase* divide / 360); //or_simply (a_per_in_octets / 8)
|
||||
dt = dt_calc[7:0];
|
||||
|
||||
pm_rise_frac_filtered = (pm_rise_frac >=8) ? (pm_rise_frac ) - 8: pm_rise_frac ; //((phase_fixed * (divide + frac / 1000)) / 360) - {pm_rise_frac[7:3],3'b000};//$rtoi(clkout0_phase * clkout0_divide / 45);//a;
|
||||
|
||||
dt_int = dt + (& pm_rise_frac[7:4]); //IF(pm_rise_overwriting>7,dt+1,dt)
|
||||
pm_fall_frac = pm_fall + pm_rise_frac;
|
||||
pm_fall_frac_filtered = pm_fall + pm_rise_frac - {pm_fall_frac[7:3], 3'b000};
|
||||
|
||||
div_calc = mmcm_pll_divider(divide, duty_cycle); //Use to determine edge[7], no count[6]
|
||||
phase_calc = mmcm_pll_phase(divide, phase);// returns{mx[1:0], phase_mux[2:0], delay_time[5:0]}
|
||||
|
||||
mmcm_frac_count_calc[37:0] =
|
||||
{ 2'b00, pm_fall_frac_filtered[2:0], wf_fall_frac,
|
||||
1'b0, clkout0_divide_frac[2:0], 1'b1, wf_rise_frac, phase_calc[10:9], 2'b00, dt[5:0],
|
||||
pm_rise_frac_filtered[2], pm_rise_frac_filtered[1], pm_rise_frac_filtered[0], 1'b0, ht_frac[5:0], lt_frac[5:0]
|
||||
} ;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("-%d.%d p%d>> :DADDR_9_15 frac30to28.frac_en.wf_r_frac.dt:%b%d%d_%b:DADDR_7_13 pm_f_frac_filtered_29to27.wf_f_frac_26:%b%d:DADDR_8_14.pm_r_frac_filt_15to13.ht_frac.lt_frac:%b%b%b:", divide, frac, phase, clkout0_divide_frac, 1, wf_rise_frac, dt, pm_fall_frac_filtered, wf_fall_frac, pm_rise_frac_filtered, ht_frac, lt_frac);
|
||||
`endif
|
||||
|
||||
end
|
||||
endfunction
|
||||
|
||||
+536
@@ -0,0 +1,536 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Company: Xilinx
|
||||
// Engineer: Jim Tatsukawa, Ralf Krueger, updated for Ultrascale+
|
||||
// Date: 6/15/2015
|
||||
// Design Name: PLLE4 DRP
|
||||
// Module Name: plle4_drp_func.h
|
||||
// Version: 2.0
|
||||
// Target Devices: UltraScale+ Architecture
|
||||
// Tool versions: 2017.1
|
||||
// Description: This header provides the functions necessary to
|
||||
// calculate the DRP register values for the V6 PLL.
|
||||
//
|
||||
// Revision Notes: 8/11 - PLLE3 updated for PLLE3 file 4564419
|
||||
// Revision Notes: 6/15 - pll_filter_lookup fixed for max M of 19
|
||||
// M_Rise bits have been removed for PLLE3
|
||||
// Revision Notes: 2/28/17 - pll_filter_lookup and CPRES updated for
|
||||
// Ultrascale+ and for max M of 21
|
||||
//
|
||||
// Disclaimer: XILINX IS PROVIDING THIS DESIGN, CODE, OR
|
||||
// INFORMATION "AS IS" SOLELY FOR USE IN DEVELOPING
|
||||
// PROGRAMS AND SOLUTIONS FOR XILINX DEVICES. BY
|
||||
// PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
|
||||
// ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
||||
// APPLICATION OR STANDARD, XILINX IS MAKING NO
|
||||
// REPRESENTATION THAT THIS IMPLEMENTATION IS FREE
|
||||
// FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE
|
||||
// RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY
|
||||
// REQUIRE FOR YOUR IMPLEMENTATION. XILINX
|
||||
// EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH
|
||||
// RESPECT TO THE ADEQUACY OF THE IMPLEMENTATION,
|
||||
// INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
||||
// REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
|
||||
// FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES
|
||||
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE.
|
||||
//
|
||||
// (c) Copyright 2009-2017 Xilinx, Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// These are user functions that should not be modified. Changes to the defines
|
||||
// or code within the functions may alter the accuracy of the calculations.
|
||||
|
||||
// Define debug to provide extra messages durring elaboration
|
||||
//`define DEBUG 1
|
||||
|
||||
// FRAC_PRECISION describes the width of the fractional portion of the fixed
|
||||
// point numbers. These should not be modified, they are for development
|
||||
// only
|
||||
`define FRAC_PRECISION 10
|
||||
// FIXED_WIDTH describes the total size for fixed point calculations(int+frac).
|
||||
// Warning: L.50 and below will not calculate properly with FIXED_WIDTHs
|
||||
// greater than 32
|
||||
`define FIXED_WIDTH 32
|
||||
|
||||
// This function takes a fixed point number and rounds it to the nearest
|
||||
// fractional precision bit.
|
||||
function [`FIXED_WIDTH:1] round_frac
|
||||
(
|
||||
// Input is (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point number
|
||||
input [`FIXED_WIDTH:1] decimal,
|
||||
|
||||
// This describes the precision of the fraction, for example a value
|
||||
// of 1 would modify the fractional so that instead of being a .16
|
||||
// fractional, it would be a .1 (rounded to the nearest 0.5 in turn)
|
||||
input [`FIXED_WIDTH:1] precision
|
||||
);
|
||||
|
||||
begin
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("round_frac - decimal: %h, precision: %h", decimal, precision);
|
||||
`endif
|
||||
// If the fractional precision bit is high then round up
|
||||
if( decimal[(`FRAC_PRECISION-precision)] == 1'b1) begin
|
||||
round_frac = decimal + (1'b1 << (`FRAC_PRECISION-precision));
|
||||
end else begin
|
||||
round_frac = decimal;
|
||||
end
|
||||
`ifdef DEBUG
|
||||
$display("round_frac: %h", round_frac);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function calculates high_time, low_time, w_edge, and no_count
|
||||
// of a non-fractional counter based on the divide and duty cycle
|
||||
//
|
||||
// NOTE: high_time and low_time are returned as integers between 0 and 63
|
||||
// inclusive. 64 should equal 6'b000000 (in other words it is okay to
|
||||
// ignore the overflow)
|
||||
function [13:0] mmcm_pll_divider
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input [31:0] duty_cycle // Duty cycle is multiplied by 100,000
|
||||
);
|
||||
|
||||
reg [`FIXED_WIDTH:1] duty_cycle_fix;
|
||||
|
||||
// High/Low time is initially calculated with a wider integer to prevent a
|
||||
// calculation error when it overflows to 64.
|
||||
reg [6:0] high_time;
|
||||
reg [6:0] low_time;
|
||||
reg w_edge;
|
||||
reg no_count;
|
||||
|
||||
reg [`FIXED_WIDTH:1] temp;
|
||||
|
||||
begin
|
||||
// Duty Cycle must be between 0 and 1,000
|
||||
if(duty_cycle <=0 || duty_cycle >= 100000) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: duty_cycle: %d is invalid", duty_cycle);
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
// Convert to FIXED_WIDTH-FRAC_PRECISION.FRAC_PRECISION fixed point
|
||||
duty_cycle_fix = (duty_cycle << `FRAC_PRECISION) / 100_000;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("duty_cycle_fix: %h", duty_cycle_fix);
|
||||
`endif
|
||||
|
||||
// If the divide is 1 nothing needs to be set except the no_count bit.
|
||||
// Other values are dummies
|
||||
if(divide == 7'h01) begin
|
||||
high_time = 7'h01;
|
||||
w_edge = 1'b0;
|
||||
low_time = 7'h01;
|
||||
no_count = 1'b1;
|
||||
end else begin
|
||||
temp = round_frac(duty_cycle_fix*divide, 1);
|
||||
|
||||
// comes from above round_frac
|
||||
high_time = temp[`FRAC_PRECISION+7:`FRAC_PRECISION+1];
|
||||
// If the duty cycle * divide rounded is .5 or greater then this bit
|
||||
// is set.
|
||||
w_edge = temp[`FRAC_PRECISION]; // comes from round_frac
|
||||
|
||||
// If the high time comes out to 0, it needs to be set to at least 1
|
||||
// and w_edge set to 0
|
||||
if(high_time == 7'h00) begin
|
||||
high_time = 7'h01;
|
||||
w_edge = 1'b0;
|
||||
end
|
||||
|
||||
if(high_time == divide) begin
|
||||
high_time = divide - 1;
|
||||
w_edge = 1'b1;
|
||||
end
|
||||
|
||||
// Calculate low_time based on the divide setting and set no_count to
|
||||
// 0 as it is only used when divide is 1.
|
||||
low_time = divide - high_time;
|
||||
no_count = 1'b0;
|
||||
end
|
||||
|
||||
// Set the return value.
|
||||
mmcm_pll_divider = {w_edge,no_count,high_time[5:0],low_time[5:0]};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function calculates mx, delay_time, and phase_mux
|
||||
// of a non-fractional counter based on the divide and phase
|
||||
//
|
||||
// NOTE: The only valid value for the MX bits is 2'b00 to ensure the coarse mux
|
||||
// is used.
|
||||
function [10:0] mmcm_pll_phase
|
||||
(
|
||||
// divide must be an integer (use fractional if not)
|
||||
// assumed that divide already checked to be valid
|
||||
input [7:0] divide, // Max divide is 128
|
||||
|
||||
// Phase is given in degrees (-360,000 to 360,000)
|
||||
input signed [31:0] phase
|
||||
);
|
||||
|
||||
reg [`FIXED_WIDTH:1] phase_in_cycles;
|
||||
reg [`FIXED_WIDTH:1] phase_fixed;
|
||||
reg [1:0] mx;
|
||||
reg [5:0] delay_time;
|
||||
reg [2:0] phase_mux;
|
||||
|
||||
reg [`FIXED_WIDTH:1] temp;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("pll_phase-divide:%d,phase:%d",
|
||||
divide, phase);
|
||||
`endif
|
||||
|
||||
if ((phase < -360000) || (phase > 360000)) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: phase of $phase is not between -360000 and 360000");
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
// If phase is less than 0, convert it to a positive phase shift
|
||||
// Convert to (FIXED_WIDTH-FRAC_PRECISION).FRAC_PRECISION fixed point
|
||||
if(phase < 0) begin
|
||||
phase_fixed = ( (phase + 360000) << `FRAC_PRECISION ) / 1000;
|
||||
end else begin
|
||||
phase_fixed = ( phase << `FRAC_PRECISION ) / 1000;
|
||||
end
|
||||
|
||||
// Put phase in terms of decimal number of vco clock cycles
|
||||
phase_in_cycles = ( phase_fixed * divide ) / 360;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("phase_in_cycles: %h", phase_in_cycles);
|
||||
`endif
|
||||
|
||||
|
||||
temp = round_frac(phase_in_cycles, 3);
|
||||
|
||||
// set mx to 2'b00 that the phase mux from the VCO is enabled
|
||||
mx = 2'b00;
|
||||
phase_mux = temp[`FRAC_PRECISION:`FRAC_PRECISION-2];
|
||||
delay_time = temp[`FRAC_PRECISION+6:`FRAC_PRECISION+1];
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("temp: %h", temp);
|
||||
`endif
|
||||
|
||||
// Setup the return value
|
||||
mmcm_pll_phase={mx, phase_mux, delay_time};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes the divide value and outputs the necessary lock values
|
||||
function [39:0] mmcm_pll_lock_lookup
|
||||
(
|
||||
input [6:0] divide // Max divide is 21
|
||||
);
|
||||
|
||||
reg [839:0] lookup;
|
||||
|
||||
begin
|
||||
lookup = {
|
||||
// This table is composed of:
|
||||
// LockRefDly_LockFBDly_LockCnt_LockSatHigh_UnlockCnt
|
||||
40'b00110_00110_1111101000_1111101001_0000000001, //1 illegal in Ultrascale+
|
||||
40'b00110_00110_1111101000_1111101001_0000000001, //2
|
||||
40'b01000_01000_1111101000_1111101001_0000000001, //3
|
||||
40'b01011_01011_1111101000_1111101001_0000000001, //4
|
||||
40'b01110_01110_1111101000_1111101001_0000000001, //5
|
||||
40'b10001_10001_1111101000_1111101001_0000000001, //6
|
||||
40'b10011_10011_1111101000_1111101001_0000000001, //7
|
||||
40'b10110_10110_1111101000_1111101001_0000000001, //8
|
||||
40'b11001_11001_1111101000_1111101001_0000000001, //9
|
||||
40'b11100_11100_1111101000_1111101001_0000000001, //10
|
||||
40'b11111_11111_1110000100_1111101001_0000000001, //11
|
||||
40'b11111_11111_1100111001_1111101001_0000000001, //12
|
||||
40'b11111_11111_1011101110_1111101001_0000000001, //13
|
||||
40'b11111_11111_1010111100_1111101001_0000000001, //14
|
||||
40'b11111_11111_1010001010_1111101001_0000000001, //15
|
||||
40'b11111_11111_1001110001_1111101001_0000000001, //16
|
||||
40'b11111_11111_1000111111_1111101001_0000000001, //17
|
||||
40'b11111_11111_1000100110_1111101001_0000000001, //18
|
||||
40'b11111_11111_1000001101_1111101001_0000000001, //19
|
||||
40'b11111_11111_0111110100_1111101001_0000000001, //20
|
||||
40'b11111_11111_0111011011_1111101001_0000000001 //21
|
||||
};
|
||||
|
||||
// Set lookup_entry with the explicit bits from lookup with a part select
|
||||
mmcm_pll_lock_lookup = lookup[ ((21-divide)*40) +: 40];
|
||||
`ifdef DEBUG
|
||||
$display("lock_lookup: %b", pll_lock_lookup);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function takes the divide value and the bandwidth setting of the PLL
|
||||
// and outputs the digital filter settings necessary. Removing bandwidth setting for PLLE3.
|
||||
function [9:0] mmcm_pll_filter_lookup
|
||||
(
|
||||
input [6:0] divide // Max divide is 21
|
||||
);
|
||||
|
||||
reg [209:0] lookup;
|
||||
reg [9:0] lookup_entry;
|
||||
|
||||
begin
|
||||
|
||||
lookup = {
|
||||
// CP_RES_LFHF
|
||||
10'b0011_0111_11, //1 not legal in Ultrascale+
|
||||
10'b0011_0111_11, //2
|
||||
10'b0011_0011_11, //3
|
||||
10'b0011_1001_11, //4
|
||||
10'b0011_0001_11, //5
|
||||
10'b0100_1110_11, //6
|
||||
10'b0011_0110_11, //7
|
||||
10'b0011_1010_11, //8
|
||||
10'b0111_1001_11, //9
|
||||
10'b0111_1001_11, //10
|
||||
10'b0101_0110_11, //11
|
||||
10'b1100_0101_11, //12
|
||||
10'b0101_1010_11, //13
|
||||
10'b0110_0110_11, //14
|
||||
10'b0110_1010_11, //15
|
||||
10'b0111_0110_11, //16
|
||||
10'b1111_0101_11, //17
|
||||
10'b1100_0110_11, //18
|
||||
10'b1110_0001_11, //19
|
||||
10'b1101_0110_11, //20
|
||||
10'b1111_0001_11 //21
|
||||
};
|
||||
|
||||
mmcm_pll_filter_lookup = lookup [ ((21-divide)*10) +: 10];
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("filter_lookup: %b", pll_filter_lookup);
|
||||
`endif
|
||||
end
|
||||
endfunction
|
||||
|
||||
// This function set the CLKOUTPHY divide settings to match
|
||||
// the desired CLKOUTPHY_MODE setting. To create VCO_X2, then
|
||||
// the CLKOUTPHY will be set to 2'b00 since the VCO is internally
|
||||
// doubled and 2'b00 will represent divide by 1. Similarly "VCO"
|
||||
// will need to divide the doubled clock VCO clock frequency by
|
||||
// 2 therefore 2'b01 will match a divide by 2.And VCO_HALF will
|
||||
// need to divide the doubled VCO by 4, therefore 2'b10
|
||||
function [9:0] mmcm_pll_clkoutphy_calc
|
||||
(
|
||||
input [8*9:0] CLKOUTPHY_MODE
|
||||
);
|
||||
|
||||
if(CLKOUTPHY_MODE == "VCO_X2") begin
|
||||
mmcm_pll_clkoutphy_calc= 2'b00;
|
||||
end else if(CLKOUTPHY_MODE == "VCO") begin
|
||||
mmcm_pll_clkoutphy_calc= 2'b01;
|
||||
end else if(CLKOUTPHY_MODE == "CLKIN") begin
|
||||
mmcm_pll_clkoutphy_calc= 2'b11;
|
||||
end else begin // Assume "VCO_HALF"
|
||||
mmcm_pll_clkoutphy_calc= 2'b10;
|
||||
end
|
||||
|
||||
endfunction
|
||||
|
||||
|
||||
// This function takes in the divide, phase, and duty cycle
|
||||
// setting to calculate the upper and lower counter registers.
|
||||
function [37:0] mmcm_pll_count_calc
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input signed [31:0] phase,
|
||||
input [31:0] duty_cycle // Multiplied by 100,000
|
||||
);
|
||||
|
||||
reg [13:0] div_calc;
|
||||
reg [16:0] phase_calc;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("pll_count_calc- divide:%h, phase:%d, duty_cycle:%d",
|
||||
divide, phase, duty_cycle);
|
||||
`endif
|
||||
|
||||
// w_edge[13], no_count[12], high_time[11:6], low_time[5:0]
|
||||
div_calc = mmcm_pll_divider(divide, duty_cycle);
|
||||
// mx[10:9], pm[8:6], dt[5:0]
|
||||
phase_calc = mmcm_pll_phase(divide, phase);
|
||||
|
||||
// Return value is the upper and lower address of counter
|
||||
// Upper address is:
|
||||
// RESERVED [31:26]
|
||||
// MX [25:24]
|
||||
// EDGE [23]
|
||||
// NOCOUNT [22]
|
||||
// DELAY_TIME [21:16]
|
||||
// Lower Address is:
|
||||
// PHASE_MUX [15:13]
|
||||
// RESERVED [12]
|
||||
// HIGH_TIME [11:6]
|
||||
// LOW_TIME [5:0]
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("div:%d dc:%d phase:%d ht:%d lt:%d ed:%d nc:%d mx:%d dt:%d pm:%d",
|
||||
divide, duty_cycle, phase, div_calc[11:6], div_calc[5:0],
|
||||
div_calc[13], div_calc[12],
|
||||
phase_calc[16:15], phase_calc[5:0], 3'b000); //Removed PM_Rise bits
|
||||
`endif
|
||||
|
||||
mmcm_pll_count_calc =
|
||||
{
|
||||
// Upper Address
|
||||
6'h00, phase_calc[10:9], div_calc[13:12], phase_calc[5:0],
|
||||
// Lower Address
|
||||
phase_calc[8:6], 1'b0, div_calc[11:0]
|
||||
};
|
||||
end
|
||||
endfunction
|
||||
|
||||
|
||||
// This function takes in the divide, phase, and duty cycle
|
||||
// setting to calculate the upper and lower counter registers.
|
||||
// for fractional multiply/divide functions.
|
||||
//
|
||||
//
|
||||
function [37:0] mmcm_pll_frac_count_calc
|
||||
(
|
||||
input [7:0] divide, // Max divide is 128
|
||||
input signed [31:0] phase,
|
||||
input [31:0] duty_cycle, // Multiplied by 1,000
|
||||
input [9:0] frac // Multiplied by 1000
|
||||
);
|
||||
|
||||
//Required for fractional divide calculations
|
||||
reg [7:0] lt_frac;
|
||||
reg [7:0] ht_frac;
|
||||
|
||||
reg /*[7:0]*/ wf_fall_frac;
|
||||
reg /*[7:0]*/ wf_rise_frac;
|
||||
|
||||
reg [31:0] a;
|
||||
reg [7:0] pm_rise_frac_filtered ;
|
||||
reg [7:0] pm_fall_frac_filtered ;
|
||||
reg [7:0] clkout0_divide_int;
|
||||
reg [2:0] clkout0_divide_frac;
|
||||
reg [7:0] even_part_high;
|
||||
reg [7:0] even_part_low;
|
||||
|
||||
reg [7:0] odd;
|
||||
reg [7:0] odd_and_frac;
|
||||
|
||||
reg [7:0] pm_fall;
|
||||
reg [7:0] pm_rise;
|
||||
reg [7:0] dt;
|
||||
reg [7:0] dt_int;
|
||||
reg [63:0] dt_calc;
|
||||
|
||||
reg [7:0] pm_rise_frac;
|
||||
reg [7:0] pm_fall_frac;
|
||||
|
||||
reg [31:0] a_per_in_octets;
|
||||
reg [31:0] a_phase_in_cycles;
|
||||
|
||||
parameter precision = 0.125;
|
||||
|
||||
reg [31:0] phase_fixed; // changed to 31:0 from 32:1 jt 5/2/11
|
||||
reg [31: 0] phase_pos;
|
||||
reg [31: 0] phase_vco;
|
||||
reg [31:0] temp;// changed to 31:0 from 32:1 jt 5/2/11
|
||||
reg [13:0] div_calc;
|
||||
reg [16:0] phase_calc;
|
||||
|
||||
begin
|
||||
`ifdef DEBUG
|
||||
$display("pll_frac_count_calc- divide:%h, phase:%d, duty_cycle:%d",
|
||||
divide, phase, duty_cycle);
|
||||
`endif
|
||||
|
||||
//convert phase to fixed
|
||||
if ((phase < -360000) || (phase > 360000)) begin
|
||||
`ifndef SYNTHESIS
|
||||
$display("ERROR: phase of $phase is not between -360000 and 360000");
|
||||
`endif
|
||||
$finish;
|
||||
end
|
||||
|
||||
|
||||
// Return value is
|
||||
// Transfer data
|
||||
// RESERVED [37:36]
|
||||
// FRAC_TIME [35:33]
|
||||
// FRAC_WF_FALL [32]
|
||||
// Upper address is:
|
||||
// RESERVED [31:26]
|
||||
// MX [25:24]
|
||||
// EDGE [23]
|
||||
// NOCOUNT [22]
|
||||
// DELAY_TIME [21:16]
|
||||
// Lower Address is:
|
||||
// PHASE_MUX [15:13]
|
||||
// RESERVED [12]
|
||||
// HIGH_TIME [11:6]
|
||||
// LOW_TIME [5:0]
|
||||
|
||||
|
||||
|
||||
clkout0_divide_frac = frac / 125;
|
||||
clkout0_divide_int = divide;
|
||||
|
||||
even_part_high = clkout0_divide_int >> 1;//$rtoi(clkout0_divide_int / 2);
|
||||
even_part_low = even_part_high;
|
||||
|
||||
odd = clkout0_divide_int - even_part_high - even_part_low;
|
||||
odd_and_frac = (8*odd) + clkout0_divide_frac;
|
||||
|
||||
lt_frac = even_part_high - (odd_and_frac <= 9);//IF(odd_and_frac>9,even_part_high, even_part_high - 1)
|
||||
ht_frac = even_part_low - (odd_and_frac <= 8);//IF(odd_and_frac>8,even_part_low, even_part_low- 1)
|
||||
|
||||
pm_fall = {odd[6:0],2'b00} + {6'h00, clkout0_divide_frac[2:1]}; // using >> instead of clkout0_divide_frac / 2
|
||||
pm_rise = 0; //0
|
||||
|
||||
wf_fall_frac = (odd_and_frac >=2) && (odd_and_frac <=9);//IF(odd_and_frac>=2,IF(odd_and_frac <= 9,1,0),0)
|
||||
wf_rise_frac = (odd_and_frac >=1) && (odd_and_frac <=8);//IF(odd_and_frac>=1,IF(odd_and_frac <= 8,1,0),0)
|
||||
|
||||
|
||||
|
||||
//Calculate phase in fractional cycles
|
||||
a_per_in_octets = (8 * divide) + (frac / 125) ;
|
||||
a_phase_in_cycles = (phase+10) * a_per_in_octets / 360000 ;//Adding 1 due to rounding errors
|
||||
pm_rise_frac = (a_phase_in_cycles[7:0] ==8'h00)?8'h00:a_phase_in_cycles[7:0] - {a_phase_in_cycles[7:3],3'b000};
|
||||
|
||||
dt_calc = ((phase+10) * a_per_in_octets / 8 )/360000 ;//TRUNC(phase* divide / 360); //or_simply (a_per_in_octets / 8)
|
||||
dt = dt_calc[7:0];
|
||||
|
||||
pm_rise_frac_filtered = (pm_rise_frac >=8) ? (pm_rise_frac ) - 8: pm_rise_frac ; //((phase_fixed * (divide + frac / 1000)) / 360) - {pm_rise_frac[7:3],3'b000};//$rtoi(clkout0_phase * clkout0_divide / 45);//a;
|
||||
|
||||
dt_int = dt + (& pm_rise_frac[7:4]); //IF(pm_rise_overwriting>7,dt+1,dt)
|
||||
pm_fall_frac = pm_fall + pm_rise_frac;
|
||||
pm_fall_frac_filtered = pm_fall + pm_rise_frac - {pm_fall_frac[7:3], 3'b000};
|
||||
|
||||
div_calc = mmcm_pll_divider(divide, duty_cycle); //Use to determine edge[7], no count[6]
|
||||
phase_calc = mmcm_pll_phase(divide, phase);// returns{mx[1:0], phase_mux[2:0], delay_time[5:0]}
|
||||
|
||||
mmcm_pll_frac_count_calc[37:0] =
|
||||
{ 2'b00, pm_fall_frac_filtered[2:0], wf_fall_frac,
|
||||
1'b0, clkout0_divide_frac[2:0], 1'b1, wf_rise_frac, phase_calc[10:9], div_calc[13:12], dt[5:0],
|
||||
3'b000, 1'b0, ht_frac[5:0], lt_frac[5:0] //Removed PM_Rise bits
|
||||
} ;
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("-%d.%d p%d>> :DADDR_9_15 frac30to28.frac_en.wf_r_frac.dt:%b%d%d_%b:DADDR_7_13 pm_f_frac_filtered_29to27.wf_f_frac_26:%b%d:DADDR_8_14.pm_r_frac_filt_15to13.ht_frac.lt_frac:%b%b%b:", divide, frac, phase, clkout0_divide_frac, 1, wf_rise_frac, dt, pm_fall_frac_filtered, wf_fall_frac, 3'b000, ht_frac, lt_frac);
|
||||
`endif
|
||||
|
||||
end
|
||||
endfunction
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
`timescale 1 ns / 1 ns
|
||||
|
||||
module reflectometer_and_dma_wrapper
|
||||
#(
|
||||
// parameters for base reflectometer works
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned PACK_FACTOR = 1,
|
||||
parameter int unsigned PROCESS_MODE = 0,
|
||||
parameter int unsigned ZERO_LEVEL = 8192,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 1024,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32,
|
||||
|
||||
// parameters for DMA and interfaces
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0
|
||||
)
|
||||
(
|
||||
input logic ctrl_clk,
|
||||
input logic rst_n,
|
||||
output wire locked,
|
||||
|
||||
axi4l_if.slave s_axil,
|
||||
axi4_if.master m_axi,
|
||||
// todo
|
||||
axis_if.master m_axis_read_data,
|
||||
|
||||
// DAC
|
||||
output wire dac_clk_o,
|
||||
output wire [DAC_DATA_WIDTH-1:0] dac_data,
|
||||
output wire dac_wrt,
|
||||
|
||||
// ADC
|
||||
output wire adc_clk_o,
|
||||
input wire [ADC_DATA_WIDTH-1:0] adc_data,
|
||||
input wire adc_otr
|
||||
|
||||
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_read_status_t)),
|
||||
.KEEP_W(($bits(dma_read_status_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) s_axis_status_read (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_write_status_t)),
|
||||
.KEEP_W(($bits(dma_write_status_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) s_axis_status_write (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_read_desc_t)),
|
||||
.KEEP_W(($bits(dma_read_desc_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_desc_read (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_write_desc_t)),
|
||||
.KEEP_W(($bits(dma_write_desc_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_desc_write (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W(RD_FIFO_WIDTH),
|
||||
.KEEP_W((RD_FIFO_WIDTH+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_accum (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
reflectometer_top #(
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE),
|
||||
.ZERO_LEVEL(ZERO_LEVEL),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RD_FIFO_WIDTH(RD_FIFO_WIDTH)
|
||||
) reflectometer_top_inst (
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.rst_n(rst_n),
|
||||
.locked(locked),
|
||||
.s_axil(s_axil),
|
||||
.m_axis_accum(m_axis_accum),
|
||||
.s_axis_status_read(s_axis_status_read),
|
||||
.s_axis_status_write(s_axis_status_write),
|
||||
.m_axis_desc_read(m_axis_desc_read),
|
||||
.m_axis_desc_write(m_axis_desc_write),
|
||||
|
||||
.dac_clk_o(dac_clk_o),
|
||||
.dac_data(dac_data),
|
||||
.dac_wrt(dac_wrt),
|
||||
.adc_clk_o(adc_clk_o),
|
||||
.adc_data(adc_data),
|
||||
.adc_otr(adc_otr)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// DMA
|
||||
//------------------------------------------------------------
|
||||
axi_dma_wrapper #(
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
|
||||
.AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED)
|
||||
) axi_dma_wrapper_inst
|
||||
(
|
||||
.clk(ctrl_clk),
|
||||
.rst(!rst_n),
|
||||
.s_axis_read_desc(m_axis_desc_read),
|
||||
.m_axis_read_desc_status(s_axis_status_read),
|
||||
.m_axis_read_data(m_axis_read_data),
|
||||
.s_axis_write_desc(m_axis_desc_write),
|
||||
.m_axis_write_desc_status(s_axis_status_write),
|
||||
.s_axis_write_data(m_axis_accum),
|
||||
.m_axi(m_axi)
|
||||
);
|
||||
|
||||
endmodule : reflectometer_and_dma_wrapper
|
||||
@@ -0,0 +1,245 @@
|
||||
`timescale 1 ns / 1 ns
|
||||
|
||||
module reflectometer_top #(
|
||||
// parameters for base reflectometer works
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned PACK_FACTOR = 1,
|
||||
parameter int unsigned PROCESS_MODE = 0,
|
||||
parameter int unsigned ZERO_LEVEL = 8192,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 1024,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32,
|
||||
|
||||
// parameters for DMA and interfaces
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1
|
||||
)
|
||||
(
|
||||
input logic ctrl_clk,
|
||||
input logic rst_n,
|
||||
output wire locked,
|
||||
|
||||
axi4l_if.slave s_axil,
|
||||
axis_if.master m_axis_accum,
|
||||
axis_if.slave s_axis_status_read,
|
||||
axis_if.slave s_axis_status_write,
|
||||
axis_if.master m_axis_desc_read,
|
||||
axis_if.master m_axis_desc_write,
|
||||
|
||||
// DAC
|
||||
output wire dac_clk_o,
|
||||
output wire [DAC_DATA_WIDTH-1:0] dac_data,
|
||||
output wire dac_wrt,
|
||||
|
||||
// ADC
|
||||
output wire adc_clk_o,
|
||||
input wire [ADC_DATA_WIDTH-1:0] adc_data,
|
||||
input wire adc_otr
|
||||
|
||||
|
||||
);
|
||||
|
||||
wire workflow_done, processing_done;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Generated clocks for controller
|
||||
// Need to create this IP in Vivado:
|
||||
// input resetn
|
||||
// input clk_200 : 200 MHz : Reference clock
|
||||
// output clk_adc_65 : 65 MHz : ADC RTL clock
|
||||
// output clk_adc_65_180 : 65 MHz, phase 180 deg. : ADC PHY clock
|
||||
// output clk_adc_125 : 125 MHz : DAC RTL clock
|
||||
// output clk_adc_125_180 : 125 MHz, phase 180 deg. : DAC PHY clock
|
||||
// output locked
|
||||
// -------------------------------------------------------------------------
|
||||
wire clk_sampler, clk_generator, clk_locked;
|
||||
|
||||
clk_wiz_0 clk_wiz_inst
|
||||
(
|
||||
// Clock in ports
|
||||
.clk_200(ctrl_clk),
|
||||
// Clock out ports
|
||||
.clk_adc_65(clk_sampler),
|
||||
.clk_adc_65_180(adc_clk_o),
|
||||
.clk_dac_125(clk_generator),
|
||||
.clk_dac_125_180(dac_clk_o),
|
||||
// Status and control signals
|
||||
.reset(~rst_n),
|
||||
.locked(clk_locked)
|
||||
);
|
||||
|
||||
assign locked = clk_locked;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Controller reset
|
||||
// Use both external reset and clk_wiz lock
|
||||
// -------------------------------------------------------------------------
|
||||
wire ctrl_rst_n = rst_n & clk_locked;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Controller
|
||||
// -------------------------------------------------------------------------
|
||||
wire [31:0] dac_pulse_width;
|
||||
wire [31:0] dac_pulse_period;
|
||||
wire [DAC_DATA_WIDTH-1:0] dac_pulse_height;
|
||||
wire [15:0] dac_pulse_num;
|
||||
|
||||
wire [31:0] adc_pulse_period;
|
||||
wire [15:0] adc_pulse_num;
|
||||
wire [31:0] adc_window_size;
|
||||
|
||||
wire dac_start;
|
||||
wire adc_start;
|
||||
wire dac_rst;
|
||||
wire adc_rst;
|
||||
|
||||
controller_wrapper_axil #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W),
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
) controller_wrapper_axil_inst
|
||||
(
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.dac_clk_in(clk_generator),
|
||||
.adc_clk_in(clk_sampler),
|
||||
.rst_n(ctrl_rst_n),
|
||||
|
||||
.s_axil(s_axil),
|
||||
|
||||
.workflow_done(workflow_done),
|
||||
.processing_done(processing_done),
|
||||
|
||||
.adc_window_size(adc_window_size),
|
||||
.dac_pulse_width(dac_pulse_width),
|
||||
.dac_pulse_period(dac_pulse_period),
|
||||
.dac_pulse_height(dac_pulse_height),
|
||||
.dac_pulse_num(dac_pulse_num),
|
||||
.adc_pulse_period(adc_pulse_period),
|
||||
.adc_pulse_num(adc_pulse_num),
|
||||
.dac_start(dac_start),
|
||||
.adc_start(adc_start),
|
||||
.dac_rst(dac_rst),
|
||||
.adc_rst(adc_rst),
|
||||
|
||||
.s_axis_status_read(s_axis_status_read),
|
||||
.s_axis_status_write(s_axis_status_write),
|
||||
.m_axis_desc_read(m_axis_desc_read),
|
||||
.m_axis_desc_write(m_axis_desc_write)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// DAC -> ADC CDC
|
||||
//------------------------------------------------------------
|
||||
(* ASYNC_REG = "TRUE" *) logic [2:0] stretch; // 125/65~=2. Чтобы поймать единичный импульс, растянем его во времени
|
||||
(* ASYNC_REG = "TRUE" *) logic [1:0] sync_DA;
|
||||
wire dac_done_stretched;
|
||||
|
||||
wire generator_done, generator_request;
|
||||
wire sampler_done, sampler_request;
|
||||
|
||||
always_ff @(posedge clk_generator or posedge dac_rst)
|
||||
begin
|
||||
if (dac_rst)
|
||||
stretch <= 0;
|
||||
else begin
|
||||
stretch[0] <= generator_done;
|
||||
stretch[1] <= stretch[0];
|
||||
stretch[2] <= stretch[1];
|
||||
end
|
||||
end
|
||||
assign dac_done_stretched = |stretch;
|
||||
|
||||
always_ff @(posedge clk_sampler or posedge adc_rst) begin
|
||||
if (adc_rst)
|
||||
sync_DA <= 0;
|
||||
else begin
|
||||
sync_DA[0] <= dac_done_stretched;
|
||||
sync_DA[1] <= sync_DA[0];
|
||||
end
|
||||
end
|
||||
assign sampler_request = sync_DA[1];
|
||||
|
||||
//------------------------------------------------------------
|
||||
// ADC -> DAC CDC
|
||||
//------------------------------------------------------------
|
||||
(* ASYNC_REG = "TRUE" *) logic [1:0] sync_AD;
|
||||
|
||||
always_ff @(posedge clk_generator or posedge dac_rst) begin
|
||||
if (dac_rst)
|
||||
sync_AD <= 0;
|
||||
else begin
|
||||
sync_AD[0] <= sampler_done;
|
||||
sync_AD[1] <= sync_AD[0];
|
||||
end
|
||||
end
|
||||
assign generator_request = sync_AD[1];
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Generator (DAC)
|
||||
//------------------------------------------------------------
|
||||
generator #(
|
||||
.DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ZERO_LEVEL(ZERO_LEVEL)
|
||||
) generator_inst (
|
||||
.clk_dac(clk_generator),
|
||||
.rst(dac_rst),
|
||||
.start(dac_start),
|
||||
.pulse_width(dac_pulse_width),
|
||||
.pulse_period(dac_pulse_period),
|
||||
.pulse_height(dac_pulse_height),
|
||||
.pulse_num(dac_pulse_num),
|
||||
.dac_out(dac_data),
|
||||
.done(generator_done),
|
||||
.request(generator_request)
|
||||
);
|
||||
assign dac_wrt = dac_clk_o;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Sampler (ADC)
|
||||
// -------------------------------------------------------------------------
|
||||
wire [ADC_DATA_WIDTH*PACK_FACTOR-1:0] sampler_m_axis_tdata;
|
||||
wire sampler_m_axis_tvalid;
|
||||
|
||||
sampler #(
|
||||
.DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE)
|
||||
) sampler_inst (
|
||||
.clk_in(clk_sampler),
|
||||
.rst(adc_rst),
|
||||
.data_in(adc_data),
|
||||
.out_of_range(adc_otr),
|
||||
.m_axis_tdata(sampler_m_axis_tdata),
|
||||
.m_axis_tvalid(sampler_m_axis_tvalid),
|
||||
.smp_num(adc_pulse_period),
|
||||
.done(sampler_done),
|
||||
.request(sampler_request)
|
||||
);
|
||||
|
||||
accumulator_top #(
|
||||
.DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RW_WIDTH(RD_FIFO_WIDTH)
|
||||
) accumulator_top_inst (
|
||||
.clk_in(clk_sampler),
|
||||
.rst(adc_rst),
|
||||
.s_axis_tdata(sampler_m_axis_tdata),
|
||||
.s_axis_tvalid(sampler_m_axis_tvalid),
|
||||
.start(adc_start),
|
||||
.smp_num(adc_pulse_period),
|
||||
.seq_num(adc_pulse_num),
|
||||
.window_size(adc_window_size),
|
||||
.dma_clk_in(ctrl_clk),
|
||||
.req_ready(1'b1),
|
||||
.m_axis_accum(m_axis_accum),
|
||||
.finish(workflow_done),
|
||||
.accum_done(processing_done)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,67 @@
|
||||
TOPLEVEL_LANG = verilog
|
||||
SIM ?= questa
|
||||
WAVES = 1
|
||||
WLF_FILE := $(SIM_BUILD)/waves.wlf
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
|
||||
RTL_DIR = $(PWD)/../../src
|
||||
RTL_ACCUM_DIR = $(PWD)/../../../../rtl/accum/src
|
||||
RTL_GENERATOR_DIR = $(PWD)/../../../../rtl/generator/src
|
||||
RTL_SAMPLER_DIR = $(PWD)/../../../../rtl/sampler/src
|
||||
RTL_CLK_DIR = $(PWD)/../../src/clk_ctrl_wiz/clk_wiz_0
|
||||
RTL_CTRL_DIR = $(PWD)/../../../../rtl/controller_new
|
||||
LIBS_DIR = $(PWD)/../../../../external/rtl_libs
|
||||
|
||||
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi_pkg.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/dma_reg_pkg.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi_if.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axis_if.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axis_if_to_flat.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi4l_flat_to_if.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/axi_reg/axi4l_reg_map.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma_rd.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma_wr.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_ram.v
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi_ram_wrapper.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/controller.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/dma_controller.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/shaper_axis_desc.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/shaper_axis_status.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/controller_wrapper_axil.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/axi4l_reg_map_controller_pkg.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/axis_defaults_helper.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/axi4l_reg_map_controller.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi_dma_wrapper_if.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/adder.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/out_axis_fifo.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/accum.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/accum_top.sv
|
||||
VERILOG_SOURCES += $(RTL_GENERATOR_DIR)/generator.sv
|
||||
VERILOG_SOURCES += $(RTL_SAMPLER_DIR)/sampler.sv
|
||||
VERILOG_SOURCES += $(RTL_CLK_DIR)/clk_wiz_0_clk_wiz.v
|
||||
VERILOG_SOURCES += $(RTL_CLK_DIR)/clk_wiz_0.v
|
||||
|
||||
VERILOG_SOURCES += $(PWD)/adc_model.sv
|
||||
VERILOG_SOURCES += $(PWD)/dac_model.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/reflectometer_ip.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/reflectometer_and_dma_wrapper.sv
|
||||
VERILOG_SOURCES += $(PWD)/tb_full_reflectometer.sv
|
||||
VERILOG_SOURCES += /mnt/c/Xilinx/Vivado/2021.2/data/verilog/src/glbl.v
|
||||
|
||||
TOPLEVEL = tb_full_reflectometer
|
||||
MODULE = full_reflectometer_test
|
||||
|
||||
|
||||
ifeq ($(SIM),questa)
|
||||
SIM_ARGS += -L xpm -L unisim
|
||||
SIM_ARGS += work.glbl
|
||||
SIM_ARGS += -wlf $(WLF_FILE)
|
||||
COMPILE_ARGS += +acc
|
||||
endif
|
||||
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
@@ -0,0 +1,59 @@
|
||||
// AN9238 virtual ADC model (1 port)
|
||||
|
||||
module virtual_adc_model #(
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
|
||||
// Bipolar input range: +/- VOLTAGE_RANGE
|
||||
parameter real VOLTAGE_RANGE = 1.0,
|
||||
|
||||
// Analog input correction
|
||||
parameter real VOLTAGE_GAIN = 0.2,
|
||||
parameter real GROUND_BIAS = 0.0,
|
||||
|
||||
// ADC timing parameters
|
||||
parameter time CONVERSION_DELAY = 250ps
|
||||
)(
|
||||
input logic clk_i,
|
||||
input real voltage_i,
|
||||
|
||||
output logic otr_o,
|
||||
output logic [ADC_DATA_WIDTH-1:0] data_o
|
||||
);
|
||||
|
||||
localparam int unsigned ZERO_CODE = (1 << (ADC_DATA_WIDTH - 1));
|
||||
localparam real VOLTAGE_STEP = (2 * VOLTAGE_RANGE) / real'((1 << ADC_DATA_WIDTH) - 1);
|
||||
|
||||
real voltage_corrected;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Convert analog voltage to ADC code
|
||||
//------------------------------------------------------------
|
||||
function automatic logic [ADC_DATA_WIDTH-1:0] voltage_to_code( input real voltage );
|
||||
if (voltage <= -VOLTAGE_RANGE) return '0;
|
||||
if (voltage >= VOLTAGE_RANGE) return {ADC_DATA_WIDTH{1'b1}};
|
||||
return $rtoi(voltage / VOLTAGE_STEP + real'((ZERO_CODE)) + 0.5);
|
||||
endfunction
|
||||
|
||||
function automatic logic range_check( input real voltage );
|
||||
real v_abs = (voltage < 0.0) ? -voltage : voltage;
|
||||
return v_abs >= VOLTAGE_RANGE;
|
||||
endfunction
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Initial state
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
data_o = ZERO_CODE; // 0V
|
||||
otr_o = 0;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Update analog output
|
||||
//------------------------------------------------------------
|
||||
always @(posedge clk_i) begin
|
||||
voltage_corrected = (voltage_i - GROUND_BIAS) * VOLTAGE_GAIN;
|
||||
data_o <= #(CONVERSION_DELAY) voltage_to_code(voltage_corrected);
|
||||
otr_o <= #(CONVERSION_DELAY) range_check(voltage_corrected);
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,58 @@
|
||||
// AN9767 model (1 port)
|
||||
|
||||
module virtual_dac_model #(
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
|
||||
// Bipolar output range: +/- VOLTAGE_RANGE
|
||||
parameter real VOLTAGE_RANGE = 5.0,
|
||||
|
||||
// Analog output correction
|
||||
parameter real VOLTAGE_GAIN = 1.0,
|
||||
parameter real GROUND_BIAS = 0.0,
|
||||
|
||||
// DAC timing parameters
|
||||
parameter time TRANSMISSION_DELAY = 150ps,
|
||||
parameter time CONVERSION_DELAY = 150ps
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic wrt_i,
|
||||
input logic [DAC_DATA_WIDTH-1:0] data_i,
|
||||
|
||||
output real voltage_o
|
||||
);
|
||||
|
||||
localparam int unsigned ZERO_CODE = (1 << (DAC_DATA_WIDTH - 1));
|
||||
localparam real VOLTAGE_STEP = (2 * VOLTAGE_RANGE) / real'((1 << DAC_DATA_WIDTH) - 1);
|
||||
|
||||
logic [DAC_DATA_WIDTH-1:0] dac_code;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Convert DAC code to analog voltage
|
||||
//------------------------------------------------------------
|
||||
function automatic real code_to_voltage( input logic [DAC_DATA_WIDTH-1:0] code);
|
||||
return (int'(code) - int'(ZERO_CODE)) * VOLTAGE_STEP;
|
||||
endfunction
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Initial state
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
dac_code = '0;
|
||||
voltage_o = code_to_voltage('0) * VOLTAGE_GAIN + GROUND_BIAS;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Latch new DAC code
|
||||
//------------------------------------------------------------
|
||||
always @(posedge wrt_i) begin
|
||||
dac_code <= #(TRANSMISSION_DELAY) data_i;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Update analog output
|
||||
//------------------------------------------------------------
|
||||
always @(posedge clk_i) begin
|
||||
voltage_o <= #(CONVERSION_DELAY) code_to_voltage(dac_code) * VOLTAGE_GAIN + GROUND_BIAS;
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,191 @@
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotbext.axi import AxiLiteBus, AxiLiteMaster
|
||||
from cocotbext.axi import AxiStreamBus, AxiStreamSink, AxiStreamSource, AxiStreamFrame
|
||||
|
||||
from reg_map import *
|
||||
|
||||
def reg_addr(reg_index: int) -> int:
|
||||
# AXI-Lite uses byte addresses, 32-bit registers are spaced by 4 bytes.
|
||||
return reg_index * 4
|
||||
|
||||
|
||||
def u32(value: int) -> bytes:
|
||||
return int(value & 0xFFFFFFFF).to_bytes(4, "little")
|
||||
|
||||
class Drivers:
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
cocotb.start_soon(Clock(dut.ctrl_clk, 10, unit="ns").start())
|
||||
|
||||
self.axil = AxiLiteMaster(
|
||||
AxiLiteBus.from_prefix(dut, "s_axil"),
|
||||
dut.ctrl_clk,
|
||||
dut.rst)
|
||||
|
||||
|
||||
# self.axis_source = AxiStreamSource(
|
||||
# AxiStreamBus.from_prefix(dut, "s_axis_write_data"),
|
||||
# dut.ctrl_clk,
|
||||
# dut.rst)
|
||||
|
||||
self.axis_sink = AxiStreamSink(
|
||||
AxiStreamBus.from_prefix(dut, "m_axis_read_data"),
|
||||
dut.ctrl_clk,
|
||||
dut.rst)
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.value = 1
|
||||
for _ in range(20):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
self.dut.rst.value = 0
|
||||
for _ in range(20):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
async def wait_locked(self, timeout_cycles=1000):
|
||||
for _ in range(timeout_cycles):
|
||||
if int(self.dut.locked.value) == 1:
|
||||
print("MMCM locked")
|
||||
return
|
||||
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
raise TimeoutError( f"Timeout waiting for locked == 1. " f"Current locked = {self.dut.locked.value}")
|
||||
|
||||
async def write_reg(self, reg_index: int, value: int):
|
||||
await self.axil.write(reg_addr(reg_index), u32(value))
|
||||
|
||||
async def read_reg(self, reg_index: int) -> int:
|
||||
resp = await self.axil.read(reg_addr(reg_index), 4)
|
||||
return int.from_bytes(bytes(resp.data), "little")
|
||||
|
||||
async def pulse_control(self, mask):
|
||||
await self.write_reg( REG_CONTROL, mask )
|
||||
|
||||
# Reflectometer Driver
|
||||
|
||||
async def configure_reflectometer (
|
||||
self,
|
||||
pulse_width,
|
||||
pulse_period,
|
||||
pulse_num,
|
||||
pulse_height,
|
||||
adc_period,
|
||||
window_size,
|
||||
timeout_cycles):
|
||||
await self.write_reg(REG_DAC_WIDTH, pulse_width)
|
||||
await self.write_reg(REG_DAC_PERIOD, pulse_period)
|
||||
await self.write_reg(REG_DAC_PULSE_NUM, pulse_num)
|
||||
await self.write_reg(REG_DAC_PULSE_HEIGHT, pulse_height)
|
||||
await self.write_reg(REG_ADC_PERIOD, adc_period)
|
||||
await self.write_reg(REG_WINDOW_SIZE, window_size)
|
||||
|
||||
await self.pulse_control(CTRL_CFG_BUS_VALID)
|
||||
|
||||
control = self.dut.dut.reflectometer_top_inst.controller_wrapper_axil_inst.controller
|
||||
|
||||
for cycle in range(timeout_cycles):
|
||||
dac_wait = int(control.cfg_wait_dac_ack.value)
|
||||
adc_wait = int(control.cfg_wait_adc_ack.value)
|
||||
|
||||
if dac_wait == 0 and adc_wait == 0:
|
||||
print(f"Configuration done after {cycle} ctrl_clk cycles")
|
||||
return
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
async def send_start(self):
|
||||
await self.pulse_control(CTRL_START)
|
||||
|
||||
async def soft_reset(self):
|
||||
await self.pulse_control(CTRL_RST_SOFT)
|
||||
|
||||
async def get_status(self):
|
||||
status = await self.read_reg(REG_STATUS)
|
||||
return {
|
||||
"busy": bool(status & STATUS_BUSY),
|
||||
"processing_done": bool(status & STATUS_PROCESSING_DONE),
|
||||
"desc_read_busy": bool(status & STATUS_DESC_READ_BUSY),
|
||||
"desc_write_busy": bool(status & STATUS_DESC_WRITE_BUSY),
|
||||
"status_read_busy": bool(status & STATUS_STATUS_READ_BUSY),
|
||||
"status_write_busy": bool(status & STATUS_STATUS_WRITE_BUSY),
|
||||
"desc_read_hs": bool(status & STATUS_DESC_READ_HS),
|
||||
"desc_write_hs": bool(status & STATUS_DESC_WRITE_HS),
|
||||
"status_read_hs": bool(status & STATUS_STATUS_READ_HS),
|
||||
"status_write_hs": bool(status & STATUS_STATUS_WRITE_HS)
|
||||
}
|
||||
|
||||
async def wait_status(self, field, value=True, timeout_cycles=1000):
|
||||
|
||||
for _ in range(timeout_cycles):
|
||||
status = await self.get_status()
|
||||
|
||||
if status[field] == value:
|
||||
return
|
||||
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
status = await self.get_status()
|
||||
|
||||
raise TimeoutError( f"Timeout waiting for status.{field} == {value}. " f"Current status = {status}")
|
||||
|
||||
async def wait_processing_done(self, timeout_cycles=1000):
|
||||
await self.wait_status("processing_done", True, timeout_cycles)
|
||||
|
||||
|
||||
async def wait_finish(self, timeout_cycles=1000):
|
||||
await self.wait_status("busy", False, timeout_cycles)
|
||||
|
||||
# DMA Driver
|
||||
|
||||
async def send_desc_write(self, addr, length_tag):
|
||||
|
||||
await self.write_reg(REG_DESC_WRITE_ADDR, addr)
|
||||
await self.write_reg(REG_DESC_WRITE_LEN_AND_TAG, length_tag)
|
||||
await self.pulse_control(CTRL_SEND_DESC_WRITE)
|
||||
|
||||
async def send_desc_read(self, addr, length, config):
|
||||
|
||||
await self.write_reg(REG_DESC_READ_ADDR, addr)
|
||||
await self.write_reg(REG_DESC_READ_LEN, length)
|
||||
await self.write_reg(REG_DESC_READ_CONFIG, config)
|
||||
await self.pulse_control( CTRL_SEND_DESC_READ)
|
||||
|
||||
async def take_status_write(self, status_write_len, status_write_config):
|
||||
await self.write_reg(REG_CONTROL, CTRL_TAKE_STATUS_WRITE)
|
||||
|
||||
|
||||
assert await self.read_reg(REG_STATUS_WRITE_CONFIG) == status_write_config
|
||||
assert await self.read_reg(REG_STATUS_WRITE_LEN) == status_write_len
|
||||
|
||||
async def take_status_read(self, status_read):
|
||||
await self.pulse_control( CTRL_TAKE_STATUS_READ)
|
||||
for _ in range(10):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
assert await self.read_reg(REG_READ_STATUS) == status_read
|
||||
|
||||
async def wait_dma_write_done(self, timeout_cycles=1000):
|
||||
await self.wait_status("desc_write_busy", False, timeout_cycles)
|
||||
|
||||
async def wait_dma_read_done(self, timeout_cycles=1000):
|
||||
await self.wait_status("desc_read_busy", False, timeout_cycles)
|
||||
|
||||
async def wait_status_read_handshake(self, timeout_cycles=1000):
|
||||
await self.wait_status("status_read_hs", True, timeout_cycles)
|
||||
|
||||
async def wait_status_write_handshake(self, timeout_cycles=1000):
|
||||
await self.wait_status("status_write_hs", True, timeout_cycles)
|
||||
|
||||
# AxiStream Driver
|
||||
|
||||
# async def send_axis_data(self, data: bytes):
|
||||
|
||||
# await self.axis_source.send(AxiStreamFrame(data) )
|
||||
|
||||
async def receive_axis_data(self):
|
||||
|
||||
frame = await self.axis_sink.recv()
|
||||
return bytes(frame)
|
||||
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
import cocotb
|
||||
from cocotb.triggers import RisingEdge
|
||||
|
||||
from drivers import Drivers
|
||||
from reference_model import Reference_model
|
||||
from scoreboard import Scoreboard
|
||||
|
||||
from reg_map import *
|
||||
|
||||
class TB:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
dut,
|
||||
pulse_width,
|
||||
pulse_period,
|
||||
pulse_num,
|
||||
pulse_height,
|
||||
adc_period,
|
||||
window_size
|
||||
):
|
||||
self.dut = dut
|
||||
|
||||
self.driver = Drivers(dut)
|
||||
|
||||
self.reference = Reference_model(
|
||||
dut=dut,
|
||||
|
||||
pulse_width=pulse_width,
|
||||
pulse_period=pulse_period,
|
||||
pulse_num=pulse_num,
|
||||
pulse_height=pulse_height,
|
||||
adc_period=adc_period,
|
||||
window_size=window_size,
|
||||
|
||||
DAC_DATA_WIDTH=DAC_DATA_WIDTH,
|
||||
ADC_DATA_WIDTH=ADC_DATA_WIDTH,
|
||||
PACK_FACTOR=PACK_FACTOR,
|
||||
PROCESS_MODE=PROCESS_MODE,
|
||||
ZERO_LEVEL=ZERO_LEVEL,
|
||||
ACCUM_WIDTH=ACCUM_WIDTH,
|
||||
N_MAX=N_MAX,
|
||||
PACKET_SIZE=PACKET_SIZE,
|
||||
RD_FIFO_WIDTH=RD_FIFO_WIDTH,
|
||||
)
|
||||
|
||||
self.scoreboard = Scoreboard()
|
||||
|
||||
|
||||
SEQ_NUM = 1
|
||||
WINDOW_SIZE = 1
|
||||
|
||||
PULSE_WIDTH = 10
|
||||
PULSE_PERIOD = 20
|
||||
PULSE_HEIGHT = 15000
|
||||
ADC_PERIOD = 20
|
||||
|
||||
@cocotb.test()
|
||||
async def rest_init(dut):
|
||||
tb = TB(dut,
|
||||
pulse_width=PULSE_WIDTH,
|
||||
pulse_period=PULSE_PERIOD,
|
||||
pulse_num=SEQ_NUM,
|
||||
pulse_height=PULSE_HEIGHT,
|
||||
adc_period=ADC_PERIOD,
|
||||
window_size=WINDOW_SIZE)
|
||||
await tb.driver.reset()
|
||||
|
||||
@cocotb.test()
|
||||
async def base_full_test(dut):
|
||||
tb = TB(dut,
|
||||
pulse_width=PULSE_WIDTH,
|
||||
pulse_period=PULSE_PERIOD,
|
||||
pulse_num=SEQ_NUM,
|
||||
pulse_height=PULSE_HEIGHT,
|
||||
adc_period=ADC_PERIOD,
|
||||
window_size=WINDOW_SIZE
|
||||
)
|
||||
await tb.driver.reset()
|
||||
await tb.driver.wait_locked()
|
||||
await tb.driver.soft_reset()
|
||||
|
||||
RESULT_ADDR = 0x1000
|
||||
|
||||
await tb.driver.configure_reflectometer(
|
||||
pulse_width = PULSE_WIDTH,
|
||||
pulse_period=PULSE_PERIOD,
|
||||
pulse_num=SEQ_NUM,
|
||||
pulse_height=PULSE_HEIGHT,
|
||||
adc_period=ADC_PERIOD,
|
||||
window_size=WINDOW_SIZE,
|
||||
timeout_cycles=1000
|
||||
)
|
||||
|
||||
samples = tb.reference.gen_input_samples()
|
||||
|
||||
SMP_NUM = len(samples[0])
|
||||
# SMP_NUM = ADC_PERIOD
|
||||
|
||||
expected = tb.reference.calculate_expected( samples, WINDOW_SIZE, ACCUM_WIDTH)
|
||||
|
||||
print("")
|
||||
print("========================================")
|
||||
print("ACCUMULATOR RANDOM TEST")
|
||||
print("========================================")
|
||||
print(f"seq_num = {SEQ_NUM}")
|
||||
print(f"smp_num = {SMP_NUM}")
|
||||
print(f"window_size = {WINDOW_SIZE}")
|
||||
print(f"data_width = {ADC_DATA_WIDTH}")
|
||||
print(f"accum_width = {ACCUM_WIDTH}")
|
||||
print(f"expected words = {len(expected)}")
|
||||
|
||||
RESULT_WORDS = len(expected)
|
||||
RESULT_BYTES = RESULT_WORDS * 4
|
||||
|
||||
|
||||
print("==============================")
|
||||
print("ACCUM TEST")
|
||||
print("words =", RESULT_WORDS)
|
||||
print("bytes =", RESULT_BYTES)
|
||||
print("==============================")
|
||||
|
||||
for _ in range(10):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
await tb.driver.send_start()
|
||||
|
||||
for _ in range(4):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
await tb.driver.wait_processing_done(timeout_cycles=100000)
|
||||
|
||||
await tb.driver.send_desc_write( addr=RESULT_ADDR, length_tag=RESULT_BYTES )
|
||||
await tb.driver.wait_dma_write_done(timeout_cycles=5000)
|
||||
|
||||
for _ in range(100):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
await tb.driver.take_status_write(status_write_len=RESULT_BYTES, status_write_config=0)
|
||||
|
||||
await tb.driver.send_desc_read(addr=RESULT_ADDR, length=RESULT_BYTES, config=0x0000_0001 )
|
||||
|
||||
received_data = await tb.driver.receive_axis_data()
|
||||
|
||||
await tb.driver.wait_dma_read_done(timeout_cycles=5000)
|
||||
|
||||
|
||||
await tb.driver.take_status_read(status_read=0x1)
|
||||
|
||||
|
||||
received = tb.scoreboard.bytes_to_words(received_data, RD_FIFO_WIDTH)
|
||||
|
||||
print("")
|
||||
print("Expected:")
|
||||
for i, value in enumerate(expected):
|
||||
print(f" [{i}] = 0x{value:08X}")
|
||||
|
||||
print("")
|
||||
print("Received:")
|
||||
for i, value in enumerate(received):
|
||||
print(f" [{i}] = 0x{value:08X}")
|
||||
|
||||
tb.scoreboard.check_results(
|
||||
expected=expected,
|
||||
received=received
|
||||
)
|
||||
|
||||
print("")
|
||||
print("========================================")
|
||||
print("ACCUMULATOR RANDOM TEST PASSED")
|
||||
print("========================================")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
from reg_map import *
|
||||
|
||||
class Reference_model:
|
||||
def __init__(
|
||||
self,
|
||||
dut,
|
||||
pulse_width,
|
||||
pulse_period,
|
||||
pulse_num,
|
||||
pulse_height,
|
||||
adc_period,
|
||||
window_size,
|
||||
DAC_DATA_WIDTH,
|
||||
ADC_DATA_WIDTH,
|
||||
PACK_FACTOR,
|
||||
PROCESS_MODE,
|
||||
ZERO_LEVEL,
|
||||
ACCUM_WIDTH,
|
||||
N_MAX,
|
||||
PACKET_SIZE,
|
||||
RD_FIFO_WIDTH
|
||||
):
|
||||
|
||||
self.dut = dut
|
||||
|
||||
# configuration
|
||||
self.pulse_width = pulse_width
|
||||
self.pulse_period = pulse_period
|
||||
self.pulse_num = pulse_num
|
||||
self.pulse_height = pulse_height
|
||||
self.adc_sample_num = adc_period
|
||||
self.window_size = window_size
|
||||
|
||||
# parameters
|
||||
self.DAC_DATA_WIDTH = DAC_DATA_WIDTH
|
||||
self.ADC_DATA_WIDTH = ADC_DATA_WIDTH
|
||||
self.PACK_FACTOR = PACK_FACTOR
|
||||
self.PROCESS_MODE = PROCESS_MODE
|
||||
self.ZERO_LEVEL = ZERO_LEVEL
|
||||
self.ACCUM_WIDTH = ACCUM_WIDTH
|
||||
self.N_MAX = N_MAX
|
||||
self.PACKET_SIZE = PACKET_SIZE
|
||||
self.RD_FIFO_WIDTH = RD_FIFO_WIDTH
|
||||
|
||||
# intermediate data
|
||||
self.samples = []
|
||||
self.expected = []
|
||||
|
||||
|
||||
def gen_input_samples(self):
|
||||
|
||||
self.samples = []
|
||||
|
||||
# -----------------------------
|
||||
# DAC: 14 bit
|
||||
# -----------------------------
|
||||
DAC_ZERO = self.ZERO_LEVEL
|
||||
DAC_MAX = (1 << self.DAC_DATA_WIDTH) - 1
|
||||
|
||||
DAC_RANGE = 5.0
|
||||
|
||||
DAC_STEP = (
|
||||
2.0 * DAC_RANGE
|
||||
) / DAC_MAX
|
||||
|
||||
# -----------------------------
|
||||
# ADC: 12 bit
|
||||
# -----------------------------
|
||||
ADC_ZERO = 1 << (self.ADC_DATA_WIDTH - 1)
|
||||
ADC_MAX = (1 << self.ADC_DATA_WIDTH) - 1
|
||||
|
||||
ADC_RANGE = 1.0
|
||||
ADC_GAIN = 0.2
|
||||
GROUND_BIAS = 0.0
|
||||
|
||||
ADC_STEP = (
|
||||
2.0 * ADC_RANGE
|
||||
) / ADC_MAX
|
||||
|
||||
# -----------------------------
|
||||
# Generate every pulse sequence
|
||||
# -----------------------------
|
||||
for _ in range(self.pulse_num):
|
||||
|
||||
pulse_samples = []
|
||||
|
||||
for sample_idx in range(self.adc_sample_num):
|
||||
|
||||
# ==========================================
|
||||
# 1. Generator produces a 14-bit DAC code
|
||||
# ==========================================
|
||||
if sample_idx < self.pulse_width:
|
||||
dac_code = self.pulse_height
|
||||
else:
|
||||
dac_code = DAC_ZERO
|
||||
|
||||
# Limit to actual DAC width
|
||||
dac_code = max(0, min(dac_code, DAC_MAX))
|
||||
|
||||
# ==========================================
|
||||
# 2. 14-bit DAC code -> analog voltage
|
||||
# ==========================================
|
||||
voltage = (
|
||||
(dac_code - DAC_ZERO)
|
||||
* DAC_STEP
|
||||
)
|
||||
|
||||
# ==========================================
|
||||
# 3. Analog path -> ADC input voltage
|
||||
# ==========================================
|
||||
voltage = (
|
||||
(voltage - GROUND_BIAS)
|
||||
* ADC_GAIN
|
||||
)
|
||||
|
||||
# ==========================================
|
||||
# 4. Analog voltage -> 12-bit ADC code
|
||||
# ==========================================
|
||||
if voltage <= -ADC_RANGE:
|
||||
|
||||
adc_code = 0
|
||||
|
||||
elif voltage >= ADC_RANGE:
|
||||
|
||||
adc_code = ADC_MAX
|
||||
|
||||
else:
|
||||
|
||||
adc_code = int(
|
||||
round(
|
||||
voltage / ADC_STEP
|
||||
+ ADC_ZERO
|
||||
)
|
||||
)
|
||||
|
||||
# Make absolutely sure that the result
|
||||
# is a valid 12-bit value.
|
||||
adc_code = max(
|
||||
0,
|
||||
min(adc_code, ADC_MAX)
|
||||
)
|
||||
|
||||
# ==========================================
|
||||
# 5. ADC out-of-range processing
|
||||
# ==========================================
|
||||
out_of_range = (
|
||||
abs(voltage) >= ADC_RANGE
|
||||
)
|
||||
|
||||
if self.PROCESS_MODE:
|
||||
|
||||
msb = (
|
||||
adc_code
|
||||
>> (self.ADC_DATA_WIDTH - 1)
|
||||
) & 1
|
||||
|
||||
if out_of_range:
|
||||
|
||||
if msb:
|
||||
sample = ADC_MAX
|
||||
else:
|
||||
sample = 0
|
||||
|
||||
else:
|
||||
|
||||
sample = (
|
||||
(((~msb) & 1)
|
||||
<< (self.ADC_DATA_WIDTH - 1))
|
||||
|
|
||||
(
|
||||
adc_code
|
||||
& (
|
||||
(1 << (self.ADC_DATA_WIDTH - 1))
|
||||
- 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
else:
|
||||
|
||||
if out_of_range:
|
||||
|
||||
if adc_code & ADC_ZERO:
|
||||
sample = ADC_MAX
|
||||
else:
|
||||
sample = 0
|
||||
|
||||
else:
|
||||
|
||||
sample = adc_code
|
||||
|
||||
# ==========================================
|
||||
# Final sample is ALWAYS 12-bit ADC data
|
||||
# ==========================================
|
||||
sample &= ADC_MAX
|
||||
|
||||
pulse_samples.append(sample)
|
||||
|
||||
self.samples.append(pulse_samples)
|
||||
|
||||
return self.samples
|
||||
|
||||
|
||||
|
||||
|
||||
def calculate_expected(
|
||||
self,
|
||||
samples,
|
||||
window_size: int,
|
||||
accum_width: int):
|
||||
if window_size <= 0:
|
||||
raise ValueError( f"window_size must be > 0, got {window_size}")
|
||||
|
||||
if not samples:
|
||||
raise ValueError("samples must not be empty")
|
||||
|
||||
seq_num = len(samples)
|
||||
smp_num = len(samples[0])
|
||||
|
||||
if smp_num == 0:
|
||||
raise ValueError("samples must not contain empty sequences")
|
||||
|
||||
for seq_idx, seq_samples in enumerate(samples):
|
||||
if len(seq_samples) != smp_num:
|
||||
raise ValueError(f"Sequence {seq_idx} has {len(seq_samples)} samples, " f"expected {smp_num}" )
|
||||
|
||||
if smp_num % window_size != 0:
|
||||
raise ValueError(f"smp_num ({smp_num}) must be divisible " f"by window_size ({window_size})")
|
||||
|
||||
exp_word_count = smp_num // window_size
|
||||
accum_mask = (1 << accum_width) - 1
|
||||
|
||||
expected = []
|
||||
|
||||
for word_idx in range(exp_word_count):
|
||||
local_sum = 0
|
||||
|
||||
for seq_idx in range(seq_num):
|
||||
for k in range(window_size):
|
||||
sample_idx = word_idx * window_size + k
|
||||
local_sum += samples[seq_idx][sample_idx]
|
||||
|
||||
expected.append(local_sum & accum_mask)
|
||||
|
||||
return expected
|
||||
|
||||
|
||||
def run(self):
|
||||
self.gen_input_samples()
|
||||
|
||||
self.expected = self.calculate_expected( self.samples, self.window_size, self.ACCUM_WIDTH)
|
||||
|
||||
return self.expected
|
||||
@@ -0,0 +1,54 @@
|
||||
# Register indexes from axi4l_reg_map_controller_pkg.sv
|
||||
REG_CONTROL = 0
|
||||
REG_STATUS = 1
|
||||
REG_DAC_WIDTH = 2
|
||||
REG_DAC_PERIOD = 3
|
||||
REG_DAC_PULSE_NUM = 4
|
||||
REG_DAC_PULSE_HEIGHT = 5
|
||||
REG_ADC_PERIOD = 6
|
||||
REG_WINDOW_SIZE = 7
|
||||
REG_ERROR = 8
|
||||
REG_DESC_READ_ADDR = 9
|
||||
REG_DESC_READ_LEN = 10
|
||||
REG_DESC_READ_CONFIG = 11
|
||||
REG_READ_STATUS = 12
|
||||
REG_DESC_WRITE_ADDR = 13
|
||||
REG_DESC_WRITE_LEN_AND_TAG = 14
|
||||
REG_STATUS_WRITE_LEN = 15
|
||||
REG_STATUS_WRITE_CONFIG = 16
|
||||
|
||||
|
||||
# REG_CONTROL pulse bits
|
||||
CTRL_START = 1 << 0
|
||||
CTRL_RST_SOFT = 1 << 1
|
||||
CTRL_CFG_BUS_VALID = 1 << 2
|
||||
CTRL_SEND_DESC_READ = 1 << 3
|
||||
CTRL_SEND_DESC_WRITE = 1 << 4
|
||||
CTRL_TAKE_STATUS_READ = 1 << 5
|
||||
CTRL_TAKE_STATUS_WRITE = 1 << 6
|
||||
|
||||
# REG_STATUS bits
|
||||
STATUS_BUSY = 1 << 0
|
||||
STATUS_PROCESSING_DONE = 1 << 1
|
||||
|
||||
STATUS_DESC_READ_BUSY = 1 << 2
|
||||
STATUS_DESC_WRITE_BUSY = 1 << 3
|
||||
STATUS_STATUS_READ_BUSY = 1 << 4
|
||||
STATUS_STATUS_WRITE_BUSY = 1 << 5
|
||||
|
||||
STATUS_DESC_READ_HS = 1 << 6
|
||||
STATUS_DESC_WRITE_HS = 1 << 7
|
||||
STATUS_STATUS_READ_HS = 1 << 8
|
||||
STATUS_STATUS_WRITE_HS = 1 << 9
|
||||
|
||||
# PARAMETERS for accumulator reference model
|
||||
|
||||
DAC_DATA_WIDTH = 14
|
||||
ADC_DATA_WIDTH = 12
|
||||
PACK_FACTOR = 1
|
||||
PROCESS_MODE = 0
|
||||
ZERO_LEVEL = 8192
|
||||
ACCUM_WIDTH = 32
|
||||
N_MAX = 4096
|
||||
PACKET_SIZE = 1024
|
||||
RD_FIFO_WIDTH = 32
|
||||
@@ -0,0 +1,40 @@
|
||||
from reg_map import *
|
||||
|
||||
class Scoreboard:
|
||||
def __init__(self):
|
||||
|
||||
self.test_passed = False
|
||||
|
||||
|
||||
def bytes_to_words(self, data: bytes, word_width: int = 32):
|
||||
word_bytes = word_width // 8
|
||||
|
||||
if len(data) % word_bytes != 0:
|
||||
raise ValueError(f"Data length {len(data)} is not divisible " f"by word size {word_bytes}" )
|
||||
|
||||
words = []
|
||||
|
||||
for i in range(0, len(data), word_bytes):
|
||||
word = int.from_bytes(data[i:i + word_bytes], byteorder="little" )
|
||||
words.append(word)
|
||||
|
||||
return words
|
||||
|
||||
|
||||
def check_results(self, expected, received):
|
||||
|
||||
assert len(received) == len(expected), (
|
||||
f"Number of words mismatch: "
|
||||
f"expected={len(expected)}, "
|
||||
f"received={len(received)}" )
|
||||
|
||||
for i, (exp, rec) in enumerate(zip(expected, received)):
|
||||
assert rec == exp, (
|
||||
f"Payload mismatch at index {i}: "
|
||||
f"expected=0x{exp:08X}, "
|
||||
f"received=0x{rec:08X}" )
|
||||
self.test_passed = True
|
||||
|
||||
print( f"Payload check passed: " f"{len(expected)} words")
|
||||
|
||||
return True
|
||||
+861
@@ -0,0 +1,861 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
`define MEASURE_CLK(clk, period) \
|
||||
begin \
|
||||
realtime t1, t2; \
|
||||
@(posedge clk); \
|
||||
t1 = $realtime; \
|
||||
@(posedge clk); \
|
||||
t2 = $realtime; \
|
||||
period = t2 - t1; \
|
||||
end
|
||||
|
||||
`define ERR_CHECK \
|
||||
total_tests++; \
|
||||
if (result_flag) begin \
|
||||
total_failed_tests++; \
|
||||
$error("Test #%0d failed. Err code: %0d", total_tests, result_flag); \
|
||||
end \
|
||||
|
||||
module reflectometer_tb;
|
||||
//------------------------------------------------------------
|
||||
// Параметры
|
||||
//------------------------------------------------------------
|
||||
localparam int unsigned DAC_DATA_WIDTH = 14;
|
||||
localparam int unsigned ADC_DATA_WIDTH = 12;
|
||||
localparam LOGIC_ZERO_LEVEL = 0; // DAC -5V for logic zero
|
||||
localparam VOLTAGE_ZERO_LEVEL = 2**(DAC_DATA_WIDTH-1); // DAC 0V for logic zero
|
||||
localparam PACK_FACTOR = 1; // not used in TB
|
||||
localparam PROCESS_MODE = 0; // 0 - uint, 1 - int. Current accumulator don't support signed sum
|
||||
localparam ACCUM_WIDTH = 32; // accumulator number bit witdth
|
||||
localparam N_MAX = 4096; // max value of windows to average by experiments
|
||||
localparam PACKET_SIZE = 1024; // bytes per UDP packet
|
||||
localparam int unsigned RD_FIFO_WIDTH = 32;
|
||||
|
||||
localparam int REQUEST_TIMEOUT = 3 * PACKET_SIZE; // timeout for packet receiving from accumulator
|
||||
|
||||
localparam ZERO_LEVEL = LOGIC_ZERO_LEVEL; // "logic" VS "voltage"
|
||||
|
||||
localparam CLK_ETH_PHY_PERIOD = 8.000; // 125 MHz
|
||||
localparam CLK_REF_PERIOD = 5.000; // 200 MHz
|
||||
|
||||
localparam int unsigned AXI_DATA_WIDTH = 32;
|
||||
|
||||
localparam int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8;
|
||||
localparam int unsigned AXI_USER_WIDTH = 1;
|
||||
localparam int unsigned AXI_ID_WIDTH = 8;
|
||||
localparam int unsigned AXI_MAX_BURST_LEN = 16;
|
||||
|
||||
localparam int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH;
|
||||
localparam int unsigned AXIS_LAST_ENABLE = 1;
|
||||
localparam int unsigned AXIS_ID_ENABLE = 1;
|
||||
localparam int unsigned AXIS_DEST_ENABLE = 0;
|
||||
localparam int unsigned AXIS_USER_ENABLE = 1;
|
||||
|
||||
localparam int unsigned ENABLE_SG = 0;
|
||||
localparam int unsigned ENABLE_UNALIGNED = 0;
|
||||
|
||||
localparam int unsigned PIPELINE_OUTPUT = 0;
|
||||
|
||||
realtime CLK_ADC_PERIOD;
|
||||
realtime CLK_DAC_PERIOD;
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Тактовые �игналы и �бро�
|
||||
//------------------------------------------------------------
|
||||
logic clk_ref = 1'b0; // 200 MHz
|
||||
logic rst_n = 1'b0;
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Входы DUT
|
||||
//------------------------------------------------------------
|
||||
// ADC интерфей�
|
||||
wire clk_adc;
|
||||
wire adc_otr;
|
||||
wire [ADC_DATA_WIDTH-1:0] adc_data;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Выходы
|
||||
//------------------------------------------------------------
|
||||
// Стату�ы
|
||||
wire mmcm_locked;
|
||||
// DAC интерфей�
|
||||
wire clk_dac;
|
||||
wire dac_wrt;
|
||||
wire [DAC_DATA_WIDTH-1:0] dac_data;
|
||||
//------------------------------------------------------------
|
||||
// Внутренние �игналы те�тбенча
|
||||
//------------------------------------------------------------
|
||||
|
||||
// Сигнал между Ц�П и �ЦП
|
||||
real signal_voltage;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Virtual DAC
|
||||
//------------------------------------------------------------
|
||||
virtual_dac_model #( // default voltage range is +/- 5V
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
// ,.VOLTAGE_GAIN(2)
|
||||
) virtual_dac (
|
||||
.clk_i(clk_dac),
|
||||
.wrt_i(dac_wrt),
|
||||
.data_i(dac_data),
|
||||
.voltage_o(signal_voltage)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Virtual ADC
|
||||
//------------------------------------------------------------
|
||||
virtual_adc_model #( // default voltage range is +/- 5V
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH)
|
||||
) virtual_adc (
|
||||
.clk_i(clk_adc),
|
||||
.voltage_i(signal_voltage),
|
||||
.otr_o(adc_otr),
|
||||
.data_o(adc_data)
|
||||
);
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
// DUT
|
||||
//------------------------------------------------------------
|
||||
tb_full_reflectometer #(
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_ID_WIDTH(AXI_ID_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED),
|
||||
.PIPELINE_OUTPUT(PIPELINE_OUTPUT),
|
||||
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE),
|
||||
.ZERO_LEVEL(ZERO_LEVEL),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RD_FIFO_WIDTH(RD_FIFO_WIDTH)
|
||||
) DUT (
|
||||
.ctrl_clk(clk_ref),
|
||||
.rst_n(rst_n),
|
||||
|
||||
// Status
|
||||
.locked(mmcm_locked),
|
||||
|
||||
// m_axil config
|
||||
.s_axil_awaddr (s_axil_awaddr),
|
||||
.s_axil_awprot (s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
|
||||
.s_axil_wdata (s_axil_wdata),
|
||||
.s_axil_wstrb (s_axil_wstrb),
|
||||
.s_axil_wvalid (s_axil_wvalid),
|
||||
.s_axil_wready (s_axil_wready),
|
||||
|
||||
.s_axil_bresp (s_axil_bresp),
|
||||
.s_axil_bvalid (s_axil_bvalid),
|
||||
.s_axil_bready (s_axil_bready),
|
||||
|
||||
.s_axil_araddr (s_axil_araddr),
|
||||
.s_axil_arprot (s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
|
||||
.s_axil_rdata (s_axil_rdata),
|
||||
.s_axil_rresp (s_axil_rresp),
|
||||
.s_axil_rvalid (s_axil_rvalid),
|
||||
.s_axil_rready (s_axil_rready),
|
||||
|
||||
// s_axis dma reader
|
||||
.m_axis_tdata (),
|
||||
.m_axis_tkeep (),
|
||||
.m_axis_tstrb (),
|
||||
.m_axis_tlast (),
|
||||
.m_axis_tid (),
|
||||
.m_axis_tdest (),
|
||||
.m_axis_tuser (),
|
||||
.m_axis_tvalid(),
|
||||
.m_axis_tready(1'b0),
|
||||
|
||||
// m_axi read_res
|
||||
.s_axi_awid(s_axi_awid),
|
||||
.s_axi_awaddr(s_axi_awaddr),
|
||||
.s_axi_awlen(s_axi_awlen),
|
||||
.s_axi_awsize(s_axi_awsize),
|
||||
.s_axi_awburst(s_axi_awburst),
|
||||
.s_axi_awlock(s_axi_awlock),
|
||||
.s_axi_awcache(s_axi_awcache),
|
||||
.s_axi_awprot(s_axi_awprot),
|
||||
.s_axi_awqos(s_axi_awqos),
|
||||
.s_axi_awregion(s_axi_awregion),
|
||||
.s_axi_awuser(s_axi_awuser),
|
||||
.s_axi_awvalid(s_axi_awvalid),
|
||||
.s_axi_awready(s_axi_awready),
|
||||
.s_axi_wdata(s_axi_wdata),
|
||||
.s_axi_wstrb(s_axi_wstrb),
|
||||
.s_axi_wlast(s_axi_wlast),
|
||||
.s_axi_wuser(s_axi_wuser),
|
||||
.s_axi_wvalid(s_axi_wvalid),
|
||||
.s_axi_wready(s_axi_wready),
|
||||
.s_axi_bid(s_axi_bid),
|
||||
.s_axi_bresp(s_axi_bresp),
|
||||
.s_axi_buser(s_axi_buser),
|
||||
.s_axi_bvalid(s_axi_bvalid),
|
||||
.s_axi_bready(s_axi_bready),
|
||||
.s_axi_arid(s_axi_arid),
|
||||
.s_axi_araddr(s_axi_araddr),
|
||||
.s_axi_arlen(s_axi_arlen),
|
||||
.s_axi_arsize(s_axi_arsize),
|
||||
.s_axi_arburst(s_axi_arburst),
|
||||
.s_axi_arlock(s_axi_arlock),
|
||||
.s_axi_arcache(s_axi_arcache),
|
||||
.s_axi_arprot(s_axi_arprot),
|
||||
.s_axi_arqos(s_axi_arqos),
|
||||
.s_axi_arregion(s_axi_arregion),
|
||||
.s_axi_aruser(s_axi_aruser),
|
||||
.s_axi_arvalid(s_axi_arvalid),
|
||||
.s_axi_arready(s_axi_arready),
|
||||
.s_axi_rid(s_axi_rid),
|
||||
.s_axi_rdata(s_axi_rdata),
|
||||
.s_axi_rresp(s_axi_rresp),
|
||||
.s_axi_rlast(s_axi_rlast),
|
||||
.s_axi_ruser(s_axi_ruser),
|
||||
.s_axi_rvalid(s_axi_rvalid),
|
||||
.s_axi_rready(s_axi_rready),
|
||||
|
||||
// DAC
|
||||
.dac_clk_o(clk_dac),
|
||||
.dac_data(dac_data),
|
||||
.dac_wrt(dac_wrt),
|
||||
|
||||
// ADC
|
||||
.adc_clk_o(clk_adc),
|
||||
.adc_data(adc_data),
|
||||
.adc_otr(adc_otr)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Òàêòîâûå ñèãíàëû
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
forever #(CLK_REF_PERIOD/2) clk_ref = ~clk_ref;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Òàñêè äëÿ òåñòèðîâàíèÿ
|
||||
//------------------------------------------------------------
|
||||
// Òàñêè ðàáîòû ñ AXI-Lite, AXI
|
||||
|
||||
// Òàñêè äëÿ ðàáîòû ñ DMA
|
||||
|
||||
// Òàñêà êîíôèãóðàöèîííàÿ
|
||||
|
||||
|
||||
task automatic dut_soft_reset(virtual axis_if#(8).tb vif);
|
||||
logic [7:0] tx_packet[];
|
||||
tx_packet = '{8'h0f};
|
||||
vif.master_send(tx_packet);
|
||||
endtask
|
||||
|
||||
task automatic dut_start(virtual axis_if#(8).tb vif);
|
||||
logic [7:0] tx_packet[];
|
||||
tx_packet = '{8'hf0};
|
||||
vif.master_send(tx_packet);
|
||||
endtask
|
||||
|
||||
task automatic dut_send_system_config(
|
||||
virtual axis_if#(8).tb vif,
|
||||
input logic [31:0] pulse_width,
|
||||
input logic [31:0] pulse_period,
|
||||
input logic [15:0] pulse_num,
|
||||
input logic [13:0] pulse_height, // achtung! p_height strictly must have 14 bits of width
|
||||
input logic [31:0] pulse_period_adc,
|
||||
input logic [31:0] window_size
|
||||
);
|
||||
// Ñîçäàåì âðåìåííûé ôèêñèðîâàííûé ìàññèâ è óïàêîâûâàåì âñ¸ îäíîé ñòðîêîé
|
||||
logic [7:0] tx_packet[];
|
||||
|
||||
// Àõòóíã, 14-áèòíûé ÖÀÏ çàõàðäêîæåí
|
||||
if (DAC_DATA_WIDTH != 14)
|
||||
$warning("[WARNING] -dut_send_system_config- Default pulse height (DAC bitwidth) is equal to 14. Be aware, controller packet structure is coded for 14 bits");
|
||||
|
||||
tx_packet = '{
|
||||
8'h88, // Êîìàíäà
|
||||
pulse_width[7:0], pulse_width[15:8], pulse_width[23:16], pulse_width[31:24],
|
||||
pulse_period[7:0], pulse_period[15:8], pulse_period[23:16], pulse_period[31:24],
|
||||
pulse_num[7:0], pulse_num[15:8], pulse_height[7:0], 8'({2'b00, pulse_height[13:8]}),
|
||||
pulse_period_adc[7:0], pulse_period_adc[15:8], pulse_period_adc[23:16], pulse_period_adc[31:24]
|
||||
};
|
||||
|
||||
vif.master_send(tx_packet);
|
||||
|
||||
// TODO remove for new controller
|
||||
window_size_port = window_size;
|
||||
endtask
|
||||
|
||||
|
||||
|
||||
// Òàñêè ñáîðà ñòàòèñòèêè
|
||||
task automatic dut_read_output(
|
||||
virtual axis_if#(8).tb vif,
|
||||
input int sample_num,
|
||||
input int window_size,
|
||||
input bit randomize_recv_delays,
|
||||
output int output_data[]
|
||||
);
|
||||
logic [7:0] rx_packet[];
|
||||
logic [ACCUM_WIDTH-1:0] data_packet[];
|
||||
int numbers_per_packet = PACKET_SIZE/(ACCUM_WIDTH/8);
|
||||
int packet_num = $ceil(real'(sample_num / window_size) / real'(numbers_per_packet));
|
||||
int timeout_flag = 0;
|
||||
int packet_counter = 0;
|
||||
|
||||
if (sample_num % window_size) begin
|
||||
$error("-dut_read_output- Sample_num must be multiple of window_size: %0d %% %0d = %0d", sample_num, window_size, sample_num % window_size);
|
||||
$finish;
|
||||
end
|
||||
|
||||
data_packet = new[numbers_per_packet];
|
||||
output_data = new[numbers_per_packet * packet_num];
|
||||
|
||||
// count send_request pulses (equal to number of packets)
|
||||
fork
|
||||
begin : packet_counter_proc
|
||||
forever begin
|
||||
@(posedge clk_eth_phy);
|
||||
if(send_request === 1)
|
||||
packet_counter++;
|
||||
end
|
||||
end
|
||||
join_none
|
||||
|
||||
// Wait until reflectometer done sampling and averaging
|
||||
wait(processing_done == 1);
|
||||
|
||||
// recv loop
|
||||
// åñëè ÷èñëî ïàêåòîâ ïðåâûøàåò çàëîæåííîå ïðåäðàññ÷èòàííîå çíà÷åíèå -- îøèáêà
|
||||
fork : recv_loop_proc
|
||||
begin
|
||||
// packet recv loop
|
||||
forever begin
|
||||
if (packet_counter > packet_num) begin
|
||||
$error("-dut_read_output- Packet overflow detected. Number of data packets exceeds expected amount of packets");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (randomize_recv_delays)
|
||||
repeat($urandom_range(0, 500)) @(posedge clk_eth_phy);
|
||||
|
||||
timeout_flag = 0;
|
||||
fork : receive_packet_timeout
|
||||
begin
|
||||
request_ready = 1;
|
||||
vif.slave_recv(rx_packet);
|
||||
request_ready = 0;
|
||||
end
|
||||
begin
|
||||
repeat(REQUEST_TIMEOUT) @(posedge clk_eth_phy);
|
||||
timeout_flag = 1;
|
||||
end
|
||||
join_any
|
||||
|
||||
disable receive_packet_timeout;
|
||||
if (timeout_flag) begin
|
||||
$error("-dut_read_output- Timeout detected when receiving packet");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (rx_packet.size() != PACKET_SIZE) begin
|
||||
$error("-dut_read_output- Wrong packet size received: %0d bytes received, %0d bytes expected", rx_packet.size(), PACKET_SIZE);
|
||||
$finish;
|
||||
end
|
||||
|
||||
// unpack values
|
||||
data_packet = {<< byte {rx_packet}};
|
||||
data_packet = {<< ACCUM_WIDTH {data_packet}};
|
||||
|
||||
// copy and convert values
|
||||
for (int j = 0; j < data_packet.size(); j++) begin
|
||||
output_data[(packet_counter-1) * data_packet.size() + j] = int'(data_packet[j]);
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
begin
|
||||
// IP workflow completion event
|
||||
wait(workflow_done == 1);
|
||||
end
|
||||
join_any
|
||||
|
||||
disable recv_loop_proc;
|
||||
disable packet_counter_proc;
|
||||
|
||||
if (packet_counter != packet_num) begin
|
||||
$error("-dut_read_output- Wrong number of packets received: %0d received, %0d expected", packet_counter, packet_num);
|
||||
$finish;
|
||||
end
|
||||
|
||||
wait(processing_done == 0);
|
||||
|
||||
endtask
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Ôóíêöèè è òàñêè äëÿ âåðèôèêàöèè ñèãíàëîâ
|
||||
//------------------------------------------------------------
|
||||
// Òàñêà ãåíåðàöèè èäåàëüíîãî òåñòîâîãî ñèãíàëà
|
||||
task automatic reference_signal(
|
||||
input int pulse_width,
|
||||
input int pulse_height,
|
||||
input int pulse_period_adc,
|
||||
input int window_size,
|
||||
output real result[]
|
||||
);
|
||||
/*
|
||||
Globals:
|
||||
ADC and DAC clock periods,
|
||||
Virtual ADC and DAC voltage steps
|
||||
|
||||
Task developed with assumption that first discrete values of DAC and ADC
|
||||
are syncrhonized at t==0 and started simultaneously.
|
||||
|
||||
Gains and biases of virtual ADC & DAC are default and ranges are [-5V;5V].
|
||||
Bitwidths may be altered.
|
||||
|
||||
Returned result[] array is an array of sums of voltage potentials in discrete time points.
|
||||
Discrete samples summed over a time window.
|
||||
|
||||
result[time] = (voltage)
|
||||
*/
|
||||
|
||||
int sample_num = pulse_period_adc / window_size; // total averaged output samples from accumulator
|
||||
|
||||
real current_signal_sample, partial_sum;
|
||||
real ref_signal_active_voltage = virtual_dac.code_to_voltage(pulse_height);
|
||||
real ref_signal_zero_voltage = virtual_dac.code_to_voltage(ZERO_LEVEL);
|
||||
|
||||
if (pulse_period_adc % window_size) begin
|
||||
$error("-reference_signal- pulse_period_adc must be multiple of window_size: %0d %% %0d = %0d", pulse_period_adc, window_size, pulse_period_adc % window_size);
|
||||
$finish;
|
||||
end
|
||||
|
||||
result = new[sample_num];
|
||||
partial_sum = 0;
|
||||
|
||||
for (int i = 0; i < pulse_period_adc; i++) begin
|
||||
// var i in ADC timespace
|
||||
// i == 0 is a t0 of pulse generation and sampling
|
||||
current_signal_sample = (i*CLK_ADC_PERIOD <= pulse_width*CLK_DAC_PERIOD) ? ref_signal_active_voltage : ref_signal_zero_voltage;
|
||||
partial_sum += current_signal_sample;
|
||||
if (i % window_size == (window_size-1)) begin
|
||||
result[i / window_size] = partial_sum;
|
||||
partial_sum = 0;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
// Ôóíêöèÿ ïðîâåðêè ðàçìåðîâ âûáîðîê
|
||||
function automatic void check_size(
|
||||
input real a[],
|
||||
input real b[]
|
||||
);
|
||||
if (a.size() != b.size())
|
||||
$fatal(1, "Array size mismatch: %0d != %0d",
|
||||
a.size(), b.size());
|
||||
|
||||
if (a.size() == 0)
|
||||
$error(1, "Empty array");
|
||||
endfunction
|
||||
|
||||
// Ñðåäíåå ïî âûáîðêå
|
||||
function automatic real array_mean(
|
||||
input real a[]
|
||||
);
|
||||
real sum = 0.0;
|
||||
|
||||
foreach (a[i])
|
||||
sum += a[i];
|
||||
|
||||
return sum / a.size();
|
||||
endfunction
|
||||
|
||||
// MSE äâóõ âûáîðîê
|
||||
function automatic real calc_mse(
|
||||
input real a[],
|
||||
input real b[]
|
||||
);
|
||||
real sum = 0.0;
|
||||
|
||||
check_size(a, b);
|
||||
|
||||
foreach (a[i]) begin
|
||||
real err;
|
||||
err = a[i] - b[i];
|
||||
sum += err * err;
|
||||
end
|
||||
|
||||
return sum / a.size();
|
||||
endfunction
|
||||
|
||||
// NRMSE äâóõ âûáîðîê (íîðìèðîâàíèå RMSE)
|
||||
function automatic real calc_nrmse(
|
||||
input real a[],
|
||||
input real b[]
|
||||
);
|
||||
const real EPS = 1e-12;
|
||||
real mse, ms = 0;
|
||||
|
||||
mse = calc_mse(a, b);
|
||||
|
||||
foreach (a[i]) begin
|
||||
ms += a[i] * a[i];
|
||||
end
|
||||
ms /= a.size();
|
||||
|
||||
return $sqrt(mse / (ms + EPS));
|
||||
endfunction
|
||||
|
||||
// Ôóíêöèÿ ìîäóëÿ
|
||||
function automatic real abs_f(input real x);
|
||||
return (x < 0.0) ? -x : x;
|
||||
endfunction
|
||||
|
||||
// Ìàêñèìàëüíàÿ àáñîëþòíàÿ îøèáêà
|
||||
function automatic real calc_max_error(
|
||||
input real a[],
|
||||
input real b[]
|
||||
);
|
||||
real max_err = 0.0;
|
||||
|
||||
check_size(a, b);
|
||||
|
||||
foreach (a[i]) begin
|
||||
real err;
|
||||
|
||||
err = abs_f(a[i] - b[i]);
|
||||
|
||||
if (err > max_err)
|
||||
max_err = err;
|
||||
end
|
||||
|
||||
return max_err;
|
||||
endfunction
|
||||
|
||||
// Êîýôôèöèåíò êîððåëÿöèè Ïèðñîíà
|
||||
function automatic real calc_pearson(
|
||||
input real a[],
|
||||
input real b[]
|
||||
);
|
||||
real mean_a;
|
||||
real mean_b;
|
||||
real numerator = 0.0;
|
||||
real denom_a = 0.0;
|
||||
real denom_b = 0.0;
|
||||
|
||||
check_size(a, b);
|
||||
|
||||
mean_a = array_mean(a);
|
||||
mean_b = array_mean(b);
|
||||
|
||||
foreach (a[i]) begin
|
||||
real da;
|
||||
real db;
|
||||
|
||||
da = a[i] - mean_a;
|
||||
db = b[i] - mean_b;
|
||||
|
||||
numerator += da * db;
|
||||
denom_a += da * da;
|
||||
denom_b += db * db;
|
||||
end
|
||||
|
||||
if ((denom_a == 0.0) || (denom_b == 0.0))
|
||||
return 0.0;
|
||||
|
||||
return numerator / $sqrt(denom_a * denom_b);
|
||||
endfunction
|
||||
|
||||
// Âñïîìîãàòåëüíàÿ ôóíêöèÿ äëÿ âûâîäà ìàññèâà
|
||||
function automatic void display_array_f(input real a[]);
|
||||
$write("\t");
|
||||
foreach(a[i])
|
||||
$write("%f ", a[i]);
|
||||
$write("\n");
|
||||
endfunction
|
||||
|
||||
// Âñïîìîãàòåëüíàÿ ôóíêöèÿ äëÿ âûâîäà ìàññèâà
|
||||
function automatic void display_array(input int a[]);
|
||||
$write("\t");
|
||||
foreach(a[i])
|
||||
$write("%0d ", a[i]);
|
||||
$write("\n");
|
||||
endfunction
|
||||
|
||||
// Îñíîâíàÿ òàñêà òèïîâîãî òåñòà
|
||||
task automatic run_test_case(
|
||||
virtual axis_if#(8).tb ctrl_vif,
|
||||
virtual axis_if#(8).tb accum_vif,
|
||||
input int pulse_width,
|
||||
input int pulse_period,
|
||||
input int pulse_num,
|
||||
input int pulse_height,
|
||||
input int pulse_period_adc,
|
||||
input int window_size,
|
||||
input bit rand_recv_delays,
|
||||
input bit use_reset,
|
||||
output int result
|
||||
);
|
||||
int output_data[]; // raw accum values
|
||||
real output_signal_v[]; // accum values after voltage conversion
|
||||
real reference_signal_v[]; // reference signal voltage values
|
||||
real nrmse, pearson, max_err; // error and correlation metrics
|
||||
|
||||
if (use_reset) begin
|
||||
dut_soft_reset(ctrl_vif);
|
||||
#100;
|
||||
end
|
||||
|
||||
dut_send_system_config(
|
||||
.vif(ctrl_vif),
|
||||
.pulse_width(pulse_width),
|
||||
.pulse_period(pulse_period),
|
||||
.pulse_num(pulse_num),
|
||||
.pulse_height(pulse_height),
|
||||
.pulse_period_adc(pulse_period_adc),
|
||||
.window_size(window_size)
|
||||
);
|
||||
#100;
|
||||
|
||||
dut_start(ctrl_vif);
|
||||
|
||||
dut_read_output(
|
||||
.vif(accum_vif),
|
||||
.sample_num(pulse_period_adc),
|
||||
.window_size(window_size),
|
||||
.randomize_recv_delays(rand_recv_delays),
|
||||
.output_data(output_data)
|
||||
);
|
||||
// actual size of payload is pulse_period_adc / window_size
|
||||
output_signal_v = new[pulse_period_adc / window_size];
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("[TB] Output data stream");
|
||||
display_array(output_data);
|
||||
`endif
|
||||
|
||||
// voltage conversion
|
||||
begin
|
||||
// zero level for partial sum
|
||||
real zero_level_bias = window_size * virtual_adc.ZERO_CODE;
|
||||
// common voltage multiplier for step & amplifier
|
||||
real voltage_multiplier = virtual_adc.VOLTAGE_STEP / virtual_adc.VOLTAGE_GAIN;
|
||||
// array conversion
|
||||
foreach (output_signal_v[i]) begin
|
||||
real average_code_per_pulse = real'(output_data[i]) / pulse_num;
|
||||
output_signal_v[i] = (average_code_per_pulse - zero_level_bias) * voltage_multiplier;
|
||||
end
|
||||
end
|
||||
|
||||
reference_signal(
|
||||
.pulse_width(pulse_width),
|
||||
.pulse_height(pulse_height),
|
||||
.pulse_period_adc(pulse_period_adc),
|
||||
.window_size(window_size),
|
||||
.result(reference_signal_v)
|
||||
);
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("[TB] Output signal");
|
||||
display_array_f(output_signal_v);
|
||||
$display("[TB] Reference signal");
|
||||
display_array_f(reference_signal_v);
|
||||
`endif
|
||||
|
||||
nrmse = calc_nrmse(output_signal_v, reference_signal_v);
|
||||
pearson = calc_pearson(output_signal_v, reference_signal_v);
|
||||
max_err = calc_max_error(output_signal_v, reference_signal_v);
|
||||
|
||||
`ifdef DEBUG
|
||||
$display("[TB] Metrics:\n\tNRMSE = %0.4f\t|\tPearson = %0.4f\t|\tMax error = %0.4f", nrmse, pearson, max_err);
|
||||
`endif
|
||||
|
||||
// check metrics
|
||||
result = 0;
|
||||
// if (pearson < PEARSON_THRESHOLD)
|
||||
// result += 1;
|
||||
if (nrmse > NRMSE_THRESHOLD)
|
||||
result += 2;
|
||||
/*
|
||||
Max error not used in evaluation because of fast pulse edge falling
|
||||
resulting in plain difference between active signal level and zero level
|
||||
For ex.: zero_level = 0x00 = -5V. pulse_height = 2^14-1 = 0x3fff = 5V
|
||||
In some cases like jitter this may cause max error = 5 - (-5) = 10(V)
|
||||
This cases are hardly traceble, thus max error not used in eval.
|
||||
|
||||
Pearson not used in evaluation because it only shows correlation of changing signals. Tests broke on static signals.
|
||||
|
||||
Pearson and max err remain in test for info.
|
||||
*/
|
||||
endtask
|
||||
|
||||
//------------------------------------------------------------
|
||||
// ÎÑÍÎÂÍÎÉ ÏÐÎÖÅÑÑ ÒÅÑÒÈÐÎÂÀÍÈß
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
int result_flag;
|
||||
int total_failed_tests = 0, total_tests = 0;
|
||||
|
||||
$info("[TB] DUT initializaton");
|
||||
// Èíèöèàëèçàöèÿ
|
||||
request_ready = 0;
|
||||
rst_n = 0;
|
||||
#100;
|
||||
rst_n = 1;
|
||||
wait(mmcm_locked === 1'b1);
|
||||
#150;
|
||||
$info("[TB] MMCM locked");
|
||||
|
||||
// Meause periods because actual values hardcoded in IP
|
||||
fork
|
||||
`MEASURE_CLK(DUT.clk_sampler, CLK_ADC_PERIOD);
|
||||
`MEASURE_CLK(DUT.clk_generator, CLK_DAC_PERIOD);
|
||||
join
|
||||
$info("[TB] ADC & DAC clock periods measured: ADC_period = %0.3f, DAC_period = %0.3f", CLK_ADC_PERIOD, CLK_DAC_PERIOD);
|
||||
|
||||
// Òåñòû
|
||||
$info("[TB] Tests start");
|
||||
$info("[TB] Simple test run");
|
||||
run_test_case(
|
||||
.ctrl_vif(control_vif),
|
||||
.accum_vif(accumulator_vif),
|
||||
.pulse_width(4000),
|
||||
.pulse_period(10000),
|
||||
.pulse_num(5),
|
||||
.pulse_height(12000),
|
||||
.pulse_period_adc(6000),
|
||||
.window_size(10),
|
||||
.rand_recv_delays(1),
|
||||
.use_reset(1),
|
||||
.result(result_flag)
|
||||
);
|
||||
`ERR_CHECK
|
||||
|
||||
$info("[TB] Random test run");
|
||||
for (int i = 0; i < TEST_NUM; i++) begin
|
||||
int pulse_width, pulse_period, pulse_num, pulse_height, pulse_period_adc, window_size;
|
||||
bit rand_recv_delays, use_reset;
|
||||
|
||||
// Ãåíåðèðóåìûå ïàðàìåòðû
|
||||
pulse_period = $urandom_range(500, 5000);
|
||||
pulse_width = $urandom_range(50, pulse_period);
|
||||
pulse_num = $urandom_range(1, 10);
|
||||
pulse_height = $urandom_range(0, 2**DAC_DATA_WIDTH-1);
|
||||
window_size = $urandom_range(1, 11);
|
||||
pulse_period_adc = $urandom_range(50, N_MAX-1) * window_size;
|
||||
rand_recv_delays = 1;
|
||||
use_reset = 1; // ($urandom_range(0, 10) >= 9);
|
||||
|
||||
$display("Test #%0d", total_tests);
|
||||
`ifdef DEBUG
|
||||
$display("Parameters:\n\tpulse_width=%0d\n\tpulse_period=%0d\n\tpulse_num=%0d\n\tpulse_height=%0d\n\tpulse_period_adc=%0d\n\twindow_size=%0d\n\trand_recv_delays=%0d\n\tuse_reset=%0d",
|
||||
pulse_width, pulse_period, pulse_num, pulse_height, pulse_period_adc, window_size, rand_recv_delays, use_reset);
|
||||
`endif
|
||||
|
||||
run_test_case(
|
||||
.ctrl_vif(control_vif),
|
||||
.accum_vif(accumulator_vif),
|
||||
.pulse_width(pulse_width),
|
||||
.pulse_period(pulse_period),
|
||||
.pulse_num(pulse_num),
|
||||
.pulse_height(pulse_height),
|
||||
.pulse_period_adc(pulse_period_adc),
|
||||
.window_size(window_size),
|
||||
.rand_recv_delays(rand_recv_delays),
|
||||
.use_reset(use_reset),
|
||||
.result(result_flag)
|
||||
);
|
||||
|
||||
`ERR_CHECK
|
||||
if (result_flag) begin
|
||||
$display("Parameters:\n\tpulse_width=%0d\n\tpulse_period=%0d\n\tpulse_num=%0d\n\tpulse_height=%0d\n\tpulse_period_adc=%0d\n\twindow_size=%0d\n\trand_recv_delays=%0d\n\tuse_reset=%0d",
|
||||
pulse_width, pulse_period, pulse_num, pulse_height, pulse_period_adc, window_size, rand_recv_delays, use_reset);
|
||||
end
|
||||
end
|
||||
|
||||
$info("[TB] Corner case test run");
|
||||
run_test_case(
|
||||
.ctrl_vif(control_vif),
|
||||
.accum_vif(accumulator_vif),
|
||||
.pulse_width(0),
|
||||
.pulse_period(1000),
|
||||
.pulse_num(5),
|
||||
.pulse_height(12000),
|
||||
.pulse_period_adc(600),
|
||||
.window_size(10),
|
||||
.rand_recv_delays(0),
|
||||
.use_reset(1),
|
||||
.result(result_flag)
|
||||
);
|
||||
`ERR_CHECK
|
||||
|
||||
run_test_case(
|
||||
.ctrl_vif(control_vif),
|
||||
.accum_vif(accumulator_vif),
|
||||
.pulse_width(1000),
|
||||
.pulse_period(1000),
|
||||
.pulse_num(5),
|
||||
.pulse_height(12000),
|
||||
.pulse_period_adc(600),
|
||||
.window_size(10),
|
||||
.rand_recv_delays(0),
|
||||
.use_reset(1),
|
||||
.result(result_flag)
|
||||
);
|
||||
`ERR_CHECK
|
||||
|
||||
run_test_case(
|
||||
.ctrl_vif(control_vif),
|
||||
.accum_vif(accumulator_vif),
|
||||
.pulse_width(500),
|
||||
.pulse_period(1000),
|
||||
.pulse_num(5),
|
||||
.pulse_height(2**(DAC_DATA_WIDTH-1)),
|
||||
.pulse_period_adc(600),
|
||||
.window_size(10),
|
||||
.rand_recv_delays(0),
|
||||
.use_reset(1),
|
||||
.result(result_flag)
|
||||
);
|
||||
`ERR_CHECK
|
||||
|
||||
run_test_case(
|
||||
.ctrl_vif(control_vif),
|
||||
.accum_vif(accumulator_vif),
|
||||
.pulse_width(500),
|
||||
.pulse_period(1000),
|
||||
.pulse_num(5),
|
||||
.pulse_height(15000),
|
||||
.pulse_period_adc(10),
|
||||
.window_size(1),
|
||||
.rand_recv_delays(0),
|
||||
.use_reset(1),
|
||||
.result(result_flag)
|
||||
);
|
||||
`ERR_CHECK
|
||||
|
||||
$display("[TB] Tests done. [%0d/%0d] tests passed, %0d failed", total_tests - total_failed_tests, total_tests, total_failed_tests);
|
||||
if (!total_failed_tests)
|
||||
$display("[TB] ALL PASSED");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
+322
@@ -0,0 +1,322 @@
|
||||
|
||||
import dma_reg_pkg::*;
|
||||
|
||||
module tb_full_reflectometer #(
|
||||
// parameters for base reflectometer works
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned PACK_FACTOR = 1,
|
||||
parameter int unsigned PROCESS_MODE = 0,
|
||||
parameter int unsigned ZERO_LEVEL = 8192,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 64,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32,
|
||||
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0
|
||||
)(
|
||||
input logic ctrl_clk,
|
||||
input logic rst_n,
|
||||
output logic locked,
|
||||
|
||||
input logic [dma_reg_pkg::AXI_ADDR_WIDTH-1:0] s_axil_awaddr,
|
||||
input logic [2:0] s_axil_awprot,
|
||||
input logic s_axil_awvalid,
|
||||
output logic s_axil_awready,
|
||||
|
||||
input logic [AXI_DATA_WIDTH-1:0] s_axil_wdata,
|
||||
input logic [AXI_DATA_WIDTH/8-1:0] s_axil_wstrb,
|
||||
input logic s_axil_wvalid,
|
||||
output logic s_axil_wready,
|
||||
|
||||
output logic [1:0] s_axil_bresp,
|
||||
output logic s_axil_bvalid,
|
||||
input logic s_axil_bready,
|
||||
|
||||
input logic [dma_reg_pkg::AXI_ADDR_WIDTH-1:0] s_axil_araddr,
|
||||
input logic [2:0] s_axil_arprot,
|
||||
input logic s_axil_arvalid,
|
||||
output logic s_axil_arready,
|
||||
|
||||
output logic [AXI_DATA_WIDTH-1:0] s_axil_rdata,
|
||||
output logic [1:0] s_axil_rresp,
|
||||
output logic s_axil_rvalid,
|
||||
input logic s_axil_rready,
|
||||
|
||||
output wire [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata,
|
||||
output wire [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep,
|
||||
output wire m_axis_read_data_tvalid,
|
||||
input wire m_axis_read_data_tready,
|
||||
output wire m_axis_read_data_tlast,
|
||||
output wire [dma_reg_pkg::AXIS_ID_WIDTH-1:0] m_axis_read_data_tid,
|
||||
output wire [dma_reg_pkg::AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest,
|
||||
output wire [dma_reg_pkg::AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser,
|
||||
|
||||
input logic [AXI_ID_WIDTH-1:0] s_axi_awid,
|
||||
input logic [dma_reg_pkg::AXI_ADDR_WIDTH-1:0] s_axi_awaddr,
|
||||
input logic [7:0] s_axi_awlen,
|
||||
input logic [2:0] s_axi_awsize,
|
||||
input logic [1:0] s_axi_awburst,
|
||||
input logic s_axi_awlock,
|
||||
input logic [3:0] s_axi_awcache,
|
||||
input logic [2:0] s_axi_awprot,
|
||||
input logic [3:0] s_axi_awqos,
|
||||
input logic [3:0] s_axi_awregion,
|
||||
input logic [AXI_USER_WIDTH-1:0] s_axi_awuser,
|
||||
input logic s_axi_awvalid,
|
||||
output logic s_axi_awready,
|
||||
input logic [AXI_DATA_WIDTH-1:0] s_axi_wdata,
|
||||
input logic [AXI_DATA_WIDTH/8-1:0] s_axi_wstrb,
|
||||
input logic s_axi_wlast,
|
||||
input logic [AXI_USER_WIDTH-1:0] s_axi_wuser,
|
||||
input logic s_axi_wvalid,
|
||||
output logic s_axi_wready,
|
||||
output logic [AXI_ID_WIDTH-1:0] s_axi_bid,
|
||||
output logic [1:0] s_axi_bresp,
|
||||
output logic [AXI_USER_WIDTH-1:0] s_axi_buser,
|
||||
output logic s_axi_bvalid,
|
||||
input logic s_axi_bready,
|
||||
input logic [AXI_ID_WIDTH-1:0] s_axi_arid,
|
||||
input logic [dma_reg_pkg::AXI_ADDR_WIDTH-1:0] s_axi_araddr,
|
||||
input logic [7:0] s_axi_arlen,
|
||||
input logic [2:0] s_axi_arsize,
|
||||
input logic [1:0] s_axi_arburst,
|
||||
input logic s_axi_arlock,
|
||||
input logic [3:0] s_axi_arcache,
|
||||
input logic [2:0] s_axi_arprot,
|
||||
input logic [3:0] s_axi_arqos,
|
||||
input logic [3:0] s_axi_arregion,
|
||||
input logic [AXI_USER_WIDTH-1:0] s_axi_aruser,
|
||||
input logic s_axi_arvalid,
|
||||
output logic s_axi_arready,
|
||||
output logic [AXI_ID_WIDTH-1:0] s_axi_rid,
|
||||
output logic [AXI_DATA_WIDTH-1:0] s_axi_rdata,
|
||||
output logic [1:0] s_axi_rresp,
|
||||
output logic s_axi_rlast,
|
||||
output logic [AXI_USER_WIDTH-1:0] s_axi_ruser,
|
||||
output logic s_axi_rvalid,
|
||||
input logic s_axi_rready,
|
||||
|
||||
// DAC
|
||||
output wire dac_clk_o,
|
||||
output wire [DAC_DATA_WIDTH-1:0] dac_data,
|
||||
output wire dac_wrt,
|
||||
|
||||
// ADC
|
||||
output wire adc_clk_o,
|
||||
input wire [ADC_DATA_WIDTH-1:0] adc_data,
|
||||
input wire adc_otr
|
||||
|
||||
|
||||
);
|
||||
// ---------------------------------------------------------------------------
|
||||
// AXI-Lite flat -> axi4l_if
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
axi4l_if #(
|
||||
.ADDR_W(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.DATA_W(AXI_DATA_WIDTH),
|
||||
.USER_W(AXI_USER_WIDTH)
|
||||
) axil_bus (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axi4l_flat_to_if #(
|
||||
.ADDR_W(g_pkg::AXI_ADDR_WIDTH),
|
||||
.DATA_W(AXI_DATA_WIDTH),
|
||||
.USER_W(AXI_USER_WIDTH)
|
||||
) u_axil_flat_to_if (
|
||||
.s_axil_awaddr (s_axil_awaddr),
|
||||
.s_axil_awprot (s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
|
||||
.s_axil_wdata (s_axil_wdata),
|
||||
.s_axil_wstrb (s_axil_wstrb),
|
||||
.s_axil_wvalid (s_axil_wvalid),
|
||||
.s_axil_wready (s_axil_wready),
|
||||
|
||||
.s_axil_bresp (s_axil_bresp),
|
||||
.s_axil_bvalid (s_axil_bvalid),
|
||||
.s_axil_bready (s_axil_bready),
|
||||
|
||||
.s_axil_araddr (s_axil_araddr),
|
||||
.s_axil_arprot (s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
|
||||
.s_axil_rdata (s_axil_rdata),
|
||||
.s_axil_rresp (s_axil_rresp),
|
||||
.s_axil_rvalid (s_axil_rvalid),
|
||||
.s_axil_rready (s_axil_rready),
|
||||
|
||||
.m_axil(axil_bus)
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AXIS interfaces for the updated controller_wrapper_axil
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// AXIS READ DMA MASTER output
|
||||
axis_if #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W (dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) dma_read_data (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
logic [AXIS_KEEP_WIDTH-1:0] unused_read_tstrb;
|
||||
|
||||
axis_if_to_flat #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W (dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) u_read_data_if_to_flat (
|
||||
.s_axis(dma_read_data),
|
||||
|
||||
.m_axis_tdata (m_axis_read_data_tdata),
|
||||
.m_axis_tkeep (m_axis_read_data_tkeep),
|
||||
.m_axis_tstrb (unused_read_tstrb),
|
||||
.m_axis_tlast (m_axis_read_data_tlast),
|
||||
.m_axis_tid (m_axis_read_data_tid),
|
||||
.m_axis_tdest (m_axis_read_data_tdest),
|
||||
.m_axis_tuser (m_axis_read_data_tuser),
|
||||
.m_axis_tvalid(m_axis_read_data_tvalid),
|
||||
.m_axis_tready(m_axis_read_data_tready)
|
||||
);
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_W(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.DATA_W(AXI_DATA_WIDTH),
|
||||
.ID_W (AXI_ID_WIDTH),
|
||||
.USER_W(AXI_USER_WIDTH)
|
||||
) m_axi (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axi4_flat_to_if #(
|
||||
.ADDR_W(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.DATA_W(AXI_DATA_WIDTH),
|
||||
.ID_W(AXI_ID_WIDTH),
|
||||
.USER_W(AXI_USER_WIDTH)
|
||||
) u_axi_flat_to_if
|
||||
(
|
||||
.s_axi_awid(s_axi_awid),
|
||||
.s_axi_awaddr(s_axi_awaddr),
|
||||
.s_axi_awlen(s_axi_awlen),
|
||||
.s_axi_awsize(s_axi_awsize),
|
||||
.s_axi_awburst(s_axi_awburst),
|
||||
.s_axi_awlock(s_axi_awlock),
|
||||
.s_axi_awcache(s_axi_awcache),
|
||||
.s_axi_awprot(s_axi_awprot),
|
||||
.s_axi_awqos(s_axi_awqos),
|
||||
.s_axi_awregion(s_axi_awregion),
|
||||
.s_axi_awuser(s_axi_awuser),
|
||||
.s_axi_awvalid(s_axi_awvalid),
|
||||
.s_axi_awready(s_axi_awready),
|
||||
.s_axi_wdata(s_axi_wdata),
|
||||
.s_axi_wstrb(s_axi_wstrb),
|
||||
.s_axi_wlast(s_axi_wlast),
|
||||
.s_axi_wuser(s_axi_wuser),
|
||||
.s_axi_wvalid(s_axi_wvalid),
|
||||
.s_axi_wready(s_axi_wready),
|
||||
.s_axi_bid(s_axi_bid),
|
||||
.s_axi_bresp(s_axi_bresp),
|
||||
.s_axi_buser(s_axi_buser),
|
||||
.s_axi_bvalid(s_axi_bvalid),
|
||||
.s_axi_bready(s_axi_bready),
|
||||
.s_axi_arid(s_axi_arid),
|
||||
.s_axi_araddr(s_axi_araddr),
|
||||
.s_axi_arlen(s_axi_arlen),
|
||||
.s_axi_arsize(s_axi_arsize),
|
||||
.s_axi_arburst(s_axi_arburst),
|
||||
.s_axi_arlock(s_axi_arlock),
|
||||
.s_axi_arcache(s_axi_arcache),
|
||||
.s_axi_arprot(s_axi_arprot),
|
||||
.s_axi_arqos(s_axi_arqos),
|
||||
.s_axi_arregion(s_axi_arregion),
|
||||
.s_axi_aruser(s_axi_aruser),
|
||||
.s_axi_arvalid(s_axi_arvalid),
|
||||
.s_axi_arready(s_axi_arready),
|
||||
.s_axi_rid(s_axi_rid),
|
||||
.s_axi_rdata(s_axi_rdata),
|
||||
.s_axi_rresp(s_axi_rresp),
|
||||
.s_axi_rlast(s_axi_rlast),
|
||||
.s_axi_ruser(s_axi_ruser),
|
||||
.s_axi_rvalid(s_axi_rvalid),
|
||||
.s_axi_rready(s_axi_rready),
|
||||
.m_axi(m_axi)
|
||||
);
|
||||
|
||||
reflectometer_and_dma_wrapper #(
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
|
||||
.AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED),
|
||||
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE),
|
||||
.ZERO_LEVEL(ZERO_LEVEL),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RD_FIFO_WIDTH(RD_FIFO_WIDTH)
|
||||
) dut (
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.rst_n(rst_n),
|
||||
.locked(locked),
|
||||
.s_axil(axil_bus),
|
||||
|
||||
.m_axi(m_axi),
|
||||
|
||||
.m_axis_read_data(dma_read_data),
|
||||
|
||||
.dac_clk_o(clk_dac),
|
||||
.dac_data(dac_data),
|
||||
.dac_wrt(dac_wrt),
|
||||
.adc_clk_o(clk_adc),
|
||||
.adc_data(adc_data),
|
||||
.adc_otr(adc_otr)
|
||||
);
|
||||
|
||||
|
||||
|
||||
endmodule : tb_full_reflectometer
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
|
||||
import dma_reg_pkg::*;
|
||||
|
||||
module tb_full_reflectometer #(
|
||||
// parameters for base reflectometer works
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned PACK_FACTOR = 1,
|
||||
parameter int unsigned PROCESS_MODE = 0,
|
||||
parameter int unsigned ZERO_LEVEL = 8192,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 64,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32,
|
||||
|
||||
// parameters for DMA and interfaces
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0
|
||||
)(
|
||||
input logic ctrl_clk,
|
||||
input logic rst,
|
||||
output logic locked,
|
||||
|
||||
input logic [ADDR_W-1:0] s_axil_awaddr,
|
||||
input logic [2:0] s_axil_awprot,
|
||||
input logic s_axil_awvalid,
|
||||
output logic s_axil_awready,
|
||||
|
||||
input logic [DATA_W-1:0] s_axil_wdata,
|
||||
input logic [DATA_W/8-1:0] s_axil_wstrb,
|
||||
input logic s_axil_wvalid,
|
||||
output logic s_axil_wready,
|
||||
|
||||
output logic [1:0] s_axil_bresp,
|
||||
output logic s_axil_bvalid,
|
||||
input logic s_axil_bready,
|
||||
|
||||
input logic [ADDR_W-1:0] s_axil_araddr,
|
||||
input logic [2:0] s_axil_arprot,
|
||||
input logic s_axil_arvalid,
|
||||
output logic s_axil_arready,
|
||||
|
||||
output logic [DATA_W-1:0] s_axil_rdata,
|
||||
output logic [1:0] s_axil_rresp,
|
||||
output logic s_axil_rvalid,
|
||||
input logic s_axil_rready,
|
||||
|
||||
output wire [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata,
|
||||
output wire [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep,
|
||||
output wire m_axis_read_data_tvalid,
|
||||
input wire m_axis_read_data_tready,
|
||||
output wire m_axis_read_data_tlast,
|
||||
output wire [dma_reg_pkg::AXIS_ID_WIDTH-1:0] m_axis_read_data_tid,
|
||||
output wire [dma_reg_pkg::AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest,
|
||||
output wire [dma_reg_pkg::AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser
|
||||
);
|
||||
|
||||
logic rst_n;
|
||||
|
||||
assign rst_n = ~rst;
|
||||
|
||||
wire clk_adc;
|
||||
wire adc_otr;
|
||||
wire [ADC_DATA_WIDTH-1:0] adc_data;
|
||||
|
||||
wire clk_dac;
|
||||
wire dac_wrt;
|
||||
wire [DAC_DATA_WIDTH-1:0] dac_data;
|
||||
|
||||
real signal_voltage;
|
||||
|
||||
virtual_dac_model #( // default voltage range is +/- 5V
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
) virtual_dac (
|
||||
.clk_i(clk_dac),
|
||||
.wrt_i(dac_wrt),
|
||||
.data_i(dac_data),
|
||||
.voltage_o(signal_voltage)
|
||||
);
|
||||
|
||||
virtual_adc_model #( // default voltage range is +/- 5V
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH)
|
||||
) virtual_adc (
|
||||
.clk_i(clk_adc),
|
||||
.voltage_i(signal_voltage),
|
||||
.otr_o(adc_otr),
|
||||
.data_o(adc_data)
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AXI-Lite flat -> axi4l_if
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
axi4l_if #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W)
|
||||
) axil_bus (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axi4l_flat_to_if #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W)
|
||||
) u_axil_flat_to_if (
|
||||
.s_axil_awaddr (s_axil_awaddr),
|
||||
.s_axil_awprot (s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
|
||||
.s_axil_wdata (s_axil_wdata),
|
||||
.s_axil_wstrb (s_axil_wstrb),
|
||||
.s_axil_wvalid (s_axil_wvalid),
|
||||
.s_axil_wready (s_axil_wready),
|
||||
|
||||
.s_axil_bresp (s_axil_bresp),
|
||||
.s_axil_bvalid (s_axil_bvalid),
|
||||
.s_axil_bready (s_axil_bready),
|
||||
|
||||
.s_axil_araddr (s_axil_araddr),
|
||||
.s_axil_arprot (s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
|
||||
.s_axil_rdata (s_axil_rdata),
|
||||
.s_axil_rresp (s_axil_rresp),
|
||||
.s_axil_rvalid (s_axil_rvalid),
|
||||
.s_axil_rready (s_axil_rready),
|
||||
|
||||
.m_axil(axil_bus)
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AXIS interfaces for the updated controller_wrapper_axil
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// AXIS READ DMA MASTER output
|
||||
axis_if #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W (dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) dma_read_data (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
logic [AXIS_KEEP_WIDTH-1:0] unused_read_tstrb;
|
||||
|
||||
axis_if_to_flat #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W (dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) u_read_data_if_to_flat (
|
||||
.s_axis(dma_read_data),
|
||||
|
||||
.m_axis_tdata (m_axis_read_data_tdata),
|
||||
.m_axis_tkeep (m_axis_read_data_tkeep),
|
||||
.m_axis_tstrb (unused_read_tstrb),
|
||||
.m_axis_tlast (m_axis_read_data_tlast),
|
||||
.m_axis_tid (m_axis_read_data_tid),
|
||||
.m_axis_tdest (m_axis_read_data_tdest),
|
||||
.m_axis_tuser (m_axis_read_data_tuser),
|
||||
.m_axis_tvalid(m_axis_read_data_tvalid),
|
||||
.m_axis_tready(m_axis_read_data_tready)
|
||||
);
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_W(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.DATA_W(AXI_DATA_WIDTH),
|
||||
.ID_W (AXI_ID_WIDTH),
|
||||
.USER_W(AXI_USER_WIDTH)
|
||||
) m_axi (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
reflectometer_and_dma_wrapper #(
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
|
||||
.AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED),
|
||||
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE),
|
||||
.ZERO_LEVEL(ZERO_LEVEL),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RD_FIFO_WIDTH(RD_FIFO_WIDTH)
|
||||
) dut (
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.rst_n(rst_n),
|
||||
.locked(locked),
|
||||
.s_axil(axil_bus),
|
||||
|
||||
.m_axi(m_axi),
|
||||
|
||||
.m_axis_read_data(dma_read_data),
|
||||
|
||||
.dac_clk_o(clk_dac),
|
||||
.dac_data(dac_data),
|
||||
.dac_wrt(dac_wrt),
|
||||
.adc_clk_o(clk_adc),
|
||||
.adc_data(adc_data),
|
||||
.adc_otr(adc_otr)
|
||||
);
|
||||
|
||||
axi_ram_wrapper
|
||||
#(
|
||||
.DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.ADDR_WIDTH(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.ID_WIDTH(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.PIPELINE_OUTPUT(PIPELINE_OUTPUT)
|
||||
) axi_ram_wrapper_inst
|
||||
(
|
||||
.clk(ctrl_clk),
|
||||
.rst(!rst_n),
|
||||
.s_axi(m_axi)
|
||||
);
|
||||
|
||||
|
||||
|
||||
endmodule : tb_full_reflectometer
|
||||
@@ -0,0 +1,55 @@
|
||||
TOPLEVEL_LANG = verilog
|
||||
SIM ?= questa
|
||||
WAVES = 1
|
||||
WLF_FILE := $(SIM_BUILD)/waves.wlf
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
|
||||
RTL_DIR = $(PWD)/../src
|
||||
RTL_ACCUM_DIR = $(PWD)/../src/accum/src
|
||||
LIBS_DIR = $(PWD)/../../../external/rtl_libs
|
||||
|
||||
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi_pkg.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/dma_reg_pkg.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi_if.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axis_if.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axis_if_to_flat.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi4l_flat_to_if.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/axi_reg/axi4l_reg_map.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma_rd.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma_wr.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_ram.v
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi_ram_wrapper.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/controller.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/dma_controller.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/shaper_axis_desc.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/shaper_axis_status.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/controller_wrapper_axil.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi4l_reg_map_controller_pkg.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axis_defaults_helper.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi4l_reg_map_controller.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi_dma_wrapper_if.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/wrapper_controller_dma.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/adder.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/out_axis_fifo.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/accum.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/accum_top.sv
|
||||
VERILOG_SOURCES += $(PWD)/tb_reflectometer_and_dma_wrapper.sv
|
||||
VERILOG_SOURCES += $(PWD)/sim_top.sv
|
||||
VERILOG_SOURCES += /mnt/c/Xilinx/Vivado/2021.2/data/verilog/src/glbl.v
|
||||
|
||||
TOPLEVEL = sim_top
|
||||
MODULE = test_reflectometer_and_dma
|
||||
|
||||
|
||||
ifeq ($(SIM),questa)
|
||||
SIM_ARGS += -L xpm
|
||||
SIM_ARGS += -wlf $(WLF_FILE)
|
||||
COMPILE_ARGS += +acc
|
||||
endif
|
||||
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
@@ -0,0 +1,67 @@
|
||||
module axi_ram_wrapper
|
||||
#(
|
||||
parameter int unsigned DATA_WIDTH = 32,
|
||||
parameter int unsigned ADDR_WIDTH = 16,
|
||||
parameter int unsigned ID_WIDTH = 8,
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0
|
||||
)
|
||||
(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
axi4_if.slave s_axi
|
||||
);
|
||||
|
||||
logic [1:0] ram_bresp;
|
||||
logic [1:0] ram_rresp;
|
||||
|
||||
|
||||
assign s_axi.resp.b.resp = axi_pkg::axi_resp_t'(ram_bresp);
|
||||
assign s_axi.resp.r.resp = axi_pkg::axi_resp_t'(ram_rresp);
|
||||
|
||||
axi_ram
|
||||
#(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.ADDR_WIDTH(ADDR_WIDTH),
|
||||
.ID_WIDTH(ID_WIDTH),
|
||||
.PIPELINE_OUTPUT(PIPELINE_OUTPUT)
|
||||
) axi_ram_inst
|
||||
(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axi_awid(s_axi.req.aw.id),
|
||||
.s_axi_awaddr(s_axi.req.aw.addr),
|
||||
.s_axi_awlen(s_axi.req.aw.len),
|
||||
.s_axi_awsize(s_axi.req.aw.size),
|
||||
.s_axi_awburst(s_axi.req.aw.burst),
|
||||
.s_axi_awlock(s_axi.req.aw.lock),
|
||||
.s_axi_awcache(s_axi.req.aw.cache),
|
||||
.s_axi_awprot(s_axi.req.aw.prot),
|
||||
.s_axi_awvalid(s_axi.req.aw.valid),
|
||||
.s_axi_awready(s_axi.resp.aw_ready),
|
||||
.s_axi_wdata(s_axi.req.w.data),
|
||||
.s_axi_wstrb(s_axi.req.w.strb),
|
||||
.s_axi_wlast(s_axi.req.w.last),
|
||||
.s_axi_wvalid(s_axi.req.w.valid),
|
||||
.s_axi_wready(s_axi.resp.w_ready),
|
||||
.s_axi_bid(s_axi.resp.b.id),
|
||||
.s_axi_bresp(ram_bresp),
|
||||
.s_axi_bvalid(s_axi.resp.b.valid),
|
||||
.s_axi_bready(s_axi.req.b_ready),
|
||||
.s_axi_arid(s_axi.req.ar.id),
|
||||
.s_axi_araddr(s_axi.req.ar.addr),
|
||||
.s_axi_arlen(s_axi.req.ar.len),
|
||||
.s_axi_arsize(s_axi.req.ar.size),
|
||||
.s_axi_arburst(s_axi.req.ar.burst),
|
||||
.s_axi_arlock(s_axi.req.ar.lock),
|
||||
.s_axi_arcache(s_axi.req.ar.cache),
|
||||
.s_axi_arprot(s_axi.req.ar.prot),
|
||||
.s_axi_arvalid(s_axi.req.ar.valid),
|
||||
.s_axi_arready(s_axi.resp.ar_ready),
|
||||
.s_axi_rid(s_axi.resp.r.id),
|
||||
.s_axi_rdata(s_axi.resp.r.data),
|
||||
.s_axi_rresp(ram_rresp),
|
||||
.s_axi_rlast(s_axi.resp.r.last),
|
||||
.s_axi_rvalid(s_axi.resp.r.valid),
|
||||
.s_axi_rready(s_axi.req.r_ready)
|
||||
);
|
||||
endmodule
|
||||
@@ -0,0 +1,142 @@
|
||||
module sim_top
|
||||
#(
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
|
||||
parameter int unsigned DAC_DATA_WIDTH = 12,
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 64,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32
|
||||
)(
|
||||
input logic ctrl_clk,
|
||||
input logic rst,
|
||||
|
||||
input logic [ADDR_W-1:0] s_axil_awaddr,
|
||||
input logic [2:0] s_axil_awprot,
|
||||
input logic s_axil_awvalid,
|
||||
output logic s_axil_awready,
|
||||
|
||||
input logic [DATA_W-1:0] s_axil_wdata,
|
||||
input logic [DATA_W/8-1:0] s_axil_wstrb,
|
||||
input logic s_axil_wvalid,
|
||||
output logic s_axil_wready,
|
||||
|
||||
output logic [1:0] s_axil_bresp,
|
||||
output logic s_axil_bvalid,
|
||||
input logic s_axil_bready,
|
||||
|
||||
input logic [ADDR_W-1:0] s_axil_araddr,
|
||||
input logic [2:0] s_axil_arprot,
|
||||
input logic s_axil_arvalid,
|
||||
output logic s_axil_arready,
|
||||
|
||||
output logic [DATA_W-1:0] s_axil_rdata,
|
||||
output logic [1:0] s_axil_rresp,
|
||||
output logic s_axil_rvalid,
|
||||
input logic s_axil_rready,
|
||||
|
||||
output wire [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata,
|
||||
output wire [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep,
|
||||
output wire m_axis_read_data_tvalid,
|
||||
input wire m_axis_read_data_tready,
|
||||
output wire m_axis_read_data_tlast,
|
||||
output wire [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid,
|
||||
output wire [dma_reg_pkg::AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest,
|
||||
output wire [dma_reg_pkg::AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser,
|
||||
|
||||
input wire [ADC_DATA_WIDTH-1:0] sampler_m_axis_tdata,
|
||||
input wire sampler_m_axis_tvalid
|
||||
);
|
||||
|
||||
glbl glbl();
|
||||
|
||||
|
||||
tb_controller_wrapper_axil
|
||||
#(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W),
|
||||
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_ID_WIDTH(AXI_ID_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
|
||||
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED),
|
||||
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RD_FIFO_WIDTH(RD_FIFO_WIDTH)
|
||||
) dut (
|
||||
.ctrl_clk (ctrl_clk),
|
||||
.rst (rst),
|
||||
|
||||
.s_axil_awaddr (s_axil_awaddr),
|
||||
.s_axil_awprot (s_axil_awprot),
|
||||
.s_axil_awvalid (s_axil_awvalid),
|
||||
.s_axil_awready (s_axil_awready),
|
||||
|
||||
.s_axil_wdata (s_axil_wdata),
|
||||
.s_axil_wstrb (s_axil_wstrb),
|
||||
.s_axil_wvalid (s_axil_wvalid),
|
||||
.s_axil_wready (s_axil_wready),
|
||||
|
||||
.s_axil_bresp (s_axil_bresp),
|
||||
.s_axil_bvalid (s_axil_bvalid),
|
||||
.s_axil_bready (s_axil_bready),
|
||||
|
||||
.s_axil_araddr (s_axil_araddr),
|
||||
.s_axil_arprot (s_axil_arprot),
|
||||
.s_axil_arvalid (s_axil_arvalid),
|
||||
.s_axil_arready (s_axil_arready),
|
||||
|
||||
.s_axil_rdata (s_axil_rdata),
|
||||
.s_axil_rresp (s_axil_rresp),
|
||||
.s_axil_rvalid (s_axil_rvalid),
|
||||
.s_axil_rready (s_axil_rready),
|
||||
|
||||
.m_axis_read_data_tdata (m_axis_read_data_tdata),
|
||||
.m_axis_read_data_tkeep (m_axis_read_data_tkeep),
|
||||
.m_axis_read_data_tvalid (m_axis_read_data_tvalid),
|
||||
.m_axis_read_data_tready (m_axis_read_data_tready),
|
||||
.m_axis_read_data_tlast (m_axis_read_data_tlast),
|
||||
.m_axis_read_data_tid (m_axis_read_data_tid),
|
||||
.m_axis_read_data_tdest (m_axis_read_data_tdest),
|
||||
.m_axis_read_data_tuser (m_axis_read_data_tuser),
|
||||
|
||||
.sampler_m_axis_tdata (sampler_m_axis_tdata),
|
||||
.sampler_m_axis_tvalid (sampler_m_axis_tvalid)
|
||||
);
|
||||
|
||||
endmodule
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
|
||||
import dma_reg_pkg::*;
|
||||
|
||||
module tb_controller_wrapper_axil #(
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
|
||||
parameter int unsigned DAC_DATA_WIDTH = 12,
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 64,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32
|
||||
)(
|
||||
input logic ctrl_clk,
|
||||
//input logic adc_clk_in,
|
||||
//input logic dac_clk_in,
|
||||
input logic rst,
|
||||
|
||||
input logic [ADDR_W-1:0] s_axil_awaddr,
|
||||
input logic [2:0] s_axil_awprot,
|
||||
input logic s_axil_awvalid,
|
||||
output logic s_axil_awready,
|
||||
|
||||
input logic [DATA_W-1:0] s_axil_wdata,
|
||||
input logic [DATA_W/8-1:0] s_axil_wstrb,
|
||||
input logic s_axil_wvalid,
|
||||
output logic s_axil_wready,
|
||||
|
||||
output logic [1:0] s_axil_bresp,
|
||||
output logic s_axil_bvalid,
|
||||
input logic s_axil_bready,
|
||||
|
||||
input logic [ADDR_W-1:0] s_axil_araddr,
|
||||
input logic [2:0] s_axil_arprot,
|
||||
input logic s_axil_arvalid,
|
||||
output logic s_axil_arready,
|
||||
|
||||
output logic [DATA_W-1:0] s_axil_rdata,
|
||||
output logic [1:0] s_axil_rresp,
|
||||
output logic s_axil_rvalid,
|
||||
input logic s_axil_rready,
|
||||
|
||||
output wire [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata,
|
||||
output wire [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep,
|
||||
output wire m_axis_read_data_tvalid,
|
||||
input wire m_axis_read_data_tready,
|
||||
output wire m_axis_read_data_tlast,
|
||||
output wire [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid,
|
||||
output wire [dma_reg_pkg::AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest,
|
||||
output wire [dma_reg_pkg::AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser,
|
||||
|
||||
input wire [ADC_DATA_WIDTH-1:0] sampler_m_axis_tdata,
|
||||
input wire sampler_m_axis_tvalid
|
||||
);
|
||||
|
||||
logic dac_clk_in;
|
||||
logic adc_clk_in;
|
||||
assign dac_clk_in = ctrl_clk;
|
||||
assign adc_clk_in = ctrl_clk;
|
||||
|
||||
logic rst_n;
|
||||
|
||||
assign rst_n = ~rst;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AXI-Lite flat -> axi4l_if
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
axi4l_if #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W)
|
||||
) axil_bus (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axi4l_flat_to_if #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W)
|
||||
) u_axil_flat_to_if (
|
||||
.s_axil_awaddr (s_axil_awaddr),
|
||||
.s_axil_awprot (s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
|
||||
.s_axil_wdata (s_axil_wdata),
|
||||
.s_axil_wstrb (s_axil_wstrb),
|
||||
.s_axil_wvalid (s_axil_wvalid),
|
||||
.s_axil_wready (s_axil_wready),
|
||||
|
||||
.s_axil_bresp (s_axil_bresp),
|
||||
.s_axil_bvalid (s_axil_bvalid),
|
||||
.s_axil_bready (s_axil_bready),
|
||||
|
||||
.s_axil_araddr (s_axil_araddr),
|
||||
.s_axil_arprot (s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
|
||||
.s_axil_rdata (s_axil_rdata),
|
||||
.s_axil_rresp (s_axil_rresp),
|
||||
.s_axil_rvalid (s_axil_rvalid),
|
||||
.s_axil_rready (s_axil_rready),
|
||||
|
||||
.m_axil(axil_bus)
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AXIS interfaces for the updated controller_wrapper_axil
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// AXIS READ DMA MASTER output
|
||||
axis_if #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W (dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) dma_read_data (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
logic [AXIS_KEEP_WIDTH-1:0] unused_read_tstrb;
|
||||
|
||||
axis_if_to_flat #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W (dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) u_read_data_if_to_flat (
|
||||
.s_axis(dma_read_data),
|
||||
|
||||
.m_axis_tdata (m_axis_read_data_tdata),
|
||||
.m_axis_tkeep (m_axis_read_data_tkeep),
|
||||
.m_axis_tstrb (unused_read_tstrb),
|
||||
.m_axis_tlast (m_axis_read_data_tlast),
|
||||
.m_axis_tid (m_axis_read_data_tid),
|
||||
.m_axis_tdest (m_axis_read_data_tdest),
|
||||
.m_axis_tuser (m_axis_read_data_tuser),
|
||||
.m_axis_tvalid(m_axis_read_data_tvalid),
|
||||
.m_axis_tready(m_axis_read_data_tready)
|
||||
);
|
||||
|
||||
|
||||
wrapper_controller_dma_accum #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W),
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_ID_WIDTH(AXI_ID_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED),
|
||||
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RD_FIFO_WIDTH(RD_FIFO_WIDTH)
|
||||
) dut (
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.clk_generator(dac_clk_in),
|
||||
.clk_sampler(adc_clk_in),
|
||||
.rst_n(rst_n),
|
||||
.s_axil(axil_bus),
|
||||
|
||||
.sampler_m_axis_tdata(sampler_m_axis_tdata),
|
||||
.sampler_m_axis_tvalid(sampler_m_axis_tvalid),
|
||||
|
||||
.m_axis_read_data(dma_read_data)
|
||||
);
|
||||
|
||||
endmodule : tb_controller_wrapper_axil
|
||||
+546
@@ -0,0 +1,546 @@
|
||||
import cocotb
|
||||
import random
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotbext.axi import AxiLiteBus, AxiLiteMaster
|
||||
from cocotbext.axi import AxiStreamBus, AxiStreamSink, AxiStreamFrame
|
||||
|
||||
|
||||
# Register indexes from axi4l_reg_map_controller_pkg.sv
|
||||
REG_CONTROL = 0
|
||||
REG_STATUS = 1
|
||||
REG_DAC_WIDTH = 2
|
||||
REG_DAC_PERIOD = 3
|
||||
REG_DAC_PULSE_NUM = 4
|
||||
REG_DAC_PULSE_HEIGHT = 5
|
||||
REG_ADC_PERIOD = 6
|
||||
REG_WINDOW_SIZE = 7
|
||||
REG_ERROR = 8
|
||||
REG_DESC_READ_ADDR = 9
|
||||
REG_DESC_READ_LEN = 10
|
||||
REG_DESC_READ_CONFIG = 11
|
||||
REG_READ_STATUS = 12
|
||||
REG_DESC_WRITE_ADDR = 13
|
||||
REG_DESC_WRITE_LEN_AND_TAG = 14
|
||||
REG_STATUS_WRITE_LEN = 15
|
||||
REG_STATUS_WRITE_CONFIG = 16
|
||||
|
||||
|
||||
# REG_CONTROL pulse bits
|
||||
CTRL_START = 1 << 0
|
||||
CTRL_RST_SOFT = 1 << 1
|
||||
CTRL_CFG_BUS_VALID = 1 << 2
|
||||
CTRL_SEND_DESC_READ = 1 << 3
|
||||
CTRL_SEND_DESC_WRITE = 1 << 4
|
||||
CTRL_TAKE_STATUS_READ = 1 << 5
|
||||
CTRL_TAKE_STATUS_WRITE = 1 << 6
|
||||
|
||||
# REG_STATUS bits
|
||||
STATUS_BUSY = 1 << 0
|
||||
STATUS_PROCESSING_DONE = 1 << 1
|
||||
|
||||
STATUS_DESC_READ_BUSY = 1 << 2
|
||||
STATUS_DESC_WRITE_BUSY = 1 << 3
|
||||
STATUS_STATUS_READ_BUSY = 1 << 4
|
||||
STATUS_STATUS_WRITE_BUSY = 1 << 5
|
||||
|
||||
STATUS_DESC_READ_HS = 1 << 6
|
||||
STATUS_DESC_WRITE_HS = 1 << 7
|
||||
STATUS_STATUS_READ_HS = 1 << 8
|
||||
STATUS_STATUS_WRITE_HS = 1 << 9
|
||||
|
||||
# PARAMETERS for accumulator reference model
|
||||
|
||||
DAC_DATA_WIDTH = 14
|
||||
ADC_DATA_WIDTH = 12
|
||||
PACK_FACTOR = 1
|
||||
PROCESS_MODE = 0
|
||||
ZERO_LEVEL = 8192
|
||||
ACCUM_WIDTH = 32
|
||||
N_MAX = 4096
|
||||
PACKET_SIZE = 1024
|
||||
RD_FIFO_WIDTH = 32
|
||||
|
||||
|
||||
def reg_addr(reg_index: int) -> int:
|
||||
# AXI-Lite uses byte addresses, 32-bit registers are spaced by 4 bytes.
|
||||
return reg_index * 4
|
||||
|
||||
|
||||
def u32(value: int) -> bytes:
|
||||
return int(value & 0xFFFFFFFF).to_bytes(4, "little")
|
||||
|
||||
|
||||
class TB:
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
cocotb.start_soon(Clock(dut.ctrl_clk, 10, unit="ns").start())
|
||||
|
||||
# cocotb.start_soon(Clock(dut.adc_clk_in, 15, unit="ns").start())
|
||||
|
||||
# cocotb.start_soon(Clock(dut.dac_clk_in, 8, unit="ns").start())
|
||||
|
||||
self.axil = AxiLiteMaster(
|
||||
AxiLiteBus.from_prefix(dut, "s_axil"),
|
||||
dut.ctrl_clk,
|
||||
dut.rst
|
||||
)
|
||||
|
||||
|
||||
# self.axis_source = AxiStreamSource(
|
||||
# AxiStreamBus.from_prefix(dut, "s_axis_write_data"),
|
||||
# dut.ctrl_clk,
|
||||
# dut.rst
|
||||
# )
|
||||
|
||||
self.axis_sink = AxiStreamSink(
|
||||
AxiStreamBus.from_prefix(dut, "m_axis_read_data"),
|
||||
dut.ctrl_clk,
|
||||
dut.rst
|
||||
)
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.value = 1
|
||||
for _ in range(20):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
self.dut.rst.value = 0
|
||||
for _ in range(20):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
async def write_reg(self, reg_index: int, value: int):
|
||||
await self.axil.write(reg_addr(reg_index), u32(value))
|
||||
|
||||
async def read_reg(self, reg_index: int) -> int:
|
||||
resp = await self.axil.read(reg_addr(reg_index), 4)
|
||||
return int.from_bytes(bytes(resp.data), "little")
|
||||
|
||||
async def pulse_control(self, mask):
|
||||
await self.write_reg( REG_CONTROL, mask )
|
||||
|
||||
# Reflectometer Driver
|
||||
|
||||
async def configure_reflectometer (
|
||||
self,
|
||||
pulse_width,
|
||||
pulse_period,
|
||||
pulse_num,
|
||||
pulse_height,
|
||||
adc_period,
|
||||
window_size,
|
||||
timeout_cycles
|
||||
):
|
||||
await self.write_reg(REG_DAC_WIDTH, pulse_width)
|
||||
await self.write_reg(REG_DAC_PERIOD, pulse_period)
|
||||
await self.write_reg(REG_DAC_PULSE_NUM, pulse_num)
|
||||
await self.write_reg(REG_DAC_PULSE_HEIGHT, pulse_height)
|
||||
await self.write_reg(REG_ADC_PERIOD, adc_period)
|
||||
await self.write_reg(REG_WINDOW_SIZE, window_size)
|
||||
|
||||
await self.pulse_control(CTRL_CFG_BUS_VALID)
|
||||
|
||||
control = self.dut.dut.dut.controller_wrapper_axil_inst.controller
|
||||
|
||||
for cycle in range(timeout_cycles):
|
||||
dac_wait = int(control.cfg_wait_dac_ack.value)
|
||||
adc_wait = int(control.cfg_wait_adc_ack.value)
|
||||
|
||||
if dac_wait == 0 and adc_wait == 0:
|
||||
print(f"Configuration done after {cycle} ctrl_clk cycles")
|
||||
return
|
||||
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
async def send_start(self):
|
||||
await self.pulse_control(CTRL_START)
|
||||
|
||||
async def soft_reset(self):
|
||||
await self.pulse_control(CTRL_RST_SOFT)
|
||||
|
||||
async def get_status(self):
|
||||
status = await self.read_reg(REG_STATUS)
|
||||
return {
|
||||
"busy": bool(status & STATUS_BUSY),
|
||||
"processing_done": bool(status & STATUS_PROCESSING_DONE),
|
||||
"desc_read_busy": bool(status & STATUS_DESC_READ_BUSY),
|
||||
"desc_write_busy": bool(status & STATUS_DESC_WRITE_BUSY),
|
||||
"status_read_busy": bool(status & STATUS_STATUS_READ_BUSY),
|
||||
"status_write_busy": bool(status & STATUS_STATUS_WRITE_BUSY),
|
||||
"desc_read_hs": bool(status & STATUS_DESC_READ_HS),
|
||||
"desc_write_hs": bool(status & STATUS_DESC_WRITE_HS),
|
||||
"status_read_hs": bool(status & STATUS_STATUS_READ_HS),
|
||||
"status_write_hs": bool(status & STATUS_STATUS_WRITE_HS)
|
||||
}
|
||||
|
||||
async def wait_status(self, field, value=True, timeout_cycles=1000):
|
||||
|
||||
for _ in range(timeout_cycles):
|
||||
|
||||
status = await self.get_status()
|
||||
|
||||
if status[field] == value:
|
||||
return
|
||||
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
status = await self.get_status()
|
||||
|
||||
raise TimeoutError( f"Timeout waiting for status.{field} == {value}. " f"Current status = {status}")
|
||||
|
||||
async def wait_processing_done(self, timeout_cycles=1000):
|
||||
await self.wait_status("processing_done", True, timeout_cycles)
|
||||
|
||||
|
||||
async def wait_finish(self, timeout_cycles=1000):
|
||||
await self.wait_status("busy", False, timeout_cycles)
|
||||
|
||||
# DMA Driver
|
||||
|
||||
async def send_desc_write(self, addr, length_tag):
|
||||
|
||||
await self.write_reg(REG_DESC_WRITE_ADDR, addr)
|
||||
await self.write_reg(REG_DESC_WRITE_LEN_AND_TAG, length_tag)
|
||||
await self.pulse_control(CTRL_SEND_DESC_WRITE)
|
||||
|
||||
async def send_desc_read(self, addr, length, config):
|
||||
|
||||
await self.write_reg(REG_DESC_READ_ADDR, addr)
|
||||
await self.write_reg(REG_DESC_READ_LEN, length)
|
||||
await self.write_reg(REG_DESC_READ_CONFIG, config)
|
||||
await self.pulse_control( CTRL_SEND_DESC_READ)
|
||||
|
||||
async def take_status_write(self, status_write_len, status_write_config):
|
||||
await self.write_reg(REG_CONTROL, CTRL_TAKE_STATUS_WRITE)
|
||||
|
||||
for _ in range(10):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
|
||||
assert await self.read_reg(REG_STATUS_WRITE_CONFIG) == status_write_config
|
||||
assert await self.read_reg(REG_STATUS_WRITE_LEN) == status_write_len
|
||||
|
||||
async def take_read_status(self):
|
||||
|
||||
await self.pulse_control( CTRL_TAKE_STATUS_READ)
|
||||
return await self.read_reg(REG_READ_STATUS)
|
||||
|
||||
async def wait_dma_write_done(self, timeout_cycles=1000):
|
||||
await self.wait_status("desc_write_busy", False, timeout_cycles)
|
||||
|
||||
async def wait_dma_read_done(self, timeout_cycles=1000):
|
||||
await self.wait_status("desc_read_busy", False, timeout_cycles)
|
||||
|
||||
async def wait_status_read_handshake(self, timeout_cycles=1000):
|
||||
await self.wait_status("status_read_hs", True, timeout_cycles)
|
||||
|
||||
async def wait_status_write_handshake(self, timeout_cycles=1000):
|
||||
await self.wait_status("status_write_hs", True, timeout_cycles)
|
||||
|
||||
# AxiStream Driver
|
||||
|
||||
# async def send_axis_data(self, data: bytes):
|
||||
|
||||
# await self.axis_source.send(AxiStreamFrame(data) )
|
||||
|
||||
async def receive_axis_data(self):
|
||||
|
||||
frame = await self.axis_sink.recv()
|
||||
return bytes(frame)
|
||||
|
||||
# Accum transaction generator
|
||||
|
||||
def generate_samples(
|
||||
self,
|
||||
seq_num: int,
|
||||
smp_num: int,
|
||||
data_width: int,
|
||||
seed: int | None = None):
|
||||
if seq_num <= 0:
|
||||
raise ValueError(f"seq_num must be > 0, got {seq_num}")
|
||||
|
||||
if smp_num <= 0:
|
||||
raise ValueError(f"smp_num must be > 0, got {smp_num}")
|
||||
|
||||
rng = random.Random(seed)
|
||||
|
||||
max_value = (1 << data_width) - 1
|
||||
|
||||
samples = []
|
||||
|
||||
for _ in range(seq_num):
|
||||
seq_samples = []
|
||||
|
||||
for _ in range(smp_num):
|
||||
seq_samples.append( rng.randint(0, max_value))
|
||||
|
||||
samples.append(seq_samples)
|
||||
|
||||
return samples
|
||||
|
||||
def calculate_expected(
|
||||
self,
|
||||
samples,
|
||||
window_size: int,
|
||||
accum_width: int):
|
||||
if window_size <= 0:
|
||||
raise ValueError( f"window_size must be > 0, got {window_size}")
|
||||
|
||||
if not samples:
|
||||
raise ValueError("samples must not be empty")
|
||||
|
||||
seq_num = len(samples)
|
||||
smp_num = len(samples[0])
|
||||
|
||||
if smp_num == 0:
|
||||
raise ValueError("samples must not contain empty sequences")
|
||||
|
||||
for seq_idx, seq_samples in enumerate(samples):
|
||||
if len(seq_samples) != smp_num:
|
||||
raise ValueError(f"Sequence {seq_idx} has {len(seq_samples)} samples, " f"expected {smp_num}" )
|
||||
|
||||
if smp_num % window_size != 0:
|
||||
raise ValueError(f"smp_num ({smp_num}) must be divisible " f"by window_size ({window_size})")
|
||||
|
||||
exp_word_count = smp_num // window_size
|
||||
accum_mask = (1 << accum_width) - 1
|
||||
|
||||
expected = []
|
||||
|
||||
for word_idx in range(exp_word_count):
|
||||
local_sum = 0
|
||||
|
||||
for seq_idx in range(seq_num):
|
||||
for k in range(window_size):
|
||||
sample_idx = word_idx * window_size + k
|
||||
local_sum += samples[seq_idx][sample_idx]
|
||||
|
||||
expected.append(local_sum & accum_mask)
|
||||
|
||||
return expected
|
||||
|
||||
async def send_samples(self, samples):
|
||||
self.dut.sampler_m_axis_tvalid.value = 0
|
||||
self.dut.sampler_m_axis_tdata.value = 0
|
||||
|
||||
for seq_samples in samples:
|
||||
|
||||
for sample in seq_samples:
|
||||
|
||||
self.dut.sampler_m_axis_tdata.value = sample
|
||||
self.dut.sampler_m_axis_tvalid.value = 1
|
||||
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
self.dut.sampler_m_axis_tdata.value = 0
|
||||
self.dut.sampler_m_axis_tvalid.value = 0
|
||||
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
def bytes_to_words(self, data: bytes, word_width: int = 32):
|
||||
word_bytes = word_width // 8
|
||||
|
||||
if len(data) % word_bytes != 0:
|
||||
raise ValueError(f"Data length {len(data)} is not divisible " f"by word size {word_bytes}" )
|
||||
|
||||
words = []
|
||||
|
||||
for i in range(0, len(data), word_bytes):
|
||||
word = int.from_bytes(data[i:i + word_bytes], byteorder="little" )
|
||||
words.append(word)
|
||||
|
||||
return words
|
||||
|
||||
def check_results(self, expected, received):
|
||||
|
||||
assert len(received) == len(expected), (
|
||||
f"Number of words mismatch: "
|
||||
f"expected={len(expected)}, "
|
||||
f"received={len(received)}" )
|
||||
|
||||
for i, (exp, rec) in enumerate(zip(expected, received)):
|
||||
assert rec == exp, (
|
||||
f"Payload mismatch at index {i}: "
|
||||
f"expected=0x{exp:08X}, "
|
||||
f"received=0x{rec:08X}" )
|
||||
|
||||
print( f"Payload check passed: " f"{len(expected)} words")
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def rest_init(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
|
||||
@cocotb.test()
|
||||
async def simple_axil_write_read(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
|
||||
await tb.write_reg(REG_DAC_WIDTH, 0x0000_0123)
|
||||
|
||||
value = await tb.read_reg(REG_DAC_WIDTH)
|
||||
assert value == 0x0000_0123
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def simple_controller_config_write(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
|
||||
await tb.write_reg(REG_DAC_WIDTH, 0x10)
|
||||
await tb.write_reg(REG_DAC_PERIOD, 0x40)
|
||||
await tb.write_reg(REG_DAC_PULSE_NUM, 3)
|
||||
await tb.write_reg(REG_DAC_PULSE_HEIGHT, 0x7FF)
|
||||
await tb.write_reg(REG_ADC_PERIOD, 0x80)
|
||||
await tb.write_reg(REG_WINDOW_SIZE, 16)
|
||||
|
||||
assert await tb.read_reg(REG_DAC_WIDTH) == 0x10
|
||||
assert await tb.read_reg(REG_WINDOW_SIZE) == 16
|
||||
|
||||
# write data: set cfg_bus_valid signal
|
||||
await tb.write_reg(REG_CONTROL, CTRL_CFG_BUS_VALID)
|
||||
|
||||
# wait
|
||||
for _ in range(10):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
dac_pulse_width = dut.dut.dut.controller_wrapper_axil_inst.dac_pulse_width
|
||||
dac_pulse_period = dut.dut.dut.controller_wrapper_axil_inst.dac_pulse_period
|
||||
dac_pulse_num = dut.dut.dut.controller_wrapper_axil_inst.dac_pulse_num
|
||||
dac_pulse_height = dut.dut.dut.controller_wrapper_axil_inst.dac_pulse_height
|
||||
adc_pulse_period = dut.dut.dut.controller_wrapper_axil_inst.adc_pulse_period
|
||||
adc_window_size = dut.dut.dut.controller_wrapper_axil_inst.adc_window_size
|
||||
|
||||
# check config
|
||||
assert int(dac_pulse_width) == 0x10
|
||||
assert int(dac_pulse_period) == 0x40
|
||||
assert int(dac_pulse_num) == 3
|
||||
assert int(dac_pulse_height) == 0x7FF
|
||||
assert int(adc_pulse_period) == 0x80
|
||||
assert int(adc_window_size) == 16
|
||||
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
|
||||
@cocotb.test()
|
||||
async def simple_controller_start_check(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
await tb.write_reg(REG_CONTROL, CTRL_START)
|
||||
|
||||
await RisingEdge(dut.dut.dut.controller_wrapper_axil_inst.adc_start)
|
||||
|
||||
@cocotb.test()
|
||||
async def dma_accum_connection(dut):
|
||||
tb = TB(dut)
|
||||
await tb.reset()
|
||||
await tb.soft_reset()
|
||||
|
||||
SEQ_NUM = 1
|
||||
SMP_NUM = 16
|
||||
WINDOW_SIZE = 16
|
||||
|
||||
PULSE_WIDTH = 0x10
|
||||
PULSE_PERIOD = 0x40
|
||||
PULSE_HEIGHT = 0x7FF
|
||||
ADC_PERIOD = 1
|
||||
|
||||
RANDOM_SEED = 12345
|
||||
|
||||
RESULT_ADDR = 0x1000
|
||||
|
||||
await tb.configure_reflectometer(
|
||||
pulse_width=PULSE_WIDTH,
|
||||
pulse_period=PULSE_PERIOD,
|
||||
pulse_num=SEQ_NUM,
|
||||
pulse_height=PULSE_HEIGHT,
|
||||
adc_period=ADC_PERIOD,
|
||||
window_size=WINDOW_SIZE,
|
||||
timeout_cycles=1000 )
|
||||
|
||||
samples = tb.generate_samples(
|
||||
seq_num=SEQ_NUM,
|
||||
smp_num=SMP_NUM,
|
||||
data_width=ADC_DATA_WIDTH,
|
||||
seed=RANDOM_SEED )
|
||||
|
||||
|
||||
expected = tb.calculate_expected(
|
||||
samples=samples,
|
||||
window_size=WINDOW_SIZE,
|
||||
accum_width=ACCUM_WIDTH
|
||||
)
|
||||
|
||||
print("")
|
||||
print("========================================")
|
||||
print("ACCUMULATOR RANDOM TEST")
|
||||
print("========================================")
|
||||
print(f"seq_num = {SEQ_NUM}")
|
||||
print(f"smp_num = {SMP_NUM}")
|
||||
print(f"window_size = {WINDOW_SIZE}")
|
||||
print(f"data_width = {ADC_DATA_WIDTH}")
|
||||
print(f"accum_width = {ACCUM_WIDTH}")
|
||||
print(f"expected words = {len(expected)}")
|
||||
|
||||
RESULT_WORDS = len(expected)
|
||||
RESULT_BYTES = RESULT_WORDS * 4
|
||||
|
||||
print("==============================")
|
||||
print("ACCUM TEST")
|
||||
print("words =", RESULT_WORDS)
|
||||
print("bytes =", RESULT_BYTES)
|
||||
print("==============================")
|
||||
|
||||
for _ in range(10):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
await tb.send_start()
|
||||
|
||||
for _ in range(4):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
await tb.send_samples(samples)
|
||||
|
||||
await tb.wait_processing_done(timeout_cycles=5000)
|
||||
|
||||
await tb.send_desc_write( addr=RESULT_ADDR, length_tag=RESULT_BYTES )
|
||||
await tb.wait_dma_write_done(timeout_cycles=5000)
|
||||
|
||||
await tb.take_status_write(status_write_len=0x4, status_write_config=0)
|
||||
|
||||
await tb.send_desc_read(addr=RESULT_ADDR, length=RESULT_BYTES, config=0x0000_0001 )
|
||||
|
||||
received_data = await tb.receive_axis_data()
|
||||
|
||||
await tb.wait_dma_read_done(timeout_cycles=5000)
|
||||
|
||||
read_status = await tb.take_read_status()
|
||||
|
||||
assert read_status == 0x1
|
||||
|
||||
received = tb.bytes_to_words(received_data, RD_FIFO_WIDTH)
|
||||
|
||||
print("")
|
||||
print("Expected:")
|
||||
for i, value in enumerate(expected):
|
||||
print(f" [{i}] = 0x{value:08X}")
|
||||
|
||||
print("")
|
||||
print("Received:")
|
||||
for i, value in enumerate(received):
|
||||
print(f" [{i}] = 0x{value:08X}")
|
||||
|
||||
tb.check_results(
|
||||
expected=expected,
|
||||
received=received
|
||||
)
|
||||
|
||||
print("")
|
||||
print("========================================")
|
||||
print("ACCUMULATOR RANDOM TEST PASSED")
|
||||
print("========================================")
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# Primary clocks
|
||||
create_clock -name ref_clock -period 5.000 [get_ports ctrl_clk]
|
||||
|
||||
set clk_125_name [get_clocks -of_objects [get_pins generator_inst/clk_dac_125]]
|
||||
set clk_65_name [get_clocks -of_objects [get_pins accumulator_top_inst/clk_adc_65]]
|
||||
|
||||
set_clock_groups -asynchronous -group $clk_125_name -group $clk_65_name
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
import dma_reg_pkg::*;
|
||||
|
||||
module wrapper_controller_dma_accum
|
||||
#(
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
|
||||
parameter int unsigned DAC_DATA_WIDTH = 12,
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0,
|
||||
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 64,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32
|
||||
)
|
||||
(
|
||||
input logic ctrl_clk,
|
||||
input logic clk_generator,
|
||||
input logic clk_sampler,
|
||||
input logic rst_n,
|
||||
axi4l_if.slave s_axil,
|
||||
|
||||
// adc_clk_in domain
|
||||
|
||||
input logic [ADC_DATA_WIDTH-1:0] sampler_m_axis_tdata,
|
||||
input logic sampler_m_axis_tvalid,
|
||||
|
||||
axis_if.master m_axis_read_data
|
||||
);
|
||||
|
||||
logic workflow_done, processing_done;
|
||||
logic [31:0] window_size;
|
||||
logic adc_start, adc_rst;
|
||||
logic [31:0] dac_pulse_width;
|
||||
logic [31:0] dac_pulse_period;
|
||||
logic [DAC_DATA_WIDTH-1:0] dac_pulse_height;
|
||||
logic [15:0] dac_pulse_num;
|
||||
|
||||
// adc_clk_in domain outputs
|
||||
logic [31:0] adc_pulse_period;
|
||||
logic [15:0] adc_pulse_num;
|
||||
|
||||
// pulse outputs
|
||||
logic dac_start, dac_rst;
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_read_status_t)),
|
||||
.KEEP_W(($bits(dma_read_status_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) s_axis_status_read (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_write_status_t)),
|
||||
.KEEP_W(($bits(dma_write_status_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) s_axis_status_write (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W(RD_FIFO_WIDTH),
|
||||
.KEEP_W((RD_FIFO_WIDTH+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_accum (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_read_desc_t)),
|
||||
.KEEP_W(($bits(dma_read_desc_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_desc_read (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_write_desc_t)),
|
||||
.KEEP_W(($bits(dma_write_desc_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_desc_write (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
controller_wrapper_axil #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W),
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
) controller_wrapper_axil_inst
|
||||
(
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.dac_clk_in(clk_generator),
|
||||
.adc_clk_in(clk_sampler),
|
||||
.rst_n(rst_n),
|
||||
|
||||
.s_axil(s_axil),
|
||||
|
||||
.workflow_done(workflow_done),
|
||||
.processing_done(processing_done),
|
||||
|
||||
.adc_window_size(window_size),
|
||||
.dac_pulse_width(dac_pulse_width),
|
||||
.dac_pulse_period(dac_pulse_period),
|
||||
.dac_pulse_height(dac_pulse_height),
|
||||
.dac_pulse_num(dac_pulse_num),
|
||||
.adc_pulse_period(adc_pulse_period),
|
||||
.adc_pulse_num(adc_pulse_num),
|
||||
.dac_start(dac_start),
|
||||
.adc_start(adc_start),
|
||||
.dac_rst(dac_rst),
|
||||
.adc_rst(adc_rst),
|
||||
|
||||
.s_axis_status_read(s_axis_status_read),
|
||||
.s_axis_status_write(s_axis_status_write),
|
||||
.m_axis_desc_read(m_axis_desc_read),
|
||||
.m_axis_desc_write(m_axis_desc_write)
|
||||
);
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_W(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.DATA_W(AXI_DATA_WIDTH),
|
||||
.ID_W (AXI_ID_WIDTH),
|
||||
.USER_W(AXI_USER_WIDTH)
|
||||
) m_axi (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axi_dma_wrapper
|
||||
#(
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
|
||||
.AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED)
|
||||
)
|
||||
axi_dma_wrapper_inst
|
||||
(
|
||||
.clk(ctrl_clk),
|
||||
.rst(!rst_n),
|
||||
.s_axis_read_desc(m_axis_desc_read),
|
||||
.m_axis_read_desc_status(s_axis_status_read),
|
||||
.m_axis_read_data(m_axis_read_data),
|
||||
.s_axis_write_desc(m_axis_desc_write),
|
||||
.m_axis_write_desc_status(s_axis_status_write),
|
||||
.s_axis_write_data(m_axis_accum),
|
||||
.m_axi(m_axi)
|
||||
);
|
||||
|
||||
axi_ram_wrapper
|
||||
#(
|
||||
.DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.ADDR_WIDTH(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.ID_WIDTH(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.PIPELINE_OUTPUT(PIPELINE_OUTPUT)
|
||||
) axi_ram_wrapper_inst
|
||||
(
|
||||
.clk(ctrl_clk),
|
||||
.rst(!rst_n),
|
||||
.s_axi(m_axi)
|
||||
);
|
||||
|
||||
accumulator_top #(
|
||||
.DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RW_WIDTH(RD_FIFO_WIDTH)
|
||||
) accumulator_top_inst (
|
||||
.clk_in(clk_sampler),
|
||||
.rst(adc_rst),
|
||||
.s_axis_tdata(sampler_m_axis_tdata),
|
||||
.s_axis_tvalid(sampler_m_axis_tvalid),
|
||||
.start(adc_start),
|
||||
.smp_num(adc_pulse_period),
|
||||
.seq_num(adc_pulse_num),
|
||||
.window_size(window_size),
|
||||
.dma_clk_in(ctrl_clk),
|
||||
.req_ready(1'b1),
|
||||
.m_axis_accum(m_axis_accum),
|
||||
.finish(workflow_done),
|
||||
.accum_done(processing_done)
|
||||
);
|
||||
|
||||
endmodule
|
||||
+18
-9
@@ -7,23 +7,32 @@
|
||||
#
|
||||
|
||||
# FPGA settings
|
||||
FPGA_PART = xc7a35tfgg484-1
|
||||
FPGA_TOP = sampler
|
||||
FPGA_PART = xc7a100tfgg484-2
|
||||
FPGA_TOP = reflectometer_top
|
||||
FPGA_ARCH = artix7
|
||||
SIM_TOP = reflectometer_tb
|
||||
|
||||
RTL_DIR = ../src
|
||||
RTL_DIR = ../../rtl
|
||||
|
||||
|
||||
include ../../../scripts/vivado.mk
|
||||
include ../../scripts/vivado.mk
|
||||
|
||||
SYN_FILES += $(sort $(shell find ../src -type f \( -name '*.v' -o -name '*.sv' \)))
|
||||
|
||||
XCI_FILES = $(sort $(shell find ../src -type f -name '*.xci'))
|
||||
INC_FILES += interfaces.svh
|
||||
|
||||
XDC_FILES += ../../../constraints/ax7a035b.xdc
|
||||
TB_FILES += reflectometer_tb.sv
|
||||
SYN_FILES += reflectometer.sv
|
||||
SYN_FILES += dac_model.sv
|
||||
SYN_FILES += adc_model.sv
|
||||
SYN_FILES += reflectometer_tb.sv
|
||||
SYN_FILES += $(sort $(shell find ../../rtl -type f \( -name '*.v' -o -name '*.sv' \)))
|
||||
|
||||
XCI_FILES = $(sort $(shell find ../../rtl/ethernet-udp/src -type f -name '*.xci'))
|
||||
XCI_FILES += $(sort $(shell find ip/ -type f -name '*.xci'))
|
||||
|
||||
XDC_FILES += ../../constraints/ax7102.xdc
|
||||
XDC_FILES += debug.xdc
|
||||
|
||||
SYN_FILES += sampler_main_tb.sv
|
||||
SIM_TOP = sampler_tb
|
||||
|
||||
|
||||
program: $(PROJECT).bit
|
||||
@@ -0,0 +1,59 @@
|
||||
// AN9238 virtual ADC model (1 port)
|
||||
|
||||
module virtual_adc_model #(
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
|
||||
// Bipolar input range: +/- VOLTAGE_RANGE
|
||||
parameter real VOLTAGE_RANGE = 1.0,
|
||||
|
||||
// Analog input correction
|
||||
parameter real VOLTAGE_GAIN = 0.2,
|
||||
parameter real GROUND_BIAS = 0.0,
|
||||
|
||||
// ADC timing parameters
|
||||
parameter time CONVERSION_DELAY = 250ps
|
||||
)(
|
||||
input logic clk_i,
|
||||
input real voltage_i,
|
||||
|
||||
output logic otr_o,
|
||||
output logic [ADC_DATA_WIDTH-1:0] data_o
|
||||
);
|
||||
|
||||
localparam int unsigned ZERO_CODE = (1 << (ADC_DATA_WIDTH - 1));
|
||||
localparam real VOLTAGE_STEP = (2 * VOLTAGE_RANGE) / real'((1 << ADC_DATA_WIDTH) - 1);
|
||||
|
||||
real voltage_corrected;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Convert analog voltage to ADC code
|
||||
//------------------------------------------------------------
|
||||
function automatic logic [ADC_DATA_WIDTH-1:0] voltage_to_code( input real voltage );
|
||||
if (voltage <= -VOLTAGE_RANGE) return '0;
|
||||
if (voltage >= VOLTAGE_RANGE) return {ADC_DATA_WIDTH{1'b1}};
|
||||
return $rtoi(voltage / VOLTAGE_STEP + real'((ZERO_CODE)) + 0.5);
|
||||
endfunction
|
||||
|
||||
function automatic logic range_check( input real voltage );
|
||||
real v_abs = (voltage < 0.0) ? -voltage : voltage;
|
||||
return v_abs >= VOLTAGE_RANGE;
|
||||
endfunction
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Initial state
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
data_o = ZERO_CODE; // 0V
|
||||
otr_o = 0;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Update analog output
|
||||
//------------------------------------------------------------
|
||||
always @(posedge clk_i) begin
|
||||
voltage_corrected = (voltage_i - GROUND_BIAS) * VOLTAGE_GAIN;
|
||||
data_o <= #(CONVERSION_DELAY) voltage_to_code(voltage_corrected);
|
||||
otr_o <= #(CONVERSION_DELAY) range_check(voltage_corrected);
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,58 @@
|
||||
// AN9767 model (1 port)
|
||||
|
||||
module virtual_dac_model #(
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
|
||||
// Bipolar output range: +/- VOLTAGE_RANGE
|
||||
parameter real VOLTAGE_RANGE = 5.0,
|
||||
|
||||
// Analog output correction
|
||||
parameter real VOLTAGE_GAIN = 1.0,
|
||||
parameter real GROUND_BIAS = 0.0,
|
||||
|
||||
// DAC timing parameters
|
||||
parameter time TRANSMISSION_DELAY = 150ps,
|
||||
parameter time CONVERSION_DELAY = 150ps
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic wrt_i,
|
||||
input logic [DAC_DATA_WIDTH-1:0] data_i,
|
||||
|
||||
output real voltage_o
|
||||
);
|
||||
|
||||
localparam int unsigned ZERO_CODE = (1 << (DAC_DATA_WIDTH - 1));
|
||||
localparam real VOLTAGE_STEP = (2 * VOLTAGE_RANGE) / real'((1 << DAC_DATA_WIDTH) - 1);
|
||||
|
||||
logic [DAC_DATA_WIDTH-1:0] dac_code;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Convert DAC code to analog voltage
|
||||
//------------------------------------------------------------
|
||||
function automatic real code_to_voltage( input logic [DAC_DATA_WIDTH-1:0] code);
|
||||
return (int'(code) - int'(ZERO_CODE)) * VOLTAGE_STEP;
|
||||
endfunction
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Initial state
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
dac_code = '0;
|
||||
voltage_o = code_to_voltage('0) * VOLTAGE_GAIN + GROUND_BIAS;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Latch new DAC code
|
||||
//------------------------------------------------------------
|
||||
always @(posedge wrt_i) begin
|
||||
dac_code <= #(TRANSMISSION_DELAY) data_i;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Update analog output
|
||||
//------------------------------------------------------------
|
||||
always @(posedge clk_i) begin
|
||||
voltage_o <= #(CONVERSION_DELAY) code_to_voltage(dac_code) * VOLTAGE_GAIN + GROUND_BIAS;
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,9 @@
|
||||
# Primary clocks
|
||||
create_clock -name ref_clock -period 5.000 [get_ports clk_in]
|
||||
create_clock -name phy_rx_clock -period 8.000 [get_ports clk_m_axis]
|
||||
create_clock -name phy_tx_clock -period 8.000 [get_ports clk_s_axis]
|
||||
|
||||
set clk_125_name [get_clocks -of_objects [get_pins generator_inst/clk_dac_125]]
|
||||
set clk_65_name [get_clocks -of_objects [get_pins accumulator_top_dut/clk_adc_65]]
|
||||
|
||||
set_clock_groups -asynchronous -group $clk_125_name -group $clk_65_name
|
||||
@@ -0,0 +1,130 @@
|
||||
`ifndef AXIS_INTERFACE_SVH
|
||||
`define AXIS_INTERFACE_SVH
|
||||
|
||||
interface axis_if #(
|
||||
parameter int DATA_WIDTH = 8
|
||||
)(
|
||||
input logic clk,
|
||||
input logic rst_n
|
||||
);
|
||||
|
||||
// Сигналы шины AXI-Stream
|
||||
logic [DATA_WIDTH-1:0] tdata;
|
||||
logic tvalid;
|
||||
logic tlast;
|
||||
logic tready;
|
||||
|
||||
initial begin // Default values
|
||||
tdata = 'x;
|
||||
tvalid = 1'b0;
|
||||
tlast = 1'b0;
|
||||
tready = 1'b0;
|
||||
end
|
||||
|
||||
// Master Clocking Block (для отправки данных из TB)
|
||||
clocking drv_cb @(posedge clk);
|
||||
default input #1step output #100ps;
|
||||
output tdata, tvalid, tlast;
|
||||
input tready;
|
||||
endclocking
|
||||
|
||||
// Slave Clocking Block (для приема данных в TB с генерацией tready)
|
||||
clocking slv_cb @(posedge clk);
|
||||
default input #1step output #100ps;
|
||||
input tdata, tvalid, tlast;
|
||||
output tready;
|
||||
endclocking
|
||||
|
||||
// Passive Monitor Clocking Block
|
||||
clocking mon_cb @(posedge clk);
|
||||
default input #1step;
|
||||
input tdata, tvalid, tlast, tready;
|
||||
endclocking
|
||||
|
||||
modport master (output tdata, tvalid, tlast, input tready);
|
||||
modport slave (input tdata, tvalid, tlast, output tready);
|
||||
|
||||
// Модпорт для тестбенча с тасками
|
||||
modport tb (
|
||||
clocking drv_cb,
|
||||
clocking slv_cb,
|
||||
clocking mon_cb,
|
||||
import master_send,
|
||||
import slave_recv,
|
||||
import monitor_recv
|
||||
);
|
||||
|
||||
// Отправка пакета (Тестбенч выступает как Master)
|
||||
task automatic master_send(input logic [DATA_WIDTH-1:0] payload[]);
|
||||
if (payload.size() == 0) return;
|
||||
|
||||
@(drv_cb);
|
||||
|
||||
for (int i = 0; i < payload.size(); i++) begin
|
||||
drv_cb.tdata <= payload[i];
|
||||
drv_cb.tvalid <= 1'b1;
|
||||
drv_cb.tlast <= (i == payload.size() - 1);
|
||||
|
||||
forever begin // Ждем подтверждение от слейва пока не получим
|
||||
@(drv_cb);
|
||||
if (drv_cb.tready === 1'b1) begin
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
// Сбрасываем сигналы после отправки пакета
|
||||
drv_cb.tvalid <= 1'b0;
|
||||
drv_cb.tlast <= 1'b0;
|
||||
drv_cb.tdata <= 'x;
|
||||
endtask
|
||||
|
||||
// Прием пакета (Тестбенч выступает как Slave и управляет tready). Не применять если есть реальный Slave (его tready опустится насильно)
|
||||
task automatic slave_recv(output logic [DATA_WIDTH-1:0] payload[]);
|
||||
logic [DATA_WIDTH-1:0] local_queue[$]; // Внутри таски очередь использовать можно
|
||||
|
||||
slv_cb.tready <= 1'b1; // Показываем, что готовы принимать
|
||||
|
||||
forever begin
|
||||
@(slv_cb);
|
||||
if (slv_cb.tvalid === 1'b1) begin
|
||||
local_queue.push_back(slv_cb.tdata);
|
||||
if (slv_cb.tlast === 1'b1) begin
|
||||
break; // Пакет закончился
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
slv_cb.tready <= 1'b0; // Снимаем готовность
|
||||
|
||||
// Перекладываем из очереди в динамический массив
|
||||
payload = new[local_queue.size()](local_queue);
|
||||
endtask
|
||||
|
||||
// Прием пакета (Тестбенч выступает как пассивный наблюдатель без tready)
|
||||
task automatic monitor_recv(output logic [DATA_WIDTH-1:0] payload[]);
|
||||
logic [DATA_WIDTH-1:0] local_queue[$]; // Внутри таски очередь использовать можно
|
||||
|
||||
forever begin
|
||||
if (mon_cb.tready === 1'b1) begin
|
||||
break; // Дождались слейва
|
||||
end
|
||||
@(slv_cb);
|
||||
end
|
||||
|
||||
forever begin
|
||||
@(mon_cb);
|
||||
if (mon_cb.tvalid === 1'b1) begin
|
||||
local_queue.push_back(mon_cb.tdata);
|
||||
if (mon_cb.tlast === 1'b1) begin
|
||||
break; // Пакет закончился
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Перекладываем из очереди в динамический массив
|
||||
payload = new[local_queue.size()](local_queue);
|
||||
endtask
|
||||
|
||||
endinterface
|
||||
|
||||
`endif // AXIS_INTERFACE_SVH`
|
||||
@@ -0,0 +1,373 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
`include "interfaces.svh"
|
||||
|
||||
module reflectometer_tb;
|
||||
//------------------------------------------------------------
|
||||
// Параметры
|
||||
//------------------------------------------------------------
|
||||
localparam int unsigned DAC_DATA_WIDTH = 14;
|
||||
localparam int unsigned ADC_DATA_WIDTH = 12;
|
||||
localparam LOGIC_ZERO_LEVEL = 0; // DAC -5V for logic zero
|
||||
localparam VOLTAGE_ZERO_LEVEL = 2**(DAC_DATA_WIDTH-1); // DAC 0V for logic zero
|
||||
localparam PACK_FACTOR = 1; // not used in TB
|
||||
localparam PROCESS_MODE = 0; // 0 - uint, 1 - int. Current accumulator don't support signed sum
|
||||
localparam ACCUM_WIDTH = 32; // accumulator number bit witdth
|
||||
localparam N_MAX = 4096; // max value of windows to average by experiments
|
||||
localparam PACKET_SIZE = 1024; // bytes per UDP packet
|
||||
|
||||
localparam int REQUEST_TIMEOUT = 3 * PACKET_SIZE; // timeout for packet receiving from accumulator
|
||||
|
||||
localparam ZERO_LEVEL = LOGIC_ZERO_LEVEL; // "logic" VS "voltage"
|
||||
|
||||
localparam CLK_ETH_PHY_PERIOD = 8.000; // 125 MHz
|
||||
localparam CLK_REF_PERIOD = 5.000; // 200 MHz
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Глобальные перменные
|
||||
//------------------------------------------------------------
|
||||
int unsigned WINDOW_SIZE = 65; // fixed subwindow size to average by time
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Тактовые сигналы и сброс
|
||||
//------------------------------------------------------------
|
||||
logic clk_ref = 1'b0; // 200 MHz
|
||||
logic clk_eth_phy = 1'b0; // common for RX & TX
|
||||
logic rst_n = 1'b0;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Управление и конфиг DUT
|
||||
//------------------------------------------------------------
|
||||
logic [31:0] window_size;
|
||||
// AXI-S интерфейс для управления
|
||||
axis_if axis_control_if (
|
||||
.clk(clk_eth_phy),
|
||||
.rst_n(rst_n)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Входы DUT
|
||||
//------------------------------------------------------------
|
||||
// ADC интерфейс
|
||||
wire clk_adc;
|
||||
wire adc_otr;
|
||||
wire [ADC_DATA_WIDTH-1:0] adc_data;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Выходы
|
||||
//------------------------------------------------------------
|
||||
// Статусы
|
||||
wire mmcm_locked;
|
||||
wire workflow_done;
|
||||
wire processing_done;
|
||||
// DAC интерфейс
|
||||
wire clk_dac;
|
||||
wire dac_wrt;
|
||||
wire [DAC_DATA_WIDTH-1:0] dac_data;
|
||||
// AXI-S интерфейс для данных
|
||||
axis_if axis_accumulator_if (
|
||||
.clk(clk_eth_phy),
|
||||
.rst_n(rst_n)
|
||||
);
|
||||
//------------------------------------------------------------
|
||||
// Внутренние сигналы тестбенча
|
||||
//------------------------------------------------------------
|
||||
// Интерфейс хендшейка с MAC-PHY
|
||||
wire send_request;
|
||||
logic request_ready;
|
||||
// Сигнал между ЦАП и АЦП
|
||||
real signal_voltage;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Virtual DAC
|
||||
//------------------------------------------------------------
|
||||
virtual_dac_model #( // default voltage range is +/- 5V
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
// ,.VOLTAGE_GAIN(2)
|
||||
) virtual_dac (
|
||||
.clk_i(clk_dac),
|
||||
.wrt_i(dac_wrt),
|
||||
.data_i(dac_data),
|
||||
.voltage_o(signal_voltage)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Virtual ADC
|
||||
//------------------------------------------------------------
|
||||
virtual_adc_model #( // default voltage range is +/- 5V
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH)
|
||||
) virtual_adc (
|
||||
.clk_i(clk_adc),
|
||||
.voltage_i(signal_voltage),
|
||||
.otr_o(adc_otr),
|
||||
.data_o(adc_data)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Statistics processing
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Config handler
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// DUT
|
||||
//------------------------------------------------------------
|
||||
reflectometer_top #(
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE),
|
||||
.ZERO_LEVEL(ZERO_LEVEL),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE)
|
||||
) DUT (
|
||||
.clk_in(clk_ref),
|
||||
.rst_n(rst_n),
|
||||
|
||||
// Status
|
||||
.locked(mmcm_locked),
|
||||
.workflow_done(workflow_done),
|
||||
.processing_done(processing_done),
|
||||
|
||||
// Accumulator AXI-S bus
|
||||
.clk_axis_accumulator(clk_eth_phy), // GMII PHY RX clock
|
||||
.axis_accumulator(axis_accumulator_if.master),
|
||||
|
||||
// Control AXI-S bus
|
||||
.clk_axis_control(clk_eth_phy), // GMII PHY TX clock
|
||||
.axis_control(axis_control_if.slave),
|
||||
.window_size(window_size), // direct signal crutch (old controller)
|
||||
|
||||
// RTL-MAC handshake
|
||||
.request_ready(request_ready),
|
||||
.send_request(send_request),
|
||||
|
||||
// DAC
|
||||
.dac_clk_o(clk_dac),
|
||||
.dac_data(dac_data),
|
||||
.dac_wrt(dac_wrt),
|
||||
|
||||
// ADC
|
||||
.adc_clk_o(clk_adc),
|
||||
.adc_data(adc_data),
|
||||
.adc_otr(adc_otr)
|
||||
);
|
||||
assign window_size = WINDOW_SIZE;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Тактовые сигналы
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
forever #(CLK_REF_PERIOD/2) clk_ref = ~clk_ref;
|
||||
end
|
||||
initial begin
|
||||
forever #(CLK_ETH_PHY_PERIOD/2) clk_eth_phy = ~clk_eth_phy;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Таски для тестирования
|
||||
//------------------------------------------------------------
|
||||
// Таски работы с AXI-Stream
|
||||
task automatic dut_soft_reset(virtual axis_if#(8).tb vif);
|
||||
logic [7:0] tx_packet[];
|
||||
tx_packet = '{8'h0f};
|
||||
vif.master_send(tx_packet);
|
||||
endtask
|
||||
|
||||
task automatic dut_start(virtual axis_if#(8).tb vif);
|
||||
logic [7:0] tx_packet[];
|
||||
tx_packet = '{8'hf0};
|
||||
vif.master_send(tx_packet);
|
||||
endtask
|
||||
|
||||
task automatic dut_send_system_config(
|
||||
virtual axis_if#(8).tb vif,
|
||||
input logic [31:0] pulse_width,
|
||||
input logic [31:0] pulse_period,
|
||||
input logic [15:0] pulse_num,
|
||||
input logic [13:0] pulse_height, // achtung! p_height strictly must have 14 bits of width
|
||||
input logic [31:0] pulse_period_adc,
|
||||
input logic [31:0] window_size
|
||||
);
|
||||
// Создаем временный фиксированный массив и упаковываем всё одной строкой
|
||||
logic [7:0] tx_packet[];
|
||||
|
||||
// Ахтунг, 14-битный ЦАП захардкожен
|
||||
if (DAC_DATA_WIDTH != 14)
|
||||
$display("[WARNING] -dut_send_system_config- Default pulse height (DAC bitwidth) is equal to 14. Be aware, controller packet structure is coded for 14 bits");
|
||||
|
||||
tx_packet = '{
|
||||
8'h88, // Команда
|
||||
pulse_width[7:0], pulse_width[15:8], pulse_width[23:16], pulse_width[31:24],
|
||||
pulse_period[7:0], pulse_period[15:8], pulse_period[23:16], pulse_period[31:24],
|
||||
pulse_num[7:0], pulse_num[15:8], pulse_height[7:0], 8'({2'b00, pulse_height[13:8]}),
|
||||
pulse_period_adc[7:0], pulse_period_adc[15:8], pulse_period_adc[23:16], pulse_period_adc[31:24]
|
||||
};
|
||||
|
||||
vif.master_send(tx_packet);
|
||||
|
||||
// TODO remove for new controller
|
||||
WINDOW_SIZE = window_size;
|
||||
endtask
|
||||
|
||||
// Таски сбора статистики
|
||||
task automatic dut_read_output(
|
||||
virtual axis_if#(8).tb vif,
|
||||
input int sample_num,
|
||||
input bit randomize_recv_delays,
|
||||
output int output_data[]
|
||||
);
|
||||
logic [7:0] rx_packet[];
|
||||
logic [ACCUM_WIDTH-1:0] data_packet[];
|
||||
int numbers_per_packet = PACKET_SIZE/(ACCUM_WIDTH/8);
|
||||
int packet_num = $ceil(real'(sample_num / WINDOW_SIZE) / real'(numbers_per_packet));
|
||||
int timeout_flag = 0;
|
||||
int packet_counter = 0;
|
||||
|
||||
if (sample_num % WINDOW_SIZE) begin
|
||||
$display("[ERROR] -dut_read_output- Sample_num must be multiple of WINDOW_SIZE: %0d %% %0d = %0d", sample_num, WINDOW_SIZE, sample_num % WINDOW_SIZE);
|
||||
$finish;
|
||||
end
|
||||
|
||||
data_packet = new[numbers_per_packet];
|
||||
output_data = new[numbers_per_packet * packet_num];
|
||||
|
||||
// count send_request pulses (equal to number of packets)
|
||||
fork
|
||||
begin : packet_counter_proc
|
||||
forever begin
|
||||
@(posedge clk_eth_phy);
|
||||
if(send_request === 1)
|
||||
packet_counter++;
|
||||
end
|
||||
end
|
||||
join_none
|
||||
|
||||
// Wait until reflectometer done sampling and averaging
|
||||
wait(processing_done == 1);
|
||||
|
||||
// recv loop
|
||||
// если число пакетов превышает заложенное предрассчитанное значение -- ошибка
|
||||
fork : recv_loop_proc
|
||||
begin
|
||||
// packet recv loop
|
||||
forever begin
|
||||
if (packet_counter > packet_num) begin
|
||||
$display("[ERROR] -dut_read_output- Packet overflow detected. Number of data packets exceeds expected amount of packets");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (randomize_recv_delays)
|
||||
repeat($urandom_range(0, 500)) @(posedge clk_eth_phy);
|
||||
|
||||
timeout_flag = 0;
|
||||
fork : receive_packet_timeout
|
||||
begin
|
||||
request_ready = 1;
|
||||
vif.slave_recv(rx_packet);
|
||||
request_ready = 0;
|
||||
end
|
||||
begin
|
||||
repeat(REQUEST_TIMEOUT) @(posedge clk_eth_phy);
|
||||
timeout_flag = 1;
|
||||
end
|
||||
join_any
|
||||
|
||||
disable receive_packet_timeout;
|
||||
if (timeout_flag) begin
|
||||
$display("[ERROR] -dut_read_output- Timeout detected when receiving packet");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (rx_packet.size() != PACKET_SIZE) begin
|
||||
$display("[ERROR] -dut_read_output- Wrong packet size received: %0d bytes received, %0d bytes expected", rx_packet.size(), PACKET_SIZE);
|
||||
$finish;
|
||||
end
|
||||
|
||||
// unpack values
|
||||
data_packet = {<< byte {rx_packet}};
|
||||
data_packet = {<< ACCUM_WIDTH {data_packet}};
|
||||
|
||||
// copy and convert values
|
||||
for (int j = 0; j < data_packet.size(); j++) begin
|
||||
output_data[(packet_counter-1) * data_packet.size() + j] = int'(data_packet[j]);
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
begin
|
||||
// IP workflow completion event
|
||||
wait(workflow_done == 1);
|
||||
end
|
||||
join_any
|
||||
|
||||
disable recv_loop_proc;
|
||||
disable packet_counter_proc;
|
||||
|
||||
if (packet_counter != packet_num) begin
|
||||
$display("[ERROR] -dut_read_output- Wrong number of packets received: %0d received, %0d expected", packet_counter, packet_num);
|
||||
$finish;
|
||||
end
|
||||
|
||||
endtask
|
||||
|
||||
// Основная таска типового теста
|
||||
// todo
|
||||
|
||||
//------------------------------------------------------------
|
||||
// ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
int output_data[];
|
||||
|
||||
automatic virtual axis_if.tb control_vif = axis_control_if.tb;
|
||||
automatic virtual axis_if.tb accumulator_vif = axis_accumulator_if.tb;
|
||||
|
||||
$display("[TB] DUT initializaton");
|
||||
// Инициализация
|
||||
request_ready = 0;
|
||||
rst_n = 0;
|
||||
#100;
|
||||
rst_n = 1;
|
||||
wait(mmcm_locked === 1'b1);
|
||||
#150;
|
||||
$display("[TB] MMCM locked");
|
||||
|
||||
dut_soft_reset(control_vif);
|
||||
#100;
|
||||
|
||||
// Тесты
|
||||
$display("[TB] Tests start");
|
||||
dut_send_system_config(
|
||||
.vif(control_vif),
|
||||
.pulse_width(32'd123),
|
||||
.pulse_period(32'd5000),
|
||||
.pulse_num(16'd1),
|
||||
.pulse_height(14'd15000), // 0V
|
||||
.pulse_period_adc(32'd2600),
|
||||
.window_size(1)
|
||||
);
|
||||
#100;
|
||||
dut_start(control_vif);
|
||||
|
||||
dut_read_output(
|
||||
.vif(accumulator_vif),
|
||||
.sample_num(2600),
|
||||
.randomize_recv_delays(0),
|
||||
.output_data(output_data)
|
||||
);
|
||||
#1000;
|
||||
|
||||
$display("Received %0d numbers", output_data.size());
|
||||
for (int i = 0; i < output_data.size(); i++) begin
|
||||
$write("%0d ", output_data[i]);
|
||||
end
|
||||
$display("");
|
||||
|
||||
$display("[TB] ALL PASSED");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<wave_config>
|
||||
<wave_state>
|
||||
</wave_state>
|
||||
<db_ref_list>
|
||||
<db_ref path="reflectometer_tb_behav.wdb" id="1">
|
||||
<top_modules>
|
||||
<top_module name="glbl" />
|
||||
<top_module name="reflectometer_tb" />
|
||||
</top_modules>
|
||||
</db_ref>
|
||||
</db_ref_list>
|
||||
<zoom_setting>
|
||||
<ZoomStartTime time="0.000 ns"></ZoomStartTime>
|
||||
<ZoomEndTime time="1,506.001 ns"></ZoomEndTime>
|
||||
<Cursor1Time time="1,000.000 ns"></Cursor1Time>
|
||||
</zoom_setting>
|
||||
<column_width_setting>
|
||||
<NameColumnWidth column_width="196"></NameColumnWidth>
|
||||
<ValueColumnWidth column_width="76"></ValueColumnWidth>
|
||||
</column_width_setting>
|
||||
<WVObjectSize size="7" />
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/rst_n">
|
||||
<obj_property name="ElementShortName">rst_n</obj_property>
|
||||
<obj_property name="ObjectShortName">rst_n</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/mmcm_locked">
|
||||
<obj_property name="ElementShortName">mmcm_locked</obj_property>
|
||||
<obj_property name="ObjectShortName">mmcm_locked</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="group" fp_name="group28">
|
||||
<obj_property name="label">Signal</obj_property>
|
||||
<obj_property name="DisplayName">label</obj_property>
|
||||
<wvobject type="array" fp_name="/reflectometer_tb/dac_data">
|
||||
<obj_property name="ElementShortName">dac_data[13:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">dac_data[13:0]</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="other" fp_name="/reflectometer_tb/signal_voltage">
|
||||
<obj_property name="ElementShortName">signal_voltage</obj_property>
|
||||
<obj_property name="ObjectShortName">signal_voltage</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="array" fp_name="/reflectometer_tb/adc_data">
|
||||
<obj_property name="ElementShortName">adc_data[11:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">adc_data[11:0]</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/adc_otr">
|
||||
<obj_property name="ElementShortName">adc_otr</obj_property>
|
||||
<obj_property name="ObjectShortName">adc_otr</obj_property>
|
||||
</wvobject>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/send_request">
|
||||
<obj_property name="ElementShortName">send_request</obj_property>
|
||||
<obj_property name="ObjectShortName">send_request</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/request_ready">
|
||||
<obj_property name="ElementShortName">request_ready</obj_property>
|
||||
<obj_property name="ObjectShortName">request_ready</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="group" fp_name="group51">
|
||||
<obj_property name="label">Controller</obj_property>
|
||||
<obj_property name="DisplayName">label</obj_property>
|
||||
<obj_property name="isExpanded"></obj_property>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/clk">
|
||||
<obj_property name="ElementShortName">clk</obj_property>
|
||||
<obj_property name="ObjectShortName">clk</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/rst_n">
|
||||
<obj_property name="ElementShortName">rst_n</obj_property>
|
||||
<obj_property name="ObjectShortName">rst_n</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="array" fp_name="/reflectometer_tb/axis_control_if/tdata">
|
||||
<obj_property name="ElementShortName">tdata[7:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">tdata[7:0]</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/tvalid">
|
||||
<obj_property name="ElementShortName">tvalid</obj_property>
|
||||
<obj_property name="ObjectShortName">tvalid</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/tlast">
|
||||
<obj_property name="ElementShortName">tlast</obj_property>
|
||||
<obj_property name="ObjectShortName">tlast</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/tready">
|
||||
<obj_property name="ElementShortName">tready</obj_property>
|
||||
<obj_property name="ObjectShortName">tready</obj_property>
|
||||
</wvobject>
|
||||
</wvobject>
|
||||
<wvobject type="group" fp_name="group52">
|
||||
<obj_property name="label">Accumulator</obj_property>
|
||||
<obj_property name="DisplayName">label</obj_property>
|
||||
<obj_property name="isExpanded"></obj_property>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/clk">
|
||||
<obj_property name="ElementShortName">clk</obj_property>
|
||||
<obj_property name="ObjectShortName">clk</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/rst_n">
|
||||
<obj_property name="ElementShortName">rst_n</obj_property>
|
||||
<obj_property name="ObjectShortName">rst_n</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="array" fp_name="/reflectometer_tb/axis_accumulator_if/tdata">
|
||||
<obj_property name="ElementShortName">tdata[7:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">tdata[7:0]</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/tvalid">
|
||||
<obj_property name="ElementShortName">tvalid</obj_property>
|
||||
<obj_property name="ObjectShortName">tvalid</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/tlast">
|
||||
<obj_property name="ElementShortName">tlast</obj_property>
|
||||
<obj_property name="ObjectShortName">tlast</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/tready">
|
||||
<obj_property name="ElementShortName">tready</obj_property>
|
||||
<obj_property name="ObjectShortName">tready</obj_property>
|
||||
</wvobject>
|
||||
</wvobject>
|
||||
</wave_config>
|
||||
@@ -0,0 +1,46 @@
|
||||
reflectometer_fpga_project/
|
||||
├── designs/
|
||||
| └── full_new_reflectometer_without_clk_wiz/
|
||||
| └── src/
|
||||
| ├── reflectometer_ip.sv
|
||||
| ├── axi_dma_wrapper_if.sv
|
||||
| ├── reflectometer_and_dma_wrapper.sv
|
||||
| └── reflectometer_top.sv
|
||||
├── external/
|
||||
| └── rtl_libs/
|
||||
| ├── axi/
|
||||
| | ├── axi_reg/
|
||||
| | | └── axi4l_reg_map.sv
|
||||
| | └── rtl/
|
||||
| | ├── axi_pkg.sv
|
||||
| | └── axis_if.sv
|
||||
| └── external/
|
||||
| └── verilog_axi/
|
||||
| └── rtl/
|
||||
| ├── axi_dma_rd.v
|
||||
| ├── axi_dma_wr.v
|
||||
| └── axi_dma.v
|
||||
└── rtl/
|
||||
├── accum/
|
||||
| └── src/
|
||||
| ├── accum_top.sv
|
||||
| ├── accum.sv
|
||||
| ├── adder.sv
|
||||
| └── out_axis_fifo.sv
|
||||
├── controller_new/
|
||||
| └── src/
|
||||
| ├── axi4l_reg_map_controller_pkg.sv
|
||||
| ├── dma_reg_pkg.sv
|
||||
| ├── axi4l_reg_map_controller.sv
|
||||
| ├── controller_wrapper_axil.sv
|
||||
| ├── controller.sv
|
||||
| ├── dma_controller.sv
|
||||
| ├── axis_defaults_helper.sv
|
||||
| ├── shaper_axis_desc.sv
|
||||
| └── shaper_axis_status.sv
|
||||
├── generator/
|
||||
| └── src/
|
||||
| └── generator.sv
|
||||
└── sampler/
|
||||
└── src/
|
||||
└── sampler.sv
|
||||
@@ -0,0 +1,199 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// SystemVerilog interface wrapper around alexforencich/verilog-axi axi_dma.v.
|
||||
//
|
||||
// AXI memory, AXI-Stream data, DMA descriptor, and DMA status channels are all
|
||||
// exposed through compact interfaces. The original Forencich core remains
|
||||
// untouched and is connected through local flat wires.
|
||||
|
||||
import dma_reg_pkg::*;
|
||||
import axi_pkg::*;
|
||||
|
||||
// DMA Specific wrappers & converters
|
||||
module axi_dma_wrapper #(
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0
|
||||
)(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
|
||||
axis_if.slave s_axis_read_desc,
|
||||
|
||||
axis_if.master m_axis_read_desc_status,
|
||||
|
||||
axis_if.master m_axis_read_data,
|
||||
|
||||
axis_if.slave s_axis_write_desc,
|
||||
|
||||
axis_if.master m_axis_write_desc_status,
|
||||
|
||||
axis_if.slave s_axis_write_data,
|
||||
|
||||
axi4_if.master m_axi
|
||||
);
|
||||
|
||||
dma_read_desc_t read_desc;
|
||||
assign read_desc = dma_read_desc_t'(s_axis_read_desc.req.t.data);
|
||||
|
||||
|
||||
dma_write_desc_t write_desc;
|
||||
assign write_desc = dma_write_desc_t'(s_axis_write_desc.req.t.data);
|
||||
|
||||
|
||||
dma_read_status_t read_status;
|
||||
assign m_axis_read_desc_status.req.t.data = read_status;
|
||||
logic m_axis_read_desc_status_valid;
|
||||
assign m_axis_read_desc_status.req.t.valid = m_axis_read_desc_status_valid;
|
||||
|
||||
|
||||
|
||||
dma_write_status_t write_status;
|
||||
assign m_axis_write_desc_status.req.t.data = write_status;
|
||||
logic m_axis_write_desc_status_valid;
|
||||
assign m_axis_write_desc_status.req.t.valid = m_axis_write_desc_status_valid;
|
||||
|
||||
logic [1:0] dma_awburst;
|
||||
logic [1:0] dma_arburst;
|
||||
logic [1:0] dma_bresp;
|
||||
logic [1:0] dma_rresp;
|
||||
|
||||
assign m_axi.req.aw.burst = axi_pkg::axi_burst_t'(dma_awburst);
|
||||
assign m_axi.req.ar.burst = axi_pkg::axi_burst_t'(dma_arburst);
|
||||
|
||||
assign dma_bresp = logic'(m_axi.resp.b.resp);
|
||||
assign dma_rresp = logic'(m_axi.resp.r.resp);
|
||||
|
||||
// Original DMA: flat ports only.
|
||||
axi_dma #(
|
||||
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
|
||||
.AXI_ADDR_WIDTH (dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.AXI_STRB_WIDTH (AXI_STRB_WIDTH),
|
||||
.AXI_ID_WIDTH (AXI_ID_WIDTH),
|
||||
.AXI_MAX_BURST_LEN (AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH (AXIS_DATA_WIDTH),
|
||||
.AXIS_KEEP_ENABLE (AXIS_KEEP_ENABLE),
|
||||
.AXIS_KEEP_WIDTH (AXIS_KEEP_WIDTH),
|
||||
.AXIS_LAST_ENABLE (AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE (AXIS_ID_ENABLE),
|
||||
.AXIS_ID_WIDTH (dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.AXIS_DEST_ENABLE (AXIS_DEST_ENABLE),
|
||||
.AXIS_DEST_WIDTH (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.AXIS_USER_ENABLE (AXIS_USER_ENABLE),
|
||||
.AXIS_USER_WIDTH (dma_reg_pkg::AXIS_USER_WIDTH),
|
||||
.LEN_WIDTH (dma_reg_pkg::LEN_WIDTH),
|
||||
.TAG_WIDTH (dma_reg_pkg::TAG_WIDTH),
|
||||
.ENABLE_SG (ENABLE_SG),
|
||||
.ENABLE_UNALIGNED (ENABLE_UNALIGNED)
|
||||
) i_axi_dma (
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
|
||||
.s_axis_read_desc_addr (read_desc.addr),
|
||||
.s_axis_read_desc_len (read_desc.len),
|
||||
.s_axis_read_desc_tag (read_desc.tag),
|
||||
.s_axis_read_desc_id (read_desc.id),
|
||||
.s_axis_read_desc_dest (read_desc.dest),
|
||||
.s_axis_read_desc_user (read_desc.user),
|
||||
.s_axis_read_desc_valid (s_axis_read_desc.req.t.valid),
|
||||
.s_axis_read_desc_ready (s_axis_read_desc.resp.ready),
|
||||
|
||||
.m_axis_read_desc_status_tag (read_status.tag),
|
||||
.m_axis_read_desc_status_error (read_status.error),
|
||||
.m_axis_read_desc_status_valid (m_axis_read_desc_status_valid),
|
||||
|
||||
.m_axis_read_data_tdata (m_axis_read_data.req.t.data),
|
||||
.m_axis_read_data_tkeep (m_axis_read_data.req.t.keep),
|
||||
.m_axis_read_data_tvalid (m_axis_read_data.req.t.valid),
|
||||
.m_axis_read_data_tready (m_axis_read_data.resp.ready),
|
||||
.m_axis_read_data_tlast (m_axis_read_data.req.t.last),
|
||||
.m_axis_read_data_tid (m_axis_read_data.req.t.id),
|
||||
.m_axis_read_data_tdest (m_axis_read_data.req.t.dest),
|
||||
.m_axis_read_data_tuser (m_axis_read_data.req.t.user),
|
||||
|
||||
.s_axis_write_desc_addr (write_desc.addr),
|
||||
.s_axis_write_desc_len (write_desc.len),
|
||||
.s_axis_write_desc_tag (write_desc.tag),
|
||||
.s_axis_write_desc_valid (s_axis_write_desc.req.t.valid),
|
||||
.s_axis_write_desc_ready (s_axis_write_desc.resp.ready),
|
||||
|
||||
.m_axis_write_desc_status_len (write_status.len),
|
||||
.m_axis_write_desc_status_tag (write_status.tag),
|
||||
.m_axis_write_desc_status_id (write_status.id),
|
||||
.m_axis_write_desc_status_dest (write_status.dest),
|
||||
.m_axis_write_desc_status_user (write_status.user),
|
||||
.m_axis_write_desc_status_error (write_status.error),
|
||||
.m_axis_write_desc_status_valid (m_axis_write_desc_status_valid),
|
||||
|
||||
.s_axis_write_data_tdata (s_axis_write_data.req.t.data),
|
||||
.s_axis_write_data_tkeep (s_axis_write_data.req.t.keep),
|
||||
.s_axis_write_data_tvalid (s_axis_write_data.req.t.valid),
|
||||
.s_axis_write_data_tready (s_axis_write_data.resp.ready),
|
||||
.s_axis_write_data_tlast (s_axis_write_data.req.t.last),
|
||||
.s_axis_write_data_tid (s_axis_write_data.req.t.id),
|
||||
.s_axis_write_data_tdest (s_axis_write_data.req.t.dest),
|
||||
.s_axis_write_data_tuser (s_axis_write_data.req.t.user),
|
||||
|
||||
.m_axi_awid (m_axi.req.aw.id),
|
||||
.m_axi_awaddr (m_axi.req.aw.addr),
|
||||
.m_axi_awlen (m_axi.req.aw.len),
|
||||
.m_axi_awsize (m_axi.req.aw.size),
|
||||
.m_axi_awburst (dma_awburst),
|
||||
.m_axi_awlock (m_axi.req.aw.lock),
|
||||
.m_axi_awcache (m_axi.req.aw.cache),
|
||||
.m_axi_awprot (m_axi.req.aw.prot),
|
||||
.m_axi_awvalid (m_axi.req.aw.valid),
|
||||
.m_axi_awready (m_axi.resp.aw_ready),
|
||||
|
||||
.m_axi_wdata (m_axi.req.w.data),
|
||||
.m_axi_wstrb (m_axi.req.w.strb),
|
||||
.m_axi_wlast ( m_axi.req.w.last),
|
||||
.m_axi_wvalid (m_axi.req.w.valid),
|
||||
.m_axi_wready (m_axi.resp.w_ready),
|
||||
|
||||
.m_axi_bid (m_axi.resp.b.id),
|
||||
.m_axi_bresp (dma_bresp),
|
||||
.m_axi_bvalid (m_axi.resp.b.valid),
|
||||
.m_axi_bready (m_axi.req.b_ready),
|
||||
|
||||
.m_axi_arid (m_axi.req.ar.id),
|
||||
.m_axi_araddr (m_axi.req.ar.addr),
|
||||
.m_axi_arlen (m_axi.req.ar.len),
|
||||
.m_axi_arsize (m_axi.req.ar.size),
|
||||
.m_axi_arburst (dma_arburst),
|
||||
.m_axi_arlock (m_axi.req.ar.lock),
|
||||
.m_axi_arcache (m_axi.req.ar.cache),
|
||||
.m_axi_arprot (m_axi.req.ar.prot),
|
||||
.m_axi_arvalid (m_axi.req.ar.valid),
|
||||
.m_axi_arready (m_axi.resp.ar_ready),
|
||||
|
||||
.m_axi_rid (m_axi.resp.r.id),
|
||||
.m_axi_rdata (m_axi.resp.r.data),
|
||||
.m_axi_rresp (dma_rresp),
|
||||
.m_axi_rlast (m_axi.resp.r.last),
|
||||
.m_axi_rvalid (m_axi.resp.r.valid),
|
||||
.m_axi_rready (m_axi.req.r_ready),
|
||||
|
||||
.read_enable (1'b1),
|
||||
.write_enable (1'b1),
|
||||
.write_abort (1'b0)
|
||||
);
|
||||
|
||||
|
||||
endmodule : axi_dma_wrapper
|
||||
|
||||
`default_nettype wire
|
||||
@@ -0,0 +1,67 @@
|
||||
module axi_ram_wrapper
|
||||
#(
|
||||
parameter int unsigned DATA_WIDTH = 32,
|
||||
parameter int unsigned ADDR_WIDTH = 16,
|
||||
parameter int unsigned ID_WIDTH = 8,
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0
|
||||
)
|
||||
(
|
||||
input logic clk,
|
||||
input logic rst,
|
||||
axi4_if.slave s_axi
|
||||
);
|
||||
|
||||
logic [1:0] ram_bresp;
|
||||
logic [1:0] ram_rresp;
|
||||
|
||||
|
||||
assign s_axi.resp.b.resp = axi_pkg::axi_resp_t'(ram_bresp);
|
||||
assign s_axi.resp.r.resp = axi_pkg::axi_resp_t'(ram_rresp);
|
||||
|
||||
axi_ram
|
||||
#(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.ADDR_WIDTH(ADDR_WIDTH),
|
||||
.ID_WIDTH(ID_WIDTH),
|
||||
.PIPELINE_OUTPUT(PIPELINE_OUTPUT)
|
||||
) axi_ram_inst
|
||||
(
|
||||
.clk(clk),
|
||||
.rst(rst),
|
||||
.s_axi_awid(s_axi.req.aw.id),
|
||||
.s_axi_awaddr(s_axi.req.aw.addr),
|
||||
.s_axi_awlen(s_axi.req.aw.len),
|
||||
.s_axi_awsize(s_axi.req.aw.size),
|
||||
.s_axi_awburst(s_axi.req.aw.burst),
|
||||
.s_axi_awlock(s_axi.req.aw.lock),
|
||||
.s_axi_awcache(s_axi.req.aw.cache),
|
||||
.s_axi_awprot(s_axi.req.aw.prot),
|
||||
.s_axi_awvalid(s_axi.req.aw.valid),
|
||||
.s_axi_awready(s_axi.resp.aw_ready),
|
||||
.s_axi_wdata(s_axi.req.w.data),
|
||||
.s_axi_wstrb(s_axi.req.w.strb),
|
||||
.s_axi_wlast(s_axi.req.w.last),
|
||||
.s_axi_wvalid(s_axi.req.w.valid),
|
||||
.s_axi_wready(s_axi.resp.w_ready),
|
||||
.s_axi_bid(s_axi.resp.b.id),
|
||||
.s_axi_bresp(ram_bresp),
|
||||
.s_axi_bvalid(s_axi.resp.b.valid),
|
||||
.s_axi_bready(s_axi.req.b_ready),
|
||||
.s_axi_arid(s_axi.req.ar.id),
|
||||
.s_axi_araddr(s_axi.req.ar.addr),
|
||||
.s_axi_arlen(s_axi.req.ar.len),
|
||||
.s_axi_arsize(s_axi.req.ar.size),
|
||||
.s_axi_arburst(s_axi.req.ar.burst),
|
||||
.s_axi_arlock(s_axi.req.ar.lock),
|
||||
.s_axi_arcache(s_axi.req.ar.cache),
|
||||
.s_axi_arprot(s_axi.req.ar.prot),
|
||||
.s_axi_arvalid(s_axi.req.ar.valid),
|
||||
.s_axi_arready(s_axi.resp.ar_ready),
|
||||
.s_axi_rid(s_axi.resp.r.id),
|
||||
.s_axi_rdata(s_axi.resp.r.data),
|
||||
.s_axi_rresp(ram_rresp),
|
||||
.s_axi_rlast(s_axi.resp.r.last),
|
||||
.s_axi_rvalid(s_axi.resp.r.valid),
|
||||
.s_axi_rready(s_axi.req.r_ready)
|
||||
);
|
||||
endmodule
|
||||
@@ -0,0 +1,175 @@
|
||||
`timescale 1 ns / 1 ns
|
||||
|
||||
module reflectometer_and_dma_wrapper
|
||||
#(
|
||||
// parameters for base reflectometer works
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned PACK_FACTOR = 1,
|
||||
parameter int unsigned PROCESS_MODE = 0,
|
||||
parameter int unsigned ZERO_LEVEL = 8192,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 1024,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32,
|
||||
|
||||
// parameters for DMA and interfaces
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0
|
||||
)
|
||||
(
|
||||
input logic ctrl_clk,
|
||||
input logic clk_sampler,
|
||||
input logic clk_generator,
|
||||
input logic ctrl_rst_n,
|
||||
|
||||
axi4l_if.slave s_axil,
|
||||
axi4_if.master m_axi,
|
||||
// todo
|
||||
axis_if.master m_axis_read_data,
|
||||
|
||||
// DAC
|
||||
output wire [DAC_DATA_WIDTH-1:0] dac_data,
|
||||
output wire dac_wrt,
|
||||
|
||||
// ADC
|
||||
input wire [ADC_DATA_WIDTH-1:0] adc_data,
|
||||
input wire adc_otr
|
||||
|
||||
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_read_status_t)),
|
||||
.KEEP_W(($bits(dma_read_status_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) s_axis_status_read (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(ctrl_rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_write_status_t)),
|
||||
.KEEP_W(($bits(dma_write_status_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) s_axis_status_write (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(ctrl_rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_read_desc_t)),
|
||||
.KEEP_W(($bits(dma_read_desc_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_desc_read (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(ctrl_rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W($bits(dma_write_desc_t)),
|
||||
.KEEP_W(($bits(dma_write_desc_t)+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_desc_write (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(ctrl_rst_n)
|
||||
);
|
||||
|
||||
axis_if #(
|
||||
.DATA_W(RD_FIFO_WIDTH),
|
||||
.KEEP_W((RD_FIFO_WIDTH+7)/8),
|
||||
.ID_W(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.DEST_W(dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W(dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) m_axis_accum (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(ctrl_rst_n)
|
||||
);
|
||||
|
||||
reflectometer_ip #(
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE),
|
||||
.ZERO_LEVEL(ZERO_LEVEL),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RD_FIFO_WIDTH(RD_FIFO_WIDTH)
|
||||
) reflectometer_ip_inst (
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.clk_sampler(clk_sampler),
|
||||
.clk_generator(clk_generator),
|
||||
.ctrl_rst_n(ctrl_rst_n),
|
||||
.s_axil(s_axil),
|
||||
.m_axis_accum(m_axis_accum),
|
||||
.s_axis_status_read(s_axis_status_read),
|
||||
.s_axis_status_write(s_axis_status_write),
|
||||
.m_axis_desc_read(m_axis_desc_read),
|
||||
.m_axis_desc_write(m_axis_desc_write),
|
||||
|
||||
.dac_data(dac_data),
|
||||
.dac_wrt(dac_wrt),
|
||||
.adc_data(adc_data),
|
||||
.adc_otr(adc_otr)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// DMA
|
||||
//------------------------------------------------------------
|
||||
axi_dma_wrapper #(
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
|
||||
.AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED)
|
||||
) axi_dma_wrapper_inst
|
||||
(
|
||||
.clk(ctrl_clk),
|
||||
.rst(!ctrl_rst_n),
|
||||
.s_axis_read_desc(m_axis_desc_read),
|
||||
.m_axis_read_desc_status(s_axis_status_read),
|
||||
.m_axis_read_data(m_axis_read_data),
|
||||
.s_axis_write_desc(m_axis_desc_write),
|
||||
.m_axis_write_desc_status(s_axis_status_write),
|
||||
.s_axis_write_data(m_axis_accum),
|
||||
.m_axi(m_axi)
|
||||
);
|
||||
|
||||
endmodule : reflectometer_and_dma_wrapper
|
||||
@@ -0,0 +1,213 @@
|
||||
`timescale 1 ns / 1 ns
|
||||
|
||||
module reflectometer_ip #(
|
||||
// parameters for base reflectometer works
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned PACK_FACTOR = 1,
|
||||
parameter int unsigned PROCESS_MODE = 0,
|
||||
parameter int unsigned ZERO_LEVEL = 8192,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 1024,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32,
|
||||
|
||||
// parameters for DMA and interfaces
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1
|
||||
)
|
||||
(
|
||||
input logic ctrl_clk,
|
||||
input logic clk_sampler,
|
||||
input logic clk_generator,
|
||||
input logic ctrl_rst_n,
|
||||
|
||||
axi4l_if.slave s_axil,
|
||||
axis_if.master m_axis_accum,
|
||||
axis_if.slave s_axis_status_read,
|
||||
axis_if.slave s_axis_status_write,
|
||||
axis_if.master m_axis_desc_read,
|
||||
axis_if.master m_axis_desc_write,
|
||||
|
||||
// DAC
|
||||
output wire [DAC_DATA_WIDTH-1:0] dac_data,
|
||||
|
||||
// ADC
|
||||
input wire [ADC_DATA_WIDTH-1:0] adc_data,
|
||||
input wire adc_otr,
|
||||
output wire dac_wrt
|
||||
|
||||
|
||||
);
|
||||
|
||||
wire workflow_done, processing_done;
|
||||
|
||||
OBUF OBUF_pulse_clk (
|
||||
.I(clk_generator),
|
||||
.O(dac_wrt)
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Controller
|
||||
// -------------------------------------------------------------------------
|
||||
wire [31:0] dac_pulse_width;
|
||||
wire [31:0] dac_pulse_period;
|
||||
wire [DAC_DATA_WIDTH-1:0] dac_pulse_height;
|
||||
wire [15:0] dac_pulse_num;
|
||||
|
||||
wire [31:0] adc_pulse_period;
|
||||
wire [15:0] adc_pulse_num;
|
||||
wire [31:0] adc_window_size;
|
||||
|
||||
wire dac_start;
|
||||
wire adc_start;
|
||||
wire dac_rst;
|
||||
wire adc_rst;
|
||||
|
||||
controller_wrapper_axil #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W),
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
) controller_wrapper_axil_inst
|
||||
(
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.dac_clk_in(clk_generator),
|
||||
.adc_clk_in(clk_sampler),
|
||||
.rst_n(ctrl_rst_n),
|
||||
|
||||
.s_axil(s_axil),
|
||||
|
||||
.workflow_done(workflow_done),
|
||||
.processing_done(processing_done),
|
||||
|
||||
.adc_window_size(adc_window_size),
|
||||
.dac_pulse_width(dac_pulse_width),
|
||||
.dac_pulse_period(dac_pulse_period),
|
||||
.dac_pulse_height(dac_pulse_height),
|
||||
.dac_pulse_num(dac_pulse_num),
|
||||
.adc_pulse_period(adc_pulse_period),
|
||||
.adc_pulse_num(adc_pulse_num),
|
||||
.dac_start(dac_start),
|
||||
.adc_start(adc_start),
|
||||
.dac_rst(dac_rst),
|
||||
.adc_rst(adc_rst),
|
||||
|
||||
.s_axis_status_read(s_axis_status_read),
|
||||
.s_axis_status_write(s_axis_status_write),
|
||||
.m_axis_desc_read(m_axis_desc_read),
|
||||
.m_axis_desc_write(m_axis_desc_write)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// DAC -> ADC CDC
|
||||
//------------------------------------------------------------
|
||||
(* ASYNC_REG = "TRUE" *) logic [2:0] stretch; // 125/65~=2. Чтобы поймать единичный импульс, растянем его во времени
|
||||
(* ASYNC_REG = "TRUE" *) logic [1:0] sync_DA;
|
||||
wire dac_done_stretched;
|
||||
|
||||
wire generator_done, generator_request;
|
||||
wire sampler_done, sampler_request;
|
||||
|
||||
always_ff @(posedge clk_generator or posedge dac_rst)
|
||||
begin
|
||||
if (dac_rst)
|
||||
stretch <= 0;
|
||||
else begin
|
||||
stretch[0] <= generator_done;
|
||||
stretch[1] <= stretch[0];
|
||||
stretch[2] <= stretch[1];
|
||||
end
|
||||
end
|
||||
assign dac_done_stretched = |stretch;
|
||||
|
||||
always_ff @(posedge clk_sampler or posedge adc_rst) begin
|
||||
if (adc_rst)
|
||||
sync_DA <= 0;
|
||||
else begin
|
||||
sync_DA[0] <= dac_done_stretched;
|
||||
sync_DA[1] <= sync_DA[0];
|
||||
end
|
||||
end
|
||||
assign sampler_request = sync_DA[1];
|
||||
|
||||
//------------------------------------------------------------
|
||||
// ADC -> DAC CDC
|
||||
//------------------------------------------------------------
|
||||
(* ASYNC_REG = "TRUE" *) logic [1:0] sync_AD;
|
||||
|
||||
always_ff @(posedge clk_generator or posedge dac_rst) begin
|
||||
if (dac_rst)
|
||||
sync_AD <= 0;
|
||||
else begin
|
||||
sync_AD[0] <= sampler_done;
|
||||
sync_AD[1] <= sync_AD[0];
|
||||
end
|
||||
end
|
||||
assign generator_request = sync_AD[1];
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Generator (DAC)
|
||||
//------------------------------------------------------------
|
||||
generator #(
|
||||
.DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ZERO_LEVEL(ZERO_LEVEL)
|
||||
) generator_inst (
|
||||
.clk_dac(clk_generator),
|
||||
.rst(dac_rst),
|
||||
.start(dac_start),
|
||||
.pulse_width(dac_pulse_width),
|
||||
.pulse_period(dac_pulse_period),
|
||||
.pulse_height(dac_pulse_height),
|
||||
.pulse_num(dac_pulse_num),
|
||||
.dac_out(dac_data),
|
||||
.done(generator_done),
|
||||
.request(generator_request)
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Sampler (ADC)
|
||||
// -------------------------------------------------------------------------
|
||||
wire [ADC_DATA_WIDTH*PACK_FACTOR-1:0] sampler_m_axis_tdata;
|
||||
wire sampler_m_axis_tvalid;
|
||||
|
||||
sampler #(
|
||||
.DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE)
|
||||
) sampler_inst (
|
||||
.clk_in(clk_sampler),
|
||||
.rst(adc_rst),
|
||||
.data_in(adc_data),
|
||||
.out_of_range(adc_otr),
|
||||
.m_axis_tdata(sampler_m_axis_tdata),
|
||||
.m_axis_tvalid(sampler_m_axis_tvalid),
|
||||
.smp_num(adc_pulse_period),
|
||||
.done(sampler_done),
|
||||
.request(sampler_request)
|
||||
);
|
||||
|
||||
accumulator_top #(
|
||||
.DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RW_WIDTH(RD_FIFO_WIDTH)
|
||||
) accumulator_top_inst (
|
||||
.clk_in(clk_sampler),
|
||||
.rst(adc_rst),
|
||||
.s_axis_tdata(sampler_m_axis_tdata),
|
||||
.s_axis_tvalid(sampler_m_axis_tvalid),
|
||||
.start(adc_start),
|
||||
.smp_num(adc_pulse_period),
|
||||
.seq_num(adc_pulse_num),
|
||||
.window_size(adc_window_size),
|
||||
.dma_clk_in(ctrl_clk),
|
||||
.req_ready(1'b1),
|
||||
.m_axis_accum(m_axis_accum),
|
||||
.finish(workflow_done),
|
||||
.accum_done(processing_done)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,138 @@
|
||||
module reflectometer_top
|
||||
#(
|
||||
// parameters for base reflectometer works
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned PACK_FACTOR = 1,
|
||||
parameter int unsigned PROCESS_MODE = 0,
|
||||
parameter int unsigned ZERO_LEVEL = 8192,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 64,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32,
|
||||
|
||||
// parameters for DMA and interfaces
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0
|
||||
)
|
||||
(
|
||||
input logic ctrl_clk,
|
||||
input logic rst_n,
|
||||
output wire locked,
|
||||
|
||||
axi4l_if.slave s_axil,
|
||||
axi4_if.master m_axi,
|
||||
// todo
|
||||
axis_if.master m_axis_read_data,
|
||||
|
||||
// DAC
|
||||
output wire dac_clk_o,
|
||||
output wire [DAC_DATA_WIDTH-1:0] dac_data,
|
||||
output wire dac_wrt,
|
||||
|
||||
// ADC
|
||||
output wire adc_clk_o,
|
||||
input wire [ADC_DATA_WIDTH-1:0] adc_data,
|
||||
input wire adc_otr
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Generated clocks for controller
|
||||
// Need to create this IP in Vivado:
|
||||
// input resetn
|
||||
// input clk_200 : 200 MHz : Reference clock
|
||||
// output clk_adc_65 : 65 MHz : ADC RTL clock
|
||||
// output clk_adc_65_180 : 65 MHz, phase 180 deg. : ADC PHY clock
|
||||
// output clk_adc_125 : 125 MHz : DAC RTL clock
|
||||
// output clk_adc_125_180 : 125 MHz, phase 180 deg. : DAC PHY clock
|
||||
// output locked
|
||||
// -------------------------------------------------------------------------
|
||||
wire clk_sampler, clk_generator, clk_locked;
|
||||
|
||||
clk_wiz_0 clk_wiz_inst
|
||||
(
|
||||
// Clock in ports
|
||||
.clk_200(ctrl_clk),
|
||||
// Clock out ports
|
||||
.clk_adc_65(clk_sampler),
|
||||
.clk_adc_65_180(adc_clk_o),
|
||||
.clk_dac_125(clk_generator),
|
||||
.clk_dac_125_180(dac_clk_o),
|
||||
// Status and control signals
|
||||
.reset(~rst_n),
|
||||
.locked(clk_locked)
|
||||
);
|
||||
|
||||
assign locked = clk_locked;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Controller reset
|
||||
// Use both external reset and clk_wiz lock
|
||||
// -------------------------------------------------------------------------
|
||||
wire ctrl_rst_n = rst_n & clk_locked;
|
||||
|
||||
|
||||
|
||||
reflectometer_and_dma_wrapper
|
||||
#(
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
|
||||
.AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED),
|
||||
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE),
|
||||
.ZERO_LEVEL(ZERO_LEVEL),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RD_FIFO_WIDTH(RD_FIFO_WIDTH)
|
||||
) reflectometer_and_dma_wrapper_inst
|
||||
(
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.clk_sampler(clk_sampler),
|
||||
.clk_generator(clk_generator),
|
||||
.ctrl_rst_n(ctrl_rst_n),
|
||||
|
||||
.s_axil(s_axil),
|
||||
.m_axi(m_axi),
|
||||
.m_axis_read_data(m_axis_read_data),
|
||||
|
||||
.dac_data(dac_data),
|
||||
.dac_wrt(dac_wrt),
|
||||
.adc_data(adc_data),
|
||||
.adc_otr(adc_otr)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,65 @@
|
||||
TOPLEVEL_LANG = verilog
|
||||
SIM ?= questa
|
||||
WAVES = 1
|
||||
WLF_FILE := $(SIM_BUILD)/waves.wlf
|
||||
|
||||
PWD := $(shell pwd)
|
||||
|
||||
|
||||
RTL_DIR = $(PWD)/../src
|
||||
RTL_ACCUM_DIR = $(PWD)/../../../rtl/accum/src
|
||||
RTL_GENERATOR_DIR = $(PWD)/../../../rtl/generator/src
|
||||
RTL_SAMPLER_DIR = $(PWD)/../../../rtl/sampler/src
|
||||
RTL_CTRL_DIR = $(PWD)/../../../rtl/controller_new/src
|
||||
LIBS_DIR = $(PWD)/../../../external/rtl_libs
|
||||
|
||||
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi_pkg.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/dma_reg_pkg.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi_if.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axis_if.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axis_if_to_flat.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/rtl/axi4l_flat_to_if.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/axi/axi_reg/axi4l_reg_map.sv
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma_rd.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma_wr.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_dma.v
|
||||
VERILOG_SOURCES += $(LIBS_DIR)/external/verilog-axi/rtl/axi_ram.v
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi_ram_wrapper.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/controller.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/dma_controller.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/shaper_axis_desc.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/shaper_axis_status.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/controller_wrapper_axil.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/axi4l_reg_map_controller_pkg.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/axis_defaults_helper.sv
|
||||
VERILOG_SOURCES += $(RTL_CTRL_DIR)/axi4l_reg_map_controller.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/axi_dma_wrapper_if.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/wrapper_controller_dma.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/adder.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/out_axis_fifo.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/accum.sv
|
||||
VERILOG_SOURCES += $(RTL_ACCUM_DIR)/accum_top.sv
|
||||
VERILOG_SOURCES += $(RTL_GENERATOR_DIR)/generator.sv
|
||||
VERILOG_SOURCES += $(RTL_SAMPLER_DIR)/sampler.sv
|
||||
|
||||
VERILOG_SOURCES += $(PWD)/adc_model.sv
|
||||
VERILOG_SOURCES += $(PWD)/dac_model.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/reflectometer_ip.sv
|
||||
VERILOG_SOURCES += $(RTL_DIR)/reflectometer_and_dma_wrapper.sv
|
||||
VERILOG_SOURCES += $(PWD)/tb_full_reflectometer.sv
|
||||
VERILOG_SOURCES += /mnt/c/Xilinx/Vivado/2021.2/data/verilog/src/glbl.v
|
||||
|
||||
TOPLEVEL = tb_full_reflectometer
|
||||
MODULE = full_reflectometer_test
|
||||
|
||||
|
||||
ifeq ($(SIM),questa)
|
||||
SIM_ARGS += -L xpm -L unisim
|
||||
SIM_ARGS += work.glbl
|
||||
SIM_ARGS += -wlf $(WLF_FILE)
|
||||
COMPILE_ARGS += +acc
|
||||
endif
|
||||
|
||||
|
||||
include $(shell cocotb-config --makefiles)/Makefile.sim
|
||||
@@ -0,0 +1,59 @@
|
||||
// AN9238 virtual ADC model (1 port)
|
||||
|
||||
module virtual_adc_model #(
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
|
||||
// Bipolar input range: +/- VOLTAGE_RANGE
|
||||
parameter real VOLTAGE_RANGE = 1.0,
|
||||
|
||||
// Analog input correction
|
||||
parameter real VOLTAGE_GAIN = 0.2,
|
||||
parameter real GROUND_BIAS = 0.0,
|
||||
|
||||
// ADC timing parameters
|
||||
parameter time CONVERSION_DELAY = 250ps
|
||||
)(
|
||||
input logic clk_i,
|
||||
input real voltage_i,
|
||||
|
||||
output logic otr_o,
|
||||
output logic [ADC_DATA_WIDTH-1:0] data_o
|
||||
);
|
||||
|
||||
localparam int unsigned ZERO_CODE = (1 << (ADC_DATA_WIDTH - 1));
|
||||
localparam real VOLTAGE_STEP = (2 * VOLTAGE_RANGE) / real'((1 << ADC_DATA_WIDTH) - 1);
|
||||
|
||||
real voltage_corrected;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Convert analog voltage to ADC code
|
||||
//------------------------------------------------------------
|
||||
function automatic logic [ADC_DATA_WIDTH-1:0] voltage_to_code( input real voltage );
|
||||
if (voltage <= -VOLTAGE_RANGE) return '0;
|
||||
if (voltage >= VOLTAGE_RANGE) return {ADC_DATA_WIDTH{1'b1}};
|
||||
return $rtoi(voltage / VOLTAGE_STEP + real'((ZERO_CODE)) + 0.5);
|
||||
endfunction
|
||||
|
||||
function automatic logic range_check( input real voltage );
|
||||
real v_abs = (voltage < 0.0) ? -voltage : voltage;
|
||||
return v_abs >= VOLTAGE_RANGE;
|
||||
endfunction
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Initial state
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
data_o = ZERO_CODE; // 0V
|
||||
otr_o = 0;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Update analog output
|
||||
//------------------------------------------------------------
|
||||
always @(posedge clk_i) begin
|
||||
voltage_corrected = (voltage_i - GROUND_BIAS) * VOLTAGE_GAIN;
|
||||
data_o <= #(CONVERSION_DELAY) voltage_to_code(voltage_corrected);
|
||||
otr_o <= #(CONVERSION_DELAY) range_check(voltage_corrected);
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,58 @@
|
||||
// AN9767 model (1 port)
|
||||
|
||||
module virtual_dac_model #(
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
|
||||
// Bipolar output range: +/- VOLTAGE_RANGE
|
||||
parameter real VOLTAGE_RANGE = 5.0,
|
||||
|
||||
// Analog output correction
|
||||
parameter real VOLTAGE_GAIN = 1.0,
|
||||
parameter real GROUND_BIAS = 0.0,
|
||||
|
||||
// DAC timing parameters
|
||||
parameter time TRANSMISSION_DELAY = 150ps,
|
||||
parameter time CONVERSION_DELAY = 150ps
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic wrt_i,
|
||||
input logic [DAC_DATA_WIDTH-1:0] data_i,
|
||||
|
||||
output real voltage_o
|
||||
);
|
||||
|
||||
localparam int unsigned ZERO_CODE = (1 << (DAC_DATA_WIDTH - 1));
|
||||
localparam real VOLTAGE_STEP = (2 * VOLTAGE_RANGE) / real'((1 << DAC_DATA_WIDTH) - 1);
|
||||
|
||||
logic [DAC_DATA_WIDTH-1:0] dac_code;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Convert DAC code to analog voltage
|
||||
//------------------------------------------------------------
|
||||
function automatic real code_to_voltage( input logic [DAC_DATA_WIDTH-1:0] code);
|
||||
return (int'(code) - int'(ZERO_CODE)) * VOLTAGE_STEP;
|
||||
endfunction
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Initial state
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
dac_code = '0;
|
||||
voltage_o = code_to_voltage('0) * VOLTAGE_GAIN + GROUND_BIAS;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Latch new DAC code
|
||||
//------------------------------------------------------------
|
||||
always @(posedge wrt_i) begin
|
||||
dac_code <= #(TRANSMISSION_DELAY) data_i;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Update analog output
|
||||
//------------------------------------------------------------
|
||||
always @(posedge clk_i) begin
|
||||
voltage_o <= #(CONVERSION_DELAY) code_to_voltage(dac_code) * VOLTAGE_GAIN + GROUND_BIAS;
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,185 @@
|
||||
import cocotb
|
||||
from cocotb.clock import Clock
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotbext.axi import AxiLiteBus, AxiLiteMaster
|
||||
from cocotbext.axi import AxiStreamBus, AxiStreamSink, AxiStreamSource, AxiStreamFrame
|
||||
|
||||
from reg_map import *
|
||||
|
||||
def reg_addr(reg_index: int) -> int:
|
||||
# AXI-Lite uses byte addresses, 32-bit registers are spaced by 4 bytes.
|
||||
return reg_index * 4
|
||||
|
||||
|
||||
def u32(value: int) -> bytes:
|
||||
return int(value & 0xFFFFFFFF).to_bytes(4, "little")
|
||||
|
||||
class Drivers:
|
||||
def __init__(self, dut):
|
||||
self.dut = dut
|
||||
|
||||
cocotb.start_soon(Clock(dut.ctrl_clk, 5, unit="ns").start())
|
||||
|
||||
cocotb.start_soon(Clock(dut.clk_sampler, 15.384, unit="ns").start())
|
||||
|
||||
cocotb.start_soon(Clock(dut.clk_generator, 8, unit="ns").start())
|
||||
|
||||
self.axil = AxiLiteMaster(
|
||||
AxiLiteBus.from_prefix(dut, "s_axil"),
|
||||
dut.ctrl_clk,
|
||||
dut.rst)
|
||||
|
||||
|
||||
# self.axis_source = AxiStreamSource(
|
||||
# AxiStreamBus.from_prefix(dut, "s_axis_write_data"),
|
||||
# dut.ctrl_clk,
|
||||
# dut.rst)
|
||||
|
||||
self.axis_sink = AxiStreamSink(
|
||||
AxiStreamBus.from_prefix(dut, "m_axis_read_data"),
|
||||
dut.ctrl_clk,
|
||||
dut.rst)
|
||||
|
||||
async def reset(self):
|
||||
self.dut.rst.value = 1
|
||||
for _ in range(20):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
self.dut.rst.value = 0
|
||||
for _ in range(20):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
async def write_reg(self, reg_index: int, value: int):
|
||||
await self.axil.write(reg_addr(reg_index), u32(value))
|
||||
|
||||
async def read_reg(self, reg_index: int) -> int:
|
||||
resp = await self.axil.read(reg_addr(reg_index), 4)
|
||||
return int.from_bytes(bytes(resp.data), "little")
|
||||
|
||||
async def pulse_control(self, mask):
|
||||
await self.write_reg( REG_CONTROL, mask )
|
||||
|
||||
# Reflectometer Driver
|
||||
|
||||
async def configure_reflectometer (
|
||||
self,
|
||||
pulse_width,
|
||||
pulse_period,
|
||||
pulse_num,
|
||||
pulse_height,
|
||||
adc_period,
|
||||
window_size,
|
||||
timeout_cycles):
|
||||
await self.write_reg(REG_DAC_WIDTH, pulse_width)
|
||||
await self.write_reg(REG_DAC_PERIOD, pulse_period)
|
||||
await self.write_reg(REG_DAC_PULSE_NUM, pulse_num)
|
||||
await self.write_reg(REG_DAC_PULSE_HEIGHT, pulse_height)
|
||||
await self.write_reg(REG_ADC_PERIOD, adc_period)
|
||||
await self.write_reg(REG_WINDOW_SIZE, window_size)
|
||||
|
||||
await self.pulse_control(CTRL_CFG_BUS_VALID)
|
||||
|
||||
control = self.dut.dut.reflectometer_ip_inst.controller_wrapper_axil_inst.controller
|
||||
|
||||
for cycle in range(timeout_cycles):
|
||||
dac_wait = int(control.cfg_wait_dac_ack.value)
|
||||
adc_wait = int(control.cfg_wait_adc_ack.value)
|
||||
|
||||
if dac_wait == 0 and adc_wait == 0:
|
||||
print(f"Configuration done after {cycle} ctrl_clk cycles")
|
||||
return
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
async def send_start(self):
|
||||
await self.pulse_control(CTRL_START)
|
||||
|
||||
async def soft_reset(self):
|
||||
await self.pulse_control(CTRL_RST_SOFT)
|
||||
|
||||
async def get_status(self):
|
||||
status = await self.read_reg(REG_STATUS)
|
||||
return {
|
||||
"busy": bool(status & STATUS_BUSY),
|
||||
"processing_done": bool(status & STATUS_PROCESSING_DONE),
|
||||
"desc_read_busy": bool(status & STATUS_DESC_READ_BUSY),
|
||||
"desc_write_busy": bool(status & STATUS_DESC_WRITE_BUSY),
|
||||
"status_read_busy": bool(status & STATUS_STATUS_READ_BUSY),
|
||||
"status_write_busy": bool(status & STATUS_STATUS_WRITE_BUSY),
|
||||
"desc_read_hs": bool(status & STATUS_DESC_READ_HS),
|
||||
"desc_write_hs": bool(status & STATUS_DESC_WRITE_HS),
|
||||
"status_read_hs": bool(status & STATUS_STATUS_READ_HS),
|
||||
"status_write_hs": bool(status & STATUS_STATUS_WRITE_HS)
|
||||
}
|
||||
|
||||
async def wait_status(self, field, value=True, timeout_cycles=1000):
|
||||
|
||||
for _ in range(timeout_cycles):
|
||||
status = await self.get_status()
|
||||
|
||||
if status[field] == value:
|
||||
return
|
||||
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
status = await self.get_status()
|
||||
|
||||
raise TimeoutError( f"Timeout waiting for status.{field} == {value}. " f"Current status = {status}")
|
||||
|
||||
async def wait_processing_done(self, timeout_cycles=1000):
|
||||
await self.wait_status("processing_done", True, timeout_cycles)
|
||||
|
||||
|
||||
async def wait_finish(self, timeout_cycles=1000):
|
||||
await self.wait_status("busy", False, timeout_cycles)
|
||||
|
||||
# DMA Driver
|
||||
|
||||
async def send_desc_write(self, addr, length_tag):
|
||||
|
||||
await self.write_reg(REG_DESC_WRITE_ADDR, addr)
|
||||
await self.write_reg(REG_DESC_WRITE_LEN_AND_TAG, length_tag)
|
||||
await self.pulse_control(CTRL_SEND_DESC_WRITE)
|
||||
|
||||
async def send_desc_read(self, addr, length, config):
|
||||
|
||||
await self.write_reg(REG_DESC_READ_ADDR, addr)
|
||||
await self.write_reg(REG_DESC_READ_LEN, length)
|
||||
await self.write_reg(REG_DESC_READ_CONFIG, config)
|
||||
await self.pulse_control( CTRL_SEND_DESC_READ)
|
||||
|
||||
async def take_status_write(self, status_write_len, status_write_config):
|
||||
await self.write_reg(REG_CONTROL, CTRL_TAKE_STATUS_WRITE)
|
||||
|
||||
|
||||
assert await self.read_reg(REG_STATUS_WRITE_CONFIG) == status_write_config
|
||||
assert await self.read_reg(REG_STATUS_WRITE_LEN) == status_write_len
|
||||
|
||||
async def take_status_read(self, status_read):
|
||||
await self.pulse_control( CTRL_TAKE_STATUS_READ)
|
||||
for _ in range(10):
|
||||
await RisingEdge(self.dut.ctrl_clk)
|
||||
|
||||
assert await self.read_reg(REG_READ_STATUS) == status_read
|
||||
|
||||
async def wait_dma_write_done(self, timeout_cycles=1000):
|
||||
await self.wait_status("desc_write_busy", False, timeout_cycles)
|
||||
|
||||
async def wait_dma_read_done(self, timeout_cycles=1000):
|
||||
await self.wait_status("desc_read_busy", False, timeout_cycles)
|
||||
|
||||
async def wait_status_read_handshake(self, timeout_cycles=1000):
|
||||
await self.wait_status("status_read_hs", True, timeout_cycles)
|
||||
|
||||
async def wait_status_write_handshake(self, timeout_cycles=1000):
|
||||
await self.wait_status("status_write_hs", True, timeout_cycles)
|
||||
|
||||
# AxiStream Driver
|
||||
|
||||
# async def send_axis_data(self, data: bytes):
|
||||
|
||||
# await self.axis_source.send(AxiStreamFrame(data) )
|
||||
|
||||
async def receive_axis_data(self):
|
||||
|
||||
frame = await self.axis_sink.recv()
|
||||
return bytes(frame)
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
import cocotb
|
||||
from cocotb.triggers import RisingEdge
|
||||
|
||||
from drivers import Drivers
|
||||
from reference_model import Reference_model
|
||||
from scoreboard import Scoreboard
|
||||
|
||||
from reg_map import *
|
||||
|
||||
class TB:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
dut,
|
||||
pulse_width,
|
||||
pulse_period,
|
||||
pulse_num,
|
||||
pulse_height,
|
||||
adc_period,
|
||||
window_size
|
||||
):
|
||||
self.dut = dut
|
||||
|
||||
self.driver = Drivers(dut)
|
||||
|
||||
self.reference = Reference_model(
|
||||
dut=dut,
|
||||
|
||||
pulse_width=pulse_width,
|
||||
pulse_period=pulse_period,
|
||||
pulse_num=pulse_num,
|
||||
pulse_height=pulse_height,
|
||||
adc_period=adc_period,
|
||||
window_size=window_size,
|
||||
|
||||
DAC_DATA_WIDTH=DAC_DATA_WIDTH,
|
||||
ADC_DATA_WIDTH=ADC_DATA_WIDTH,
|
||||
PACK_FACTOR=PACK_FACTOR,
|
||||
PROCESS_MODE=PROCESS_MODE,
|
||||
ZERO_LEVEL=ZERO_LEVEL,
|
||||
ACCUM_WIDTH=ACCUM_WIDTH,
|
||||
N_MAX=N_MAX,
|
||||
PACKET_SIZE=PACKET_SIZE,
|
||||
RD_FIFO_WIDTH=RD_FIFO_WIDTH,
|
||||
)
|
||||
|
||||
self.scoreboard = Scoreboard()
|
||||
|
||||
|
||||
SEQ_NUM = 1
|
||||
WINDOW_SIZE = 1
|
||||
|
||||
PULSE_WIDTH = 10
|
||||
PULSE_PERIOD = 20
|
||||
PULSE_HEIGHT = 15000
|
||||
ADC_PERIOD = 20
|
||||
|
||||
@cocotb.test()
|
||||
async def rest_init(dut):
|
||||
tb = TB(dut,
|
||||
pulse_width=PULSE_WIDTH,
|
||||
pulse_period=PULSE_PERIOD,
|
||||
pulse_num=SEQ_NUM,
|
||||
pulse_height=PULSE_HEIGHT,
|
||||
adc_period=ADC_PERIOD,
|
||||
window_size=WINDOW_SIZE)
|
||||
await tb.driver.reset()
|
||||
|
||||
@cocotb.test()
|
||||
async def base_full_test(dut):
|
||||
tb = TB(dut,
|
||||
pulse_width=PULSE_WIDTH,
|
||||
pulse_period=PULSE_PERIOD,
|
||||
pulse_num=SEQ_NUM,
|
||||
pulse_height=PULSE_HEIGHT,
|
||||
adc_period=ADC_PERIOD,
|
||||
window_size=WINDOW_SIZE
|
||||
)
|
||||
await tb.driver.reset()
|
||||
await tb.driver.soft_reset()
|
||||
|
||||
RESULT_ADDR = 0x1000
|
||||
|
||||
await tb.driver.configure_reflectometer(
|
||||
pulse_width = PULSE_WIDTH,
|
||||
pulse_period=PULSE_PERIOD,
|
||||
pulse_num=SEQ_NUM,
|
||||
pulse_height=PULSE_HEIGHT,
|
||||
adc_period=ADC_PERIOD,
|
||||
window_size=WINDOW_SIZE,
|
||||
timeout_cycles=1000
|
||||
)
|
||||
|
||||
samples = tb.reference.gen_input_samples()
|
||||
|
||||
SMP_NUM = len(samples[0])
|
||||
# SMP_NUM = ADC_PERIOD
|
||||
|
||||
expected = tb.reference.calculate_expected( samples, WINDOW_SIZE, ACCUM_WIDTH)
|
||||
|
||||
print("")
|
||||
print("========================================")
|
||||
print("ACCUMULATOR RANDOM TEST")
|
||||
print("========================================")
|
||||
print(f"seq_num = {SEQ_NUM}")
|
||||
print(f"smp_num = {SMP_NUM}")
|
||||
print(f"window_size = {WINDOW_SIZE}")
|
||||
print(f"data_width = {ADC_DATA_WIDTH}")
|
||||
print(f"accum_width = {ACCUM_WIDTH}")
|
||||
print(f"expected words = {len(expected)}")
|
||||
|
||||
RESULT_WORDS = len(expected)
|
||||
RESULT_BYTES = RESULT_WORDS * 4
|
||||
|
||||
|
||||
print("==============================")
|
||||
print("ACCUM TEST")
|
||||
print("words =", RESULT_WORDS)
|
||||
print("bytes =", RESULT_BYTES)
|
||||
print("==============================")
|
||||
|
||||
for _ in range(10):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
await tb.driver.send_start()
|
||||
|
||||
for _ in range(4):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
await tb.driver.wait_processing_done(timeout_cycles=100000)
|
||||
|
||||
await tb.driver.send_desc_write( addr=RESULT_ADDR, length_tag=RESULT_BYTES )
|
||||
await tb.driver.wait_dma_write_done(timeout_cycles=5000)
|
||||
|
||||
for _ in range(100):
|
||||
await RisingEdge(dut.ctrl_clk)
|
||||
|
||||
# await tb.driver.take_status_write(status_write_len=RESULT_BYTES, status_write_config=0)
|
||||
|
||||
await tb.driver.send_desc_read(addr=RESULT_ADDR, length=RESULT_BYTES, config=0x0000_0001 )
|
||||
|
||||
received_data = await tb.driver.receive_axis_data()
|
||||
|
||||
await tb.driver.wait_dma_read_done(timeout_cycles=5000)
|
||||
|
||||
|
||||
await tb.driver.take_status_read(status_read=0x1)
|
||||
|
||||
|
||||
received = tb.scoreboard.bytes_to_words(received_data, RD_FIFO_WIDTH)
|
||||
|
||||
print("")
|
||||
print("Expected:")
|
||||
for i, value in enumerate(expected):
|
||||
print(f" [{i}] = 0x{value:08X}")
|
||||
|
||||
print("")
|
||||
print("Received:")
|
||||
for i, value in enumerate(received):
|
||||
print(f" [{i}] = 0x{value:08X}")
|
||||
|
||||
tb.scoreboard.check_results(
|
||||
expected=expected,
|
||||
received=received
|
||||
)
|
||||
|
||||
print("")
|
||||
print("========================================")
|
||||
print("ACCUMULATOR RANDOM TEST PASSED")
|
||||
print("========================================")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
from reg_map import *
|
||||
|
||||
class Reference_model:
|
||||
def __init__(
|
||||
self,
|
||||
dut,
|
||||
pulse_width,
|
||||
pulse_period,
|
||||
pulse_num,
|
||||
pulse_height,
|
||||
adc_period,
|
||||
window_size,
|
||||
DAC_DATA_WIDTH,
|
||||
ADC_DATA_WIDTH,
|
||||
PACK_FACTOR,
|
||||
PROCESS_MODE,
|
||||
ZERO_LEVEL,
|
||||
ACCUM_WIDTH,
|
||||
N_MAX,
|
||||
PACKET_SIZE,
|
||||
RD_FIFO_WIDTH
|
||||
):
|
||||
|
||||
self.dut = dut
|
||||
|
||||
# configuration
|
||||
self.pulse_width = pulse_width
|
||||
self.pulse_period = pulse_period
|
||||
self.pulse_num = pulse_num
|
||||
self.pulse_height = pulse_height
|
||||
self.adc_sample_num = adc_period
|
||||
self.window_size = window_size
|
||||
|
||||
# parameters
|
||||
self.DAC_DATA_WIDTH = DAC_DATA_WIDTH
|
||||
self.ADC_DATA_WIDTH = ADC_DATA_WIDTH
|
||||
self.PACK_FACTOR = PACK_FACTOR
|
||||
self.PROCESS_MODE = PROCESS_MODE
|
||||
self.ZERO_LEVEL = ZERO_LEVEL
|
||||
self.ACCUM_WIDTH = ACCUM_WIDTH
|
||||
self.N_MAX = N_MAX
|
||||
self.PACKET_SIZE = PACKET_SIZE
|
||||
self.RD_FIFO_WIDTH = RD_FIFO_WIDTH
|
||||
|
||||
# intermediate data
|
||||
self.samples = []
|
||||
self.expected = []
|
||||
|
||||
|
||||
def gen_input_samples(self):
|
||||
|
||||
self.samples = []
|
||||
|
||||
# -----------------------------
|
||||
# DAC: 14 bit
|
||||
# -----------------------------
|
||||
DAC_ZERO = self.ZERO_LEVEL
|
||||
DAC_MAX = (1 << self.DAC_DATA_WIDTH) - 1
|
||||
|
||||
DAC_RANGE = 5.0
|
||||
|
||||
DAC_STEP = (
|
||||
2.0 * DAC_RANGE
|
||||
) / DAC_MAX
|
||||
|
||||
# -----------------------------
|
||||
# ADC: 12 bit
|
||||
# -----------------------------
|
||||
ADC_ZERO = 1 << (self.ADC_DATA_WIDTH - 1)
|
||||
ADC_MAX = (1 << self.ADC_DATA_WIDTH) - 1
|
||||
|
||||
ADC_RANGE = 1.0
|
||||
ADC_GAIN = 0.2
|
||||
GROUND_BIAS = 0.0
|
||||
|
||||
ADC_STEP = (
|
||||
2.0 * ADC_RANGE
|
||||
) / ADC_MAX
|
||||
|
||||
# -----------------------------
|
||||
# Generate every pulse sequence
|
||||
# -----------------------------
|
||||
for _ in range(self.pulse_num):
|
||||
|
||||
pulse_samples = []
|
||||
|
||||
for sample_idx in range(self.adc_sample_num):
|
||||
|
||||
# ==========================================
|
||||
# 1. Generator produces a 14-bit DAC code
|
||||
# ==========================================
|
||||
if sample_idx < self.pulse_width:
|
||||
dac_code = self.pulse_height
|
||||
else:
|
||||
dac_code = DAC_ZERO
|
||||
|
||||
# Limit to actual DAC width
|
||||
dac_code = max(0, min(dac_code, DAC_MAX))
|
||||
|
||||
# ==========================================
|
||||
# 2. 14-bit DAC code -> analog voltage
|
||||
# ==========================================
|
||||
voltage = (
|
||||
(dac_code - DAC_ZERO)
|
||||
* DAC_STEP
|
||||
)
|
||||
|
||||
# ==========================================
|
||||
# 3. Analog path -> ADC input voltage
|
||||
# ==========================================
|
||||
voltage = (
|
||||
(voltage - GROUND_BIAS)
|
||||
* ADC_GAIN
|
||||
)
|
||||
|
||||
# ==========================================
|
||||
# 4. Analog voltage -> 12-bit ADC code
|
||||
# ==========================================
|
||||
if voltage <= -ADC_RANGE:
|
||||
|
||||
adc_code = 0
|
||||
|
||||
elif voltage >= ADC_RANGE:
|
||||
|
||||
adc_code = ADC_MAX
|
||||
|
||||
else:
|
||||
|
||||
adc_code = int(
|
||||
round(
|
||||
voltage / ADC_STEP
|
||||
+ ADC_ZERO
|
||||
)
|
||||
)
|
||||
|
||||
# Make absolutely sure that the result
|
||||
# is a valid 12-bit value.
|
||||
adc_code = max(
|
||||
0,
|
||||
min(adc_code, ADC_MAX)
|
||||
)
|
||||
|
||||
# ==========================================
|
||||
# 5. ADC out-of-range processing
|
||||
# ==========================================
|
||||
out_of_range = (
|
||||
abs(voltage) >= ADC_RANGE
|
||||
)
|
||||
|
||||
if self.PROCESS_MODE:
|
||||
|
||||
msb = (
|
||||
adc_code
|
||||
>> (self.ADC_DATA_WIDTH - 1)
|
||||
) & 1
|
||||
|
||||
if out_of_range:
|
||||
|
||||
if msb:
|
||||
sample = ADC_MAX
|
||||
else:
|
||||
sample = 0
|
||||
|
||||
else:
|
||||
|
||||
sample = (
|
||||
(((~msb) & 1)
|
||||
<< (self.ADC_DATA_WIDTH - 1))
|
||||
|
|
||||
(
|
||||
adc_code
|
||||
& (
|
||||
(1 << (self.ADC_DATA_WIDTH - 1))
|
||||
- 1
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
else:
|
||||
|
||||
if out_of_range:
|
||||
|
||||
if adc_code & ADC_ZERO:
|
||||
sample = ADC_MAX
|
||||
else:
|
||||
sample = 0
|
||||
|
||||
else:
|
||||
|
||||
sample = adc_code
|
||||
|
||||
# ==========================================
|
||||
# Final sample is ALWAYS 12-bit ADC data
|
||||
# ==========================================
|
||||
sample &= ADC_MAX
|
||||
|
||||
pulse_samples.append(sample)
|
||||
|
||||
self.samples.append(pulse_samples)
|
||||
|
||||
return self.samples
|
||||
|
||||
|
||||
|
||||
|
||||
def calculate_expected(
|
||||
self,
|
||||
samples,
|
||||
window_size: int,
|
||||
accum_width: int):
|
||||
if window_size <= 0:
|
||||
raise ValueError( f"window_size must be > 0, got {window_size}")
|
||||
|
||||
if not samples:
|
||||
raise ValueError("samples must not be empty")
|
||||
|
||||
seq_num = len(samples)
|
||||
smp_num = len(samples[0])
|
||||
|
||||
if smp_num == 0:
|
||||
raise ValueError("samples must not contain empty sequences")
|
||||
|
||||
for seq_idx, seq_samples in enumerate(samples):
|
||||
if len(seq_samples) != smp_num:
|
||||
raise ValueError(f"Sequence {seq_idx} has {len(seq_samples)} samples, " f"expected {smp_num}" )
|
||||
|
||||
if smp_num % window_size != 0:
|
||||
raise ValueError(f"smp_num ({smp_num}) must be divisible " f"by window_size ({window_size})")
|
||||
|
||||
exp_word_count = smp_num // window_size
|
||||
accum_mask = (1 << accum_width) - 1
|
||||
|
||||
expected = []
|
||||
|
||||
for word_idx in range(exp_word_count):
|
||||
local_sum = 0
|
||||
|
||||
for seq_idx in range(seq_num):
|
||||
for k in range(window_size):
|
||||
sample_idx = word_idx * window_size + k
|
||||
local_sum += samples[seq_idx][sample_idx]
|
||||
|
||||
expected.append(local_sum & accum_mask)
|
||||
|
||||
return expected
|
||||
|
||||
|
||||
def run(self):
|
||||
self.gen_input_samples()
|
||||
|
||||
self.expected = self.calculate_expected( self.samples, self.window_size, self.ACCUM_WIDTH)
|
||||
|
||||
return self.expected
|
||||
@@ -0,0 +1,54 @@
|
||||
# Register indexes from axi4l_reg_map_controller_pkg.sv
|
||||
REG_CONTROL = 0
|
||||
REG_STATUS = 1
|
||||
REG_DAC_WIDTH = 2
|
||||
REG_DAC_PERIOD = 3
|
||||
REG_DAC_PULSE_NUM = 4
|
||||
REG_DAC_PULSE_HEIGHT = 5
|
||||
REG_ADC_PERIOD = 6
|
||||
REG_WINDOW_SIZE = 7
|
||||
REG_ERROR = 8
|
||||
REG_DESC_READ_ADDR = 9
|
||||
REG_DESC_READ_LEN = 10
|
||||
REG_DESC_READ_CONFIG = 11
|
||||
REG_READ_STATUS = 12
|
||||
REG_DESC_WRITE_ADDR = 13
|
||||
REG_DESC_WRITE_LEN_AND_TAG = 14
|
||||
REG_STATUS_WRITE_LEN = 15
|
||||
REG_STATUS_WRITE_CONFIG = 16
|
||||
|
||||
|
||||
# REG_CONTROL pulse bits
|
||||
CTRL_START = 1 << 0
|
||||
CTRL_RST_SOFT = 1 << 1
|
||||
CTRL_CFG_BUS_VALID = 1 << 2
|
||||
CTRL_SEND_DESC_READ = 1 << 3
|
||||
CTRL_SEND_DESC_WRITE = 1 << 4
|
||||
CTRL_TAKE_STATUS_READ = 1 << 5
|
||||
CTRL_TAKE_STATUS_WRITE = 1 << 6
|
||||
|
||||
# REG_STATUS bits
|
||||
STATUS_BUSY = 1 << 0
|
||||
STATUS_PROCESSING_DONE = 1 << 1
|
||||
|
||||
STATUS_DESC_READ_BUSY = 1 << 2
|
||||
STATUS_DESC_WRITE_BUSY = 1 << 3
|
||||
STATUS_STATUS_READ_BUSY = 1 << 4
|
||||
STATUS_STATUS_WRITE_BUSY = 1 << 5
|
||||
|
||||
STATUS_DESC_READ_HS = 1 << 6
|
||||
STATUS_DESC_WRITE_HS = 1 << 7
|
||||
STATUS_STATUS_READ_HS = 1 << 8
|
||||
STATUS_STATUS_WRITE_HS = 1 << 9
|
||||
|
||||
# PARAMETERS for accumulator reference model
|
||||
|
||||
DAC_DATA_WIDTH = 14
|
||||
ADC_DATA_WIDTH = 12
|
||||
PACK_FACTOR = 1
|
||||
PROCESS_MODE = 0
|
||||
ZERO_LEVEL = 8192
|
||||
ACCUM_WIDTH = 32
|
||||
N_MAX = 4096
|
||||
PACKET_SIZE = 1024
|
||||
RD_FIFO_WIDTH = 32
|
||||
@@ -0,0 +1,40 @@
|
||||
from reg_map import *
|
||||
|
||||
class Scoreboard:
|
||||
def __init__(self):
|
||||
|
||||
self.test_passed = False
|
||||
|
||||
|
||||
def bytes_to_words(self, data: bytes, word_width: int = 32):
|
||||
word_bytes = word_width // 8
|
||||
|
||||
if len(data) % word_bytes != 0:
|
||||
raise ValueError(f"Data length {len(data)} is not divisible " f"by word size {word_bytes}" )
|
||||
|
||||
words = []
|
||||
|
||||
for i in range(0, len(data), word_bytes):
|
||||
word = int.from_bytes(data[i:i + word_bytes], byteorder="little" )
|
||||
words.append(word)
|
||||
|
||||
return words
|
||||
|
||||
|
||||
def check_results(self, expected, received):
|
||||
|
||||
assert len(received) == len(expected), (
|
||||
f"Number of words mismatch: "
|
||||
f"expected={len(expected)}, "
|
||||
f"received={len(received)}" )
|
||||
|
||||
for i, (exp, rec) in enumerate(zip(expected, received)):
|
||||
assert rec == exp, (
|
||||
f"Payload mismatch at index {i}: "
|
||||
f"expected=0x{exp:08X}, "
|
||||
f"received=0x{rec:08X}" )
|
||||
self.test_passed = True
|
||||
|
||||
print( f"Payload check passed: " f"{len(expected)} words")
|
||||
|
||||
return True
|
||||
@@ -0,0 +1,263 @@
|
||||
|
||||
import dma_reg_pkg::*;
|
||||
|
||||
module tb_full_reflectometer #(
|
||||
// parameters for base reflectometer works
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter int unsigned PACK_FACTOR = 1,
|
||||
parameter int unsigned PROCESS_MODE = 0,
|
||||
parameter int unsigned ZERO_LEVEL = 8192,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 64,
|
||||
parameter int unsigned RD_FIFO_WIDTH = 32,
|
||||
|
||||
// parameters for DMA and interfaces
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
|
||||
parameter int unsigned AXI_DATA_WIDTH = 32,
|
||||
|
||||
parameter int unsigned AXI_STRB_WIDTH = AXI_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXI_USER_WIDTH = 1,
|
||||
parameter int unsigned AXI_ID_WIDTH = 8,
|
||||
parameter int unsigned AXI_MAX_BURST_LEN = 16,
|
||||
|
||||
parameter int unsigned AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
|
||||
parameter int unsigned AXIS_KEEP_ENABLE = AXIS_DATA_WIDTH > 8,
|
||||
parameter int unsigned AXIS_KEEP_WIDTH = AXIS_DATA_WIDTH / 8,
|
||||
parameter int unsigned AXIS_LAST_ENABLE = 1,
|
||||
parameter int unsigned AXIS_ID_ENABLE = 1,
|
||||
parameter int unsigned AXIS_DEST_ENABLE = 0,
|
||||
parameter int unsigned AXIS_USER_ENABLE = 1,
|
||||
|
||||
parameter int unsigned ENABLE_SG = 0,
|
||||
parameter int unsigned ENABLE_UNALIGNED = 0,
|
||||
|
||||
parameter int unsigned PIPELINE_OUTPUT = 0
|
||||
)(
|
||||
input logic ctrl_clk,
|
||||
input logic clk_sampler,
|
||||
input logic clk_generator,
|
||||
input logic rst,
|
||||
|
||||
input logic [ADDR_W-1:0] s_axil_awaddr,
|
||||
input logic [2:0] s_axil_awprot,
|
||||
input logic s_axil_awvalid,
|
||||
output logic s_axil_awready,
|
||||
|
||||
input logic [DATA_W-1:0] s_axil_wdata,
|
||||
input logic [DATA_W/8-1:0] s_axil_wstrb,
|
||||
input logic s_axil_wvalid,
|
||||
output logic s_axil_wready,
|
||||
|
||||
output logic [1:0] s_axil_bresp,
|
||||
output logic s_axil_bvalid,
|
||||
input logic s_axil_bready,
|
||||
|
||||
input logic [ADDR_W-1:0] s_axil_araddr,
|
||||
input logic [2:0] s_axil_arprot,
|
||||
input logic s_axil_arvalid,
|
||||
output logic s_axil_arready,
|
||||
|
||||
output logic [DATA_W-1:0] s_axil_rdata,
|
||||
output logic [1:0] s_axil_rresp,
|
||||
output logic s_axil_rvalid,
|
||||
input logic s_axil_rready,
|
||||
|
||||
output wire [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata,
|
||||
output wire [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep,
|
||||
output wire m_axis_read_data_tvalid,
|
||||
input wire m_axis_read_data_tready,
|
||||
output wire m_axis_read_data_tlast,
|
||||
output wire [dma_reg_pkg::AXIS_ID_WIDTH-1:0] m_axis_read_data_tid,
|
||||
output wire [dma_reg_pkg::AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest,
|
||||
output wire [dma_reg_pkg::AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser
|
||||
);
|
||||
|
||||
logic rst_n;
|
||||
logic dac_wrt;
|
||||
|
||||
OBUF OBUF_pulse_clk (
|
||||
.I(clk_generator),
|
||||
.O(dac_wrt)
|
||||
);
|
||||
|
||||
assign rst_n = ~rst;
|
||||
|
||||
wire adc_otr;
|
||||
wire [ADC_DATA_WIDTH-1:0] adc_data;
|
||||
|
||||
wire [DAC_DATA_WIDTH-1:0] dac_data;
|
||||
|
||||
real signal_voltage;
|
||||
|
||||
virtual_dac_model #( // default voltage range is +/- 5V
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
) virtual_dac (
|
||||
.clk_i(clk_generator),
|
||||
.wrt_i(dac_wrt),
|
||||
.data_i(dac_data),
|
||||
.voltage_o(signal_voltage)
|
||||
);
|
||||
|
||||
virtual_adc_model #( // default voltage range is +/- 5V
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH)
|
||||
) virtual_adc (
|
||||
.clk_i(clk_sampler),
|
||||
.voltage_i(signal_voltage),
|
||||
.otr_o(adc_otr),
|
||||
.data_o(adc_data)
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AXI-Lite flat -> axi4l_if
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
axi4l_if #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W)
|
||||
) axil_bus (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
axi4l_flat_to_if #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W)
|
||||
) u_axil_flat_to_if (
|
||||
.s_axil_awaddr (s_axil_awaddr),
|
||||
.s_axil_awprot (s_axil_awprot),
|
||||
.s_axil_awvalid(s_axil_awvalid),
|
||||
.s_axil_awready(s_axil_awready),
|
||||
|
||||
.s_axil_wdata (s_axil_wdata),
|
||||
.s_axil_wstrb (s_axil_wstrb),
|
||||
.s_axil_wvalid (s_axil_wvalid),
|
||||
.s_axil_wready (s_axil_wready),
|
||||
|
||||
.s_axil_bresp (s_axil_bresp),
|
||||
.s_axil_bvalid (s_axil_bvalid),
|
||||
.s_axil_bready (s_axil_bready),
|
||||
|
||||
.s_axil_araddr (s_axil_araddr),
|
||||
.s_axil_arprot (s_axil_arprot),
|
||||
.s_axil_arvalid(s_axil_arvalid),
|
||||
.s_axil_arready(s_axil_arready),
|
||||
|
||||
.s_axil_rdata (s_axil_rdata),
|
||||
.s_axil_rresp (s_axil_rresp),
|
||||
.s_axil_rvalid (s_axil_rvalid),
|
||||
.s_axil_rready (s_axil_rready),
|
||||
|
||||
.m_axil(axil_bus)
|
||||
);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// AXIS interfaces for the updated controller_wrapper_axil
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// AXIS READ DMA MASTER output
|
||||
axis_if #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W (dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) dma_read_data (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
logic [AXIS_KEEP_WIDTH-1:0] unused_read_tstrb;
|
||||
|
||||
axis_if_to_flat #(
|
||||
.DATA_W (AXIS_DATA_WIDTH),
|
||||
.KEEP_W (AXIS_KEEP_WIDTH),
|
||||
.ID_W (AXIS_ID_WIDTH),
|
||||
.DEST_W (dma_reg_pkg::AXIS_DEST_WIDTH),
|
||||
.USER_W (dma_reg_pkg::AXIS_USER_WIDTH)
|
||||
) u_read_data_if_to_flat (
|
||||
.s_axis(dma_read_data),
|
||||
|
||||
.m_axis_tdata (m_axis_read_data_tdata),
|
||||
.m_axis_tkeep (m_axis_read_data_tkeep),
|
||||
.m_axis_tstrb (unused_read_tstrb),
|
||||
.m_axis_tlast (m_axis_read_data_tlast),
|
||||
.m_axis_tid (m_axis_read_data_tid),
|
||||
.m_axis_tdest (m_axis_read_data_tdest),
|
||||
.m_axis_tuser (m_axis_read_data_tuser),
|
||||
.m_axis_tvalid(m_axis_read_data_tvalid),
|
||||
.m_axis_tready(m_axis_read_data_tready)
|
||||
);
|
||||
|
||||
axi4_if #(
|
||||
.ADDR_W(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.DATA_W(AXI_DATA_WIDTH),
|
||||
.ID_W (AXI_ID_WIDTH),
|
||||
.USER_W(AXI_USER_WIDTH)
|
||||
) m_axi (
|
||||
.aclk(ctrl_clk),
|
||||
.aresetn(rst_n)
|
||||
);
|
||||
|
||||
reflectometer_and_dma_wrapper #(
|
||||
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
|
||||
.AXI_USER_WIDTH(AXI_USER_WIDTH),
|
||||
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
|
||||
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
|
||||
.AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
|
||||
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
|
||||
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
|
||||
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
|
||||
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
|
||||
.ENABLE_SG(ENABLE_SG),
|
||||
.ENABLE_UNALIGNED(ENABLE_UNALIGNED),
|
||||
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE),
|
||||
.ZERO_LEVEL(ZERO_LEVEL),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE),
|
||||
.RD_FIFO_WIDTH(RD_FIFO_WIDTH)
|
||||
) dut (
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.clk_sampler(clk_sampler),
|
||||
.clk_generator(clk_generator),
|
||||
.ctrl_rst_n(rst_n),
|
||||
.s_axil(axil_bus),
|
||||
|
||||
.m_axi(m_axi),
|
||||
|
||||
.m_axis_read_data(dma_read_data),
|
||||
|
||||
.dac_data(dac_data),
|
||||
.adc_data(adc_data),
|
||||
.adc_otr(adc_otr)
|
||||
);
|
||||
|
||||
axi_ram_wrapper
|
||||
#(
|
||||
.DATA_WIDTH(AXI_DATA_WIDTH),
|
||||
.ADDR_WIDTH(dma_reg_pkg::AXI_ADDR_WIDTH),
|
||||
.ID_WIDTH(dma_reg_pkg::AXIS_ID_WIDTH),
|
||||
.PIPELINE_OUTPUT(PIPELINE_OUTPUT)
|
||||
) axi_ram_wrapper_inst
|
||||
(
|
||||
.clk(ctrl_clk),
|
||||
.rst(rst),
|
||||
.s_axi(m_axi)
|
||||
);
|
||||
|
||||
|
||||
|
||||
endmodule : tb_full_reflectometer
|
||||
@@ -10,13 +10,21 @@
|
||||
FPGA_PART = xc7a100tfgg484-2
|
||||
FPGA_TOP = reflectometer_top
|
||||
FPGA_ARCH = artix7
|
||||
SIM_TOP = reflectometer_tb
|
||||
|
||||
RTL_DIR = ../../rtl
|
||||
|
||||
|
||||
include ../../scripts/vivado.mk
|
||||
|
||||
|
||||
INC_FILES += interfaces.svh
|
||||
|
||||
TB_FILES += reflectometer_tb.sv
|
||||
SYN_FILES += reflectometer.sv
|
||||
SYN_FILES += dac_model.sv
|
||||
SYN_FILES += adc_model.sv
|
||||
SYN_FILES += reflectometer_tb.sv
|
||||
SYN_FILES += $(sort $(shell find ../../rtl -type f \( -name '*.v' -o -name '*.sv' \)))
|
||||
|
||||
XCI_FILES = $(sort $(shell find ../../rtl/ethernet-udp/src -type f -name '*.xci'))
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// AN9238 virtual ADC model (1 port)
|
||||
|
||||
module virtual_adc_model #(
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
|
||||
// Bipolar input range: +/- VOLTAGE_RANGE
|
||||
parameter real VOLTAGE_RANGE = 1.0,
|
||||
|
||||
// Analog input correction
|
||||
parameter real VOLTAGE_GAIN = 0.2,
|
||||
parameter real GROUND_BIAS = 0.0,
|
||||
|
||||
// ADC timing parameters
|
||||
parameter time CONVERSION_DELAY = 250ps
|
||||
)(
|
||||
input logic clk_i,
|
||||
input real voltage_i,
|
||||
|
||||
output logic otr_o,
|
||||
output logic [ADC_DATA_WIDTH-1:0] data_o
|
||||
);
|
||||
|
||||
localparam int unsigned ZERO_CODE = (1 << (ADC_DATA_WIDTH - 1));
|
||||
localparam real VOLTAGE_STEP = (2 * VOLTAGE_RANGE) / real'((1 << ADC_DATA_WIDTH) - 1);
|
||||
|
||||
real voltage_corrected;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Convert analog voltage to ADC code
|
||||
//------------------------------------------------------------
|
||||
function automatic logic [ADC_DATA_WIDTH-1:0] voltage_to_code( input real voltage );
|
||||
if (voltage <= -VOLTAGE_RANGE) return '0;
|
||||
if (voltage >= VOLTAGE_RANGE) return {ADC_DATA_WIDTH{1'b1}};
|
||||
return $rtoi(voltage / VOLTAGE_STEP + real'((ZERO_CODE)) + 0.5);
|
||||
endfunction
|
||||
|
||||
function automatic logic range_check( input real voltage );
|
||||
real v_abs = (voltage < 0.0) ? -voltage : voltage;
|
||||
return v_abs >= VOLTAGE_RANGE;
|
||||
endfunction
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Initial state
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
data_o = ZERO_CODE; // 0V
|
||||
otr_o = 0;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Update analog output
|
||||
//------------------------------------------------------------
|
||||
always @(posedge clk_i) begin
|
||||
voltage_corrected = (voltage_i - GROUND_BIAS) * VOLTAGE_GAIN;
|
||||
data_o <= #(CONVERSION_DELAY) voltage_to_code(voltage_corrected);
|
||||
otr_o <= #(CONVERSION_DELAY) range_check(voltage_corrected);
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,58 @@
|
||||
// AN9767 model (1 port)
|
||||
|
||||
module virtual_dac_model #(
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
|
||||
// Bipolar output range: +/- VOLTAGE_RANGE
|
||||
parameter real VOLTAGE_RANGE = 5.0,
|
||||
|
||||
// Analog output correction
|
||||
parameter real VOLTAGE_GAIN = 1.0,
|
||||
parameter real GROUND_BIAS = 0.0,
|
||||
|
||||
// DAC timing parameters
|
||||
parameter time TRANSMISSION_DELAY = 150ps,
|
||||
parameter time CONVERSION_DELAY = 150ps
|
||||
)(
|
||||
input logic clk_i,
|
||||
input logic wrt_i,
|
||||
input logic [DAC_DATA_WIDTH-1:0] data_i,
|
||||
|
||||
output real voltage_o
|
||||
);
|
||||
|
||||
localparam int unsigned ZERO_CODE = (1 << (DAC_DATA_WIDTH - 1));
|
||||
localparam real VOLTAGE_STEP = (2 * VOLTAGE_RANGE) / real'((1 << DAC_DATA_WIDTH) - 1);
|
||||
|
||||
logic [DAC_DATA_WIDTH-1:0] dac_code;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Convert DAC code to analog voltage
|
||||
//------------------------------------------------------------
|
||||
function automatic real code_to_voltage( input logic [DAC_DATA_WIDTH-1:0] code);
|
||||
return (int'(code) - int'(ZERO_CODE)) * VOLTAGE_STEP;
|
||||
endfunction
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Initial state
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
dac_code = '0;
|
||||
voltage_o = code_to_voltage('0) * VOLTAGE_GAIN + GROUND_BIAS;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Latch new DAC code
|
||||
//------------------------------------------------------------
|
||||
always @(posedge wrt_i) begin
|
||||
dac_code <= #(TRANSMISSION_DELAY) data_i;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Update analog output
|
||||
//------------------------------------------------------------
|
||||
always @(posedge clk_i) begin
|
||||
voltage_o <= #(CONVERSION_DELAY) code_to_voltage(dac_code) * VOLTAGE_GAIN + GROUND_BIAS;
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -1 +1,9 @@
|
||||
set_clock_groups -name ASYNC_UDP_CTRL -asynchronous -group [get_clocks rgmii_rxc] -group [get_clocks clk_out1_clk_wiz_ctrl_inst] -group [get_clocks clk_out2_clk_wiz_ctrl_inst]
|
||||
# Primary clocks
|
||||
create_clock -name ref_clock -period 5.000 [get_ports clk_in]
|
||||
create_clock -name phy_rx_clock -period 8.000 [get_ports clk_m_axis]
|
||||
create_clock -name phy_tx_clock -period 8.000 [get_ports clk_s_axis]
|
||||
|
||||
set clk_125_name [get_clocks -of_objects [get_pins generator_inst/clk_dac_125]]
|
||||
set clk_65_name [get_clocks -of_objects [get_pins accumulator_top_dut/clk_adc_65]]
|
||||
|
||||
set_clock_groups -asynchronous -group $clk_125_name -group $clk_65_name
|
||||
@@ -0,0 +1,130 @@
|
||||
`ifndef AXIS_INTERFACE_SVH
|
||||
`define AXIS_INTERFACE_SVH
|
||||
|
||||
interface axis_if #(
|
||||
parameter int DATA_WIDTH = 8
|
||||
)(
|
||||
input logic clk,
|
||||
input logic rst_n
|
||||
);
|
||||
|
||||
// Сигналы шины AXI-Stream
|
||||
logic [DATA_WIDTH-1:0] tdata;
|
||||
logic tvalid;
|
||||
logic tlast;
|
||||
logic tready;
|
||||
|
||||
initial begin // Default values
|
||||
tdata = 'x;
|
||||
tvalid = 1'b0;
|
||||
tlast = 1'b0;
|
||||
tready = 1'b0;
|
||||
end
|
||||
|
||||
// Master Clocking Block (для отправки данных из TB)
|
||||
clocking drv_cb @(posedge clk);
|
||||
default input #1step output #100ps;
|
||||
output tdata, tvalid, tlast;
|
||||
input tready;
|
||||
endclocking
|
||||
|
||||
// Slave Clocking Block (для приема данных в TB с генерацией tready)
|
||||
clocking slv_cb @(posedge clk);
|
||||
default input #1step output #100ps;
|
||||
input tdata, tvalid, tlast;
|
||||
output tready;
|
||||
endclocking
|
||||
|
||||
// Passive Monitor Clocking Block
|
||||
clocking mon_cb @(posedge clk);
|
||||
default input #1step;
|
||||
input tdata, tvalid, tlast, tready;
|
||||
endclocking
|
||||
|
||||
modport master (output tdata, tvalid, tlast, input tready);
|
||||
modport slave (input tdata, tvalid, tlast, output tready);
|
||||
|
||||
// Модпорт для тестбенча с тасками
|
||||
modport tb (
|
||||
clocking drv_cb,
|
||||
clocking slv_cb,
|
||||
clocking mon_cb,
|
||||
import master_send,
|
||||
import slave_recv,
|
||||
import monitor_recv
|
||||
);
|
||||
|
||||
// Отправка пакета (Тестбенч выступает как Master)
|
||||
task automatic master_send(input logic [DATA_WIDTH-1:0] payload[]);
|
||||
if (payload.size() == 0) return;
|
||||
|
||||
@(drv_cb);
|
||||
|
||||
for (int i = 0; i < payload.size(); i++) begin
|
||||
drv_cb.tdata <= payload[i];
|
||||
drv_cb.tvalid <= 1'b1;
|
||||
drv_cb.tlast <= (i == payload.size() - 1);
|
||||
|
||||
forever begin // Ждем подтверждение от слейва пока не получим
|
||||
@(drv_cb);
|
||||
if (drv_cb.tready === 1'b1) begin
|
||||
break;
|
||||
end
|
||||
end
|
||||
end
|
||||
// Сбрасываем сигналы после отправки пакета
|
||||
drv_cb.tvalid <= 1'b0;
|
||||
drv_cb.tlast <= 1'b0;
|
||||
drv_cb.tdata <= 'x;
|
||||
endtask
|
||||
|
||||
// Прием пакета (Тестбенч выступает как Slave и управляет tready). Не применять если есть реальный Slave (его tready опустится насильно)
|
||||
task automatic slave_recv(output logic [DATA_WIDTH-1:0] payload[]);
|
||||
logic [DATA_WIDTH-1:0] local_queue[$]; // Внутри таски очередь использовать можно
|
||||
|
||||
slv_cb.tready <= 1'b1; // Показываем, что готовы принимать
|
||||
|
||||
forever begin
|
||||
@(slv_cb);
|
||||
if (slv_cb.tvalid === 1'b1) begin
|
||||
local_queue.push_back(slv_cb.tdata);
|
||||
if (slv_cb.tlast === 1'b1) begin
|
||||
break; // Пакет закончился
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
slv_cb.tready <= 1'b0; // Снимаем готовность
|
||||
|
||||
// Перекладываем из очереди в динамический массив
|
||||
payload = new[local_queue.size()](local_queue);
|
||||
endtask
|
||||
|
||||
// Прием пакета (Тестбенч выступает как пассивный наблюдатель без tready)
|
||||
task automatic monitor_recv(output logic [DATA_WIDTH-1:0] payload[]);
|
||||
logic [DATA_WIDTH-1:0] local_queue[$]; // Внутри таски очередь использовать можно
|
||||
|
||||
forever begin
|
||||
if (mon_cb.tready === 1'b1) begin
|
||||
break; // Дождались слейва
|
||||
end
|
||||
@(slv_cb);
|
||||
end
|
||||
|
||||
forever begin
|
||||
@(mon_cb);
|
||||
if (mon_cb.tvalid === 1'b1) begin
|
||||
local_queue.push_back(mon_cb.tdata);
|
||||
if (mon_cb.tlast === 1'b1) begin
|
||||
break; // Пакет закончился
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// Перекладываем из очереди в динамический массив
|
||||
payload = new[local_queue.size()](local_queue);
|
||||
endtask
|
||||
|
||||
endinterface
|
||||
|
||||
`endif // AXIS_INTERFACE_SVH`
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,128 +1,115 @@
|
||||
`timescale 1 ns / 1 ns
|
||||
|
||||
`include "interfaces.svh"
|
||||
|
||||
module reflectometer_top #(
|
||||
parameter int unsigned DAC_DATA_WIDTH = 14,
|
||||
parameter int unsigned ADC_DATA_WIDTH = 12,
|
||||
parameter PACK_FACTOR = 1,
|
||||
parameter PROCESS_MODE = 0,
|
||||
parameter ZERO_LEVEL = 8192,
|
||||
parameter ACCUM_WIDTH = 32,
|
||||
parameter N_MAX = 4096,
|
||||
parameter WINDOW_SIZE = 65,
|
||||
parameter PACKET_SIZE = 1024
|
||||
parameter int unsigned PACK_FACTOR = 1,
|
||||
parameter int unsigned PROCESS_MODE = 0,
|
||||
parameter int unsigned ZERO_LEVEL = 8192,
|
||||
parameter int unsigned ACCUM_WIDTH = 32,
|
||||
parameter int unsigned N_MAX = 4096,
|
||||
parameter int unsigned PACKET_SIZE = 1024
|
||||
)(
|
||||
input sys_clk,
|
||||
input rst_n,
|
||||
input wire clk_in,
|
||||
input wire rst_n,
|
||||
output wire locked,
|
||||
|
||||
output [3:0] led,
|
||||
// Accumulator AXI-S bus
|
||||
input wire clk_axis_accumulator, // GMII PHY RX clock
|
||||
axis_if.master axis_accumulator,
|
||||
|
||||
input gmii_rx_clk,
|
||||
input gmii_tx_clk,
|
||||
// Control AXI-S bus
|
||||
input wire clk_axis_control, // GMII PHY TX clock
|
||||
axis_if.slave axis_control,
|
||||
input wire [31:0] window_size, // New accum & old controller crutch
|
||||
|
||||
(* MARK_DEBUG="true" *) output logic [7:0] s_axis_tx_tdata,
|
||||
(* MARK_DEBUG="true" *) output logic s_axis_tx_tvalid,
|
||||
(* MARK_DEBUG="true" *) input logic s_axis_tx_tready,
|
||||
(* MARK_DEBUG="true" *) output logic s_axis_tx_tlast,
|
||||
// Status signals
|
||||
output wire workflow_done,
|
||||
output wire processing_done,
|
||||
|
||||
(* MARK_DEBUG="true" *) input wire [7:0] m_axis_rx_tdata,
|
||||
(* MARK_DEBUG="true" *) input wire m_axis_rx_tvalid,
|
||||
(* MARK_DEBUG="true" *) input wire m_axis_rx_tlast,
|
||||
(* MARK_DEBUG="true" *) output wire m_axis_rx_tready,
|
||||
|
||||
// axis_mac
|
||||
|
||||
(* MARK_DEBUG="true" *) input logic req_ready,
|
||||
(* MARK_DEBUG="true" *) output logic send_req,
|
||||
// RTL-MAC handshake
|
||||
input wire request_ready,
|
||||
output wire send_request,
|
||||
|
||||
// DAC
|
||||
|
||||
output wire p2_clk,
|
||||
(* MARK_DEBUG="true" *) output wire [DAC_DATA_WIDTH-1:0] p2_data,
|
||||
(* MARK_DEBUG="true" *) output wire p2_wrt,
|
||||
output wire dac_clk_o,
|
||||
output wire [DAC_DATA_WIDTH-1:0] dac_data,
|
||||
output wire dac_wrt,
|
||||
|
||||
// ADC
|
||||
output ch2_clk,
|
||||
(* MARK_DEBUG="true" *) input [ADC_DATA_WIDTH-1:0] ch2_data,
|
||||
input ch2_otr
|
||||
output wire adc_clk_o,
|
||||
input wire [ADC_DATA_WIDTH-1:0] adc_data,
|
||||
input wire adc_otr
|
||||
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// IDELAYCTRL
|
||||
// -------------------------------------------------------------------------
|
||||
(* IODELAY_GROUP = "rgmii_idelay_group" *)
|
||||
IDELAYCTRL IDELAYCTRL_inst (
|
||||
.RDY (),
|
||||
.REFCLK (sys_clk),
|
||||
.RST (1'b0)
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Generated clocks for controller
|
||||
// Need to create this IP in Vivado:
|
||||
// input : 200 MHz
|
||||
// output0: 130 MHz
|
||||
// output1: 65 MHz
|
||||
// input resetn
|
||||
// input clk_200 : 200 MHz : Reference clock
|
||||
// output clk_adc_65 : 65 MHz : ADC RTL clock
|
||||
// output clk_adc_65_180 : 65 MHz, phase 180 deg. : ADC PHY clock
|
||||
// output clk_adc_125 : 125 MHz : DAC RTL clock
|
||||
// output clk_adc_125_180 : 125 MHz, phase 180 deg. : DAC PHY clock
|
||||
// output locked
|
||||
// -------------------------------------------------------------------------
|
||||
wire dac_clk;
|
||||
wire adc_clk;
|
||||
wire clk_wiz_locked;
|
||||
wire clk_sampler, clk_generator, clk_locked;
|
||||
|
||||
clk_wiz_ctrl_inst clk_wiz_ctrl_inst (
|
||||
.clk_in1 (sys_clk),
|
||||
.reset (~rst_n),
|
||||
.clk_out1 (dac_clk), // 130 MHz
|
||||
.clk_out2 (adc_clk), // 65 MHz
|
||||
.locked (clk_wiz_locked)
|
||||
clk_wiz_ctrl_inst clk_wiz_inst
|
||||
(
|
||||
// Clock in ports
|
||||
.clk_200(clk_in),
|
||||
// Clock out ports
|
||||
.clk_adc_65(clk_sampler),
|
||||
.clk_adc_65_180(adc_clk_o),
|
||||
.clk_dac_125(clk_generator),
|
||||
.clk_dac_125_180(dac_clk_o),
|
||||
// Status and control signals
|
||||
.resetn(rst_n),
|
||||
.locked(clk_locked)
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// axis_mac interface
|
||||
// RX stream from Ethernet goes into controller
|
||||
// TX stream is unused for now
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
assign locked = clk_locked;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Controller reset
|
||||
// Use both external reset and clk_wiz lock
|
||||
// -------------------------------------------------------------------------
|
||||
wire ctrl_rst_n = rst_n & clk_wiz_locked;
|
||||
|
||||
|
||||
(* MARK_DEBUG="true" *) logic finish;
|
||||
|
||||
// Controller outputs to debug
|
||||
(* MARK_DEBUG="true" *) wire [31:0] dac_pulse_width;
|
||||
(* MARK_DEBUG="true" *) wire [31:0] dac_pulse_period;
|
||||
(* MARK_DEBUG="true" *) wire [DAC_DATA_WIDTH-1:0] dac_pulse_height;
|
||||
(* MARK_DEBUG="true" *) wire [15:0] dac_pulse_num;
|
||||
|
||||
(* MARK_DEBUG="true" *) wire [31:0] adc_pulse_period;
|
||||
(* MARK_DEBUG="true" *) wire [15:0] adc_pulse_num;
|
||||
|
||||
(* MARK_DEBUG="true" *) wire dac_start;
|
||||
(* MARK_DEBUG="true" *) wire adc_start;
|
||||
(* MARK_DEBUG="true" *) wire dac_rst;
|
||||
(* MARK_DEBUG="true" *) wire adc_rst;
|
||||
|
||||
wire ctrl_rst_n = rst_n & clk_locked;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Controller
|
||||
// ETH domain = gmii_rx_clk, because RX AXI master comes from axis_mac RX side
|
||||
// -------------------------------------------------------------------------
|
||||
wire [31:0] dac_pulse_width;
|
||||
wire [31:0] dac_pulse_period;
|
||||
wire [DAC_DATA_WIDTH-1:0] dac_pulse_height;
|
||||
wire [15:0] dac_pulse_num;
|
||||
|
||||
wire [31:0] adc_pulse_period;
|
||||
wire [15:0] adc_pulse_num;
|
||||
|
||||
wire dac_start;
|
||||
wire adc_start;
|
||||
wire dac_rst;
|
||||
wire adc_rst;
|
||||
|
||||
wire finish;
|
||||
|
||||
control #(
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
) udp_ctrl_inst (
|
||||
.eth_clk_in (gmii_rx_clk),
|
||||
.dac_clk_in (dac_clk),
|
||||
.adc_clk_in (adc_clk),
|
||||
.eth_clk_in (clk_axis_control),
|
||||
.dac_clk_in (clk_generator),
|
||||
.adc_clk_in (clk_sampler),
|
||||
.rst_n (ctrl_rst_n),
|
||||
|
||||
.s_axis_tdata (m_axis_rx_tdata),
|
||||
.s_axis_tvalid (m_axis_rx_tvalid),
|
||||
.s_axis_tready (m_axis_rx_tready),
|
||||
.s_axis_tlast (m_axis_rx_tlast),
|
||||
.s_axis_tdata (axis_control.tdata),
|
||||
.s_axis_tvalid (axis_control.tvalid),
|
||||
.s_axis_tready (axis_control.tready),
|
||||
.s_axis_tlast (axis_control.tlast),
|
||||
|
||||
.finish (finish),
|
||||
|
||||
@@ -141,180 +128,125 @@ module reflectometer_top #(
|
||||
.adc_rst (adc_rst)
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// DAC
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
(* MARK_DEBUG="true" *) logic sample_req;
|
||||
(* MARK_DEBUG="true" *) logic sample_req_sync1;
|
||||
(* MARK_DEBUG="true" *) logic sample_req_sync2;
|
||||
(* MARK_DEBUG="true" *) logic sample_req_sync3;
|
||||
|
||||
(* MARK_DEBUG="true" *) logic sample_done;
|
||||
(* MARK_DEBUG="true" *) logic sample_done_sync1;
|
||||
(* MARK_DEBUG="true" *) logic sample_done_sync2;
|
||||
(* MARK_DEBUG="true" *) logic sample_done_sync3;
|
||||
|
||||
//------------------------------------------------------------
|
||||
//------------------------------------------------------------
|
||||
// DAC -> ADC CDC
|
||||
//------------------------------------------------------------
|
||||
always_ff @(posedge adc_clk or posedge adc_rst) begin
|
||||
if (adc_rst) begin
|
||||
sample_req <= 1'b0;
|
||||
sample_req_sync2 <= 1'b0;
|
||||
sample_req_sync3 <= 1'b0;
|
||||
end
|
||||
(* ASYNC_REG = "TRUE" *) logic [2:0] stretch; // 125/65~=2. Чтобы поймать единичный импульс, растянем его во времени
|
||||
(* ASYNC_REG = "TRUE" *) logic [1:0] sync_DA;
|
||||
wire dac_done_stretched;
|
||||
|
||||
wire generator_done, generator_request;
|
||||
wire sampler_done, sampler_request;
|
||||
|
||||
always_ff @(posedge clk_generator or posedge dac_rst)
|
||||
begin
|
||||
if (dac_rst)
|
||||
stretch <= 0;
|
||||
else begin
|
||||
sample_req_sync2 <= sample_req_sync1;
|
||||
sample_req_sync3 <= sample_req_sync2;
|
||||
sample_req <= sample_req_sync3;
|
||||
stretch[0] <= generator_done;
|
||||
stretch[1] <= stretch[0];
|
||||
stretch[2] <= stretch[1];
|
||||
end
|
||||
end
|
||||
assign dac_done_stretched = |stretch;
|
||||
|
||||
//------------------------------------------------------------
|
||||
always_ff @(posedge clk_sampler or posedge adc_rst) begin
|
||||
if (adc_rst)
|
||||
sync_DA <= 0;
|
||||
else begin
|
||||
sync_DA[0] <= dac_done_stretched;
|
||||
sync_DA[1] <= sync_DA[0];
|
||||
end
|
||||
end
|
||||
assign sampler_request = sync_DA[1];
|
||||
|
||||
//------------------------------------------------------------
|
||||
// ADC -> DAC CDC
|
||||
//------------------------------------------------------------
|
||||
always_ff @(posedge dac_clk or posedge dac_rst) begin
|
||||
if (dac_rst) begin
|
||||
sample_done <= 1'b0;
|
||||
sample_done_sync2 <= 1'b0;
|
||||
sample_done_sync3 <= 1'b0;
|
||||
end
|
||||
(* ASYNC_REG = "TRUE" *) logic [1:0] sync_AD;
|
||||
|
||||
always_ff @(posedge clk_generator or posedge dac_rst) begin
|
||||
if (dac_rst)
|
||||
sync_AD <= 0;
|
||||
else begin
|
||||
sample_done_sync2 <= sample_done_sync1;
|
||||
sample_done_sync3 <= sample_done_sync2;
|
||||
sample_done <= sample_done_sync3;
|
||||
sync_AD[0] <= sampler_done;
|
||||
sync_AD[1] <= sync_AD[0];
|
||||
end
|
||||
end
|
||||
assign generator_request = sync_AD[1];
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Generator
|
||||
//------------------------------------------------------------
|
||||
|
||||
// Generator (DAC)
|
||||
//------------------------------------------------------------
|
||||
generator #(
|
||||
.DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ZERO_LEVEL(ZERO_LEVEL)
|
||||
) generator_inst (
|
||||
.clk_in(dac_clk),
|
||||
.clk_dac(clk_generator),
|
||||
.rst(dac_rst),
|
||||
.start(dac_start),
|
||||
.pulse_width(dac_pulse_width),
|
||||
.pulse_period(dac_pulse_period),
|
||||
.pulse_height(dac_pulse_height),
|
||||
.pulse_num(dac_pulse_num),
|
||||
.pulse(p2_wrt),
|
||||
.pulse_height_out(p2_data),
|
||||
.sample_done(sample_done),
|
||||
.sample_req(sample_req_sync1)
|
||||
.dac_out(dac_data),
|
||||
.done(generator_done),
|
||||
.request(generator_request)
|
||||
);
|
||||
assign dac_wrt = dac_clk_o;
|
||||
|
||||
wire ch2_clk_oddr;
|
||||
|
||||
ODDR #(
|
||||
.DDR_CLK_EDGE("SAME_EDGE"),
|
||||
.INIT(1'b0),
|
||||
.SRTYPE("SYNC")
|
||||
) ODDR_ch2_clk (
|
||||
.Q (ch2_clk_oddr),
|
||||
.C (adc_clk),
|
||||
.CE(1'b1),
|
||||
.D1(1'b1),
|
||||
.D2(1'b0),
|
||||
.R (1'b0),
|
||||
.S (1'b0)
|
||||
);
|
||||
|
||||
OBUF OBUF_ch2_clk (
|
||||
.I(ch2_clk_oddr),
|
||||
.O(ch2_clk)
|
||||
);
|
||||
|
||||
wire p2_clk_oddr;
|
||||
|
||||
ODDR #(
|
||||
.DDR_CLK_EDGE("SAME_EDGE"),
|
||||
.INIT(1'b0),
|
||||
.SRTYPE("SYNC")
|
||||
) ODDR_p2_clk (
|
||||
.Q (p2_clk_oddr),
|
||||
.C (dac_clk),
|
||||
.CE(1'b1),
|
||||
.D1(1'b1),
|
||||
.D2(1'b0),
|
||||
.R (1'b0),
|
||||
.S (1'b0)
|
||||
);
|
||||
|
||||
OBUF OBUF_p2_clk (
|
||||
.I(p2_clk_oddr),
|
||||
.O(p2_clk)
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// ADC
|
||||
// -------------------------------------------------------------------------
|
||||
// Sampler (ADC)
|
||||
// -------------------------------------------------------------------------
|
||||
wire [ADC_DATA_WIDTH*PACK_FACTOR-1:0] sampler_m_axis_tdata;
|
||||
wire sampler_m_axis_tvalid;
|
||||
|
||||
(* MARK_DEBUG="true" *) logic [ADC_DATA_WIDTH*PACK_FACTOR-1:0] accum_m_axis_tdata;
|
||||
(* MARK_DEBUG="true" *) logic acum_m_axis_tvalid;
|
||||
|
||||
sampler
|
||||
#(
|
||||
sampler #(
|
||||
.DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE)
|
||||
)
|
||||
sampler_dut
|
||||
(
|
||||
.clk_in(adc_clk),
|
||||
.rst(adc_rst),
|
||||
.data_in(ch2_data),
|
||||
.out_of_range(ch2_otr),
|
||||
.m_axis_tdata(accum_m_axis_tdata),
|
||||
.m_axis_tvalid(acum_m_axis_tvalid),
|
||||
) sampler_dut (
|
||||
.clk_in(clk_sampler),
|
||||
.rst(adc_rst),
|
||||
.data_in(adc_data),
|
||||
.out_of_range(adc_otr),
|
||||
.m_axis_tdata(sampler_m_axis_tdata),
|
||||
.m_axis_tvalid(sampler_m_axis_tvalid),
|
||||
.smp_num(adc_pulse_period),
|
||||
.sample_req(sample_req),
|
||||
.sample_done(sample_done_sync1)
|
||||
.done(sampler_done),
|
||||
.request(sampler_request)
|
||||
);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Accumulator
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
accumulator_top
|
||||
#(
|
||||
assign workflow_done = finish;
|
||||
|
||||
accumulator_top #(
|
||||
.DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.WINDOW_SIZE(WINDOW_SIZE),
|
||||
.PACKET_SIZE(PACKET_SIZE)
|
||||
)
|
||||
accumulator_top_dut
|
||||
(
|
||||
.clk_in(adc_clk),
|
||||
) accumulator_top_dut (
|
||||
.clk_in(clk_sampler),
|
||||
.rst(adc_rst),
|
||||
.s_axis_tdata(accum_m_axis_tdata),
|
||||
.s_axis_tvalid(acum_m_axis_tvalid),
|
||||
.s_axis_tdata(sampler_m_axis_tdata),
|
||||
.s_axis_tvalid(sampler_m_axis_tvalid),
|
||||
.start(adc_start),
|
||||
.smp_num(adc_pulse_period),
|
||||
.seq_num(adc_pulse_num),
|
||||
.window_size(window_size),
|
||||
|
||||
.eth_clk_in(gmii_tx_clk),
|
||||
.req_ready(req_ready),
|
||||
.send_req(send_req),
|
||||
.m_axis_tdata(s_axis_tx_tdata),
|
||||
.m_axis_tvalid(s_axis_tx_tvalid),
|
||||
.m_axis_tready(s_axis_tx_tready),
|
||||
.m_axis_tlast(s_axis_tx_tlast),
|
||||
.req_ready(request_ready),
|
||||
.send_req(send_request),
|
||||
.eth_clk_in(clk_axis_accumulator),
|
||||
.m_axis_tdata(axis_accumulator.tdata),
|
||||
.m_axis_tvalid(axis_accumulator.tvalid),
|
||||
.m_axis_tready(axis_accumulator.tready),
|
||||
.m_axis_tlast(axis_accumulator.tlast),
|
||||
|
||||
.finish(finish)
|
||||
.finish(finish), // full reflectometer workflow complete (with transaction)
|
||||
.accum_done(processing_done) // signal generation, sampling and processing complete
|
||||
);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Simple LED status
|
||||
// -------------------------------------------------------------------------
|
||||
assign led[0] = clk_wiz_locked;
|
||||
assign led[1] = m_axis_rx_tvalid;
|
||||
assign led[2] = dac_start;
|
||||
|
||||
endmodule
|
||||
endmodule
|
||||
|
||||
@@ -0,0 +1,373 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
`include "interfaces.svh"
|
||||
|
||||
module reflectometer_tb;
|
||||
//------------------------------------------------------------
|
||||
// Параметры
|
||||
//------------------------------------------------------------
|
||||
localparam int unsigned DAC_DATA_WIDTH = 14;
|
||||
localparam int unsigned ADC_DATA_WIDTH = 12;
|
||||
localparam LOGIC_ZERO_LEVEL = 0; // DAC -5V for logic zero
|
||||
localparam VOLTAGE_ZERO_LEVEL = 2**(DAC_DATA_WIDTH-1); // DAC 0V for logic zero
|
||||
localparam PACK_FACTOR = 1; // not used in TB
|
||||
localparam PROCESS_MODE = 0; // 0 - uint, 1 - int. Current accumulator don't support signed sum
|
||||
localparam ACCUM_WIDTH = 32; // accumulator number bit witdth
|
||||
localparam N_MAX = 4096; // max value of windows to average by experiments
|
||||
localparam PACKET_SIZE = 1024; // bytes per UDP packet
|
||||
|
||||
localparam int REQUEST_TIMEOUT = 3 * PACKET_SIZE; // timeout for packet receiving from accumulator
|
||||
|
||||
localparam ZERO_LEVEL = LOGIC_ZERO_LEVEL; // "logic" VS "voltage"
|
||||
|
||||
localparam CLK_ETH_PHY_PERIOD = 8.000; // 125 MHz
|
||||
localparam CLK_REF_PERIOD = 5.000; // 200 MHz
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Глобальные перменные
|
||||
//------------------------------------------------------------
|
||||
int unsigned WINDOW_SIZE = 65; // fixed subwindow size to average by time
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Тактовые сигналы и сброс
|
||||
//------------------------------------------------------------
|
||||
logic clk_ref = 1'b0; // 200 MHz
|
||||
logic clk_eth_phy = 1'b0; // common for RX & TX
|
||||
logic rst_n = 1'b0;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Управление и конфиг DUT
|
||||
//------------------------------------------------------------
|
||||
logic [31:0] window_size;
|
||||
// AXI-S интерфейс для управления
|
||||
axis_if axis_control_if (
|
||||
.clk(clk_eth_phy),
|
||||
.rst_n(rst_n)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Входы DUT
|
||||
//------------------------------------------------------------
|
||||
// ADC интерфейс
|
||||
wire clk_adc;
|
||||
wire adc_otr;
|
||||
wire [ADC_DATA_WIDTH-1:0] adc_data;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Выходы
|
||||
//------------------------------------------------------------
|
||||
// Статусы
|
||||
wire mmcm_locked;
|
||||
wire workflow_done;
|
||||
wire processing_done;
|
||||
// DAC интерфейс
|
||||
wire clk_dac;
|
||||
wire dac_wrt;
|
||||
wire [DAC_DATA_WIDTH-1:0] dac_data;
|
||||
// AXI-S интерфейс для данных
|
||||
axis_if axis_accumulator_if (
|
||||
.clk(clk_eth_phy),
|
||||
.rst_n(rst_n)
|
||||
);
|
||||
//------------------------------------------------------------
|
||||
// Внутренние сигналы тестбенча
|
||||
//------------------------------------------------------------
|
||||
// Интерфейс хендшейка с MAC-PHY
|
||||
wire send_request;
|
||||
logic request_ready;
|
||||
// Сигнал между ЦАП и АЦП
|
||||
real signal_voltage;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Virtual DAC
|
||||
//------------------------------------------------------------
|
||||
virtual_dac_model #( // default voltage range is +/- 5V
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
// ,.VOLTAGE_GAIN(2)
|
||||
) virtual_dac (
|
||||
.clk_i(clk_dac),
|
||||
.wrt_i(dac_wrt),
|
||||
.data_i(dac_data),
|
||||
.voltage_o(signal_voltage)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Virtual ADC
|
||||
//------------------------------------------------------------
|
||||
virtual_adc_model #( // default voltage range is +/- 5V
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH)
|
||||
) virtual_adc (
|
||||
.clk_i(clk_adc),
|
||||
.voltage_i(signal_voltage),
|
||||
.otr_o(adc_otr),
|
||||
.data_o(adc_data)
|
||||
);
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Statistics processing
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Config handler
|
||||
//------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------
|
||||
// DUT
|
||||
//------------------------------------------------------------
|
||||
reflectometer_top #(
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH),
|
||||
.ADC_DATA_WIDTH(ADC_DATA_WIDTH),
|
||||
.PACK_FACTOR(PACK_FACTOR),
|
||||
.PROCESS_MODE(PROCESS_MODE),
|
||||
.ZERO_LEVEL(ZERO_LEVEL),
|
||||
.ACCUM_WIDTH(ACCUM_WIDTH),
|
||||
.N_MAX(N_MAX),
|
||||
.PACKET_SIZE(PACKET_SIZE)
|
||||
) DUT (
|
||||
.clk_in(clk_ref),
|
||||
.rst_n(rst_n),
|
||||
|
||||
// Status
|
||||
.locked(mmcm_locked),
|
||||
.workflow_done(workflow_done),
|
||||
.processing_done(processing_done),
|
||||
|
||||
// Accumulator AXI-S bus
|
||||
.clk_axis_accumulator(clk_eth_phy), // GMII PHY RX clock
|
||||
.axis_accumulator(axis_accumulator_if.master),
|
||||
|
||||
// Control AXI-S bus
|
||||
.clk_axis_control(clk_eth_phy), // GMII PHY TX clock
|
||||
.axis_control(axis_control_if.slave),
|
||||
.window_size(window_size), // direct signal crutch (old controller)
|
||||
|
||||
// RTL-MAC handshake
|
||||
.request_ready(request_ready),
|
||||
.send_request(send_request),
|
||||
|
||||
// DAC
|
||||
.dac_clk_o(clk_dac),
|
||||
.dac_data(dac_data),
|
||||
.dac_wrt(dac_wrt),
|
||||
|
||||
// ADC
|
||||
.adc_clk_o(clk_adc),
|
||||
.adc_data(adc_data),
|
||||
.adc_otr(adc_otr)
|
||||
);
|
||||
assign window_size = WINDOW_SIZE;
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Тактовые сигналы
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
forever #(CLK_REF_PERIOD/2) clk_ref = ~clk_ref;
|
||||
end
|
||||
initial begin
|
||||
forever #(CLK_ETH_PHY_PERIOD/2) clk_eth_phy = ~clk_eth_phy;
|
||||
end
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Таски для тестирования
|
||||
//------------------------------------------------------------
|
||||
// Таски работы с AXI-Stream
|
||||
task automatic dut_soft_reset(virtual axis_if#(8).tb vif);
|
||||
logic [7:0] tx_packet[];
|
||||
tx_packet = '{8'h0f};
|
||||
vif.master_send(tx_packet);
|
||||
endtask
|
||||
|
||||
task automatic dut_start(virtual axis_if#(8).tb vif);
|
||||
logic [7:0] tx_packet[];
|
||||
tx_packet = '{8'hf0};
|
||||
vif.master_send(tx_packet);
|
||||
endtask
|
||||
|
||||
task automatic dut_send_system_config(
|
||||
virtual axis_if#(8).tb vif,
|
||||
input logic [31:0] pulse_width,
|
||||
input logic [31:0] pulse_period,
|
||||
input logic [15:0] pulse_num,
|
||||
input logic [13:0] pulse_height, // achtung! p_height strictly must have 14 bits of width
|
||||
input logic [31:0] pulse_period_adc,
|
||||
input logic [31:0] window_size
|
||||
);
|
||||
// Создаем временный фиксированный массив и упаковываем всё одной строкой
|
||||
logic [7:0] tx_packet[];
|
||||
|
||||
// Ахтунг, 14-битный ЦАП захардкожен
|
||||
if (DAC_DATA_WIDTH != 14)
|
||||
$display("[WARNING] -dut_send_system_config- Default pulse height (DAC bitwidth) is equal to 14. Be aware, controller packet structure is coded for 14 bits");
|
||||
|
||||
tx_packet = '{
|
||||
8'h88, // Команда
|
||||
pulse_width[7:0], pulse_width[15:8], pulse_width[23:16], pulse_width[31:24],
|
||||
pulse_period[7:0], pulse_period[15:8], pulse_period[23:16], pulse_period[31:24],
|
||||
pulse_num[7:0], pulse_num[15:8], pulse_height[7:0], 8'({2'b00, pulse_height[13:8]}),
|
||||
pulse_period_adc[7:0], pulse_period_adc[15:8], pulse_period_adc[23:16], pulse_period_adc[31:24]
|
||||
};
|
||||
|
||||
vif.master_send(tx_packet);
|
||||
|
||||
// TODO remove for new controller
|
||||
WINDOW_SIZE = window_size;
|
||||
endtask
|
||||
|
||||
// Таски сбора статистики
|
||||
task automatic dut_read_output(
|
||||
virtual axis_if#(8).tb vif,
|
||||
input int sample_num,
|
||||
input bit randomize_recv_delays,
|
||||
output int output_data[]
|
||||
);
|
||||
logic [7:0] rx_packet[];
|
||||
logic [ACCUM_WIDTH-1:0] data_packet[];
|
||||
int numbers_per_packet = PACKET_SIZE/(ACCUM_WIDTH/8);
|
||||
int packet_num = $ceil(real'(sample_num / WINDOW_SIZE) / real'(numbers_per_packet));
|
||||
int timeout_flag = 0;
|
||||
int packet_counter = 0;
|
||||
|
||||
if (sample_num % WINDOW_SIZE) begin
|
||||
$display("[ERROR] -dut_read_output- Sample_num must be multiple of WINDOW_SIZE: %0d %% %0d = %0d", sample_num, WINDOW_SIZE, sample_num % WINDOW_SIZE);
|
||||
$finish;
|
||||
end
|
||||
|
||||
data_packet = new[numbers_per_packet];
|
||||
output_data = new[numbers_per_packet * packet_num];
|
||||
|
||||
// count send_request pulses (equal to number of packets)
|
||||
fork
|
||||
begin : packet_counter_proc
|
||||
forever begin
|
||||
@(posedge clk_eth_phy);
|
||||
if(send_request === 1)
|
||||
packet_counter++;
|
||||
end
|
||||
end
|
||||
join_none
|
||||
|
||||
// Wait until reflectometer done sampling and averaging
|
||||
wait(processing_done == 1);
|
||||
|
||||
// recv loop
|
||||
// если число пакетов превышает заложенное предрассчитанное значение -- ошибка
|
||||
fork : recv_loop_proc
|
||||
begin
|
||||
// packet recv loop
|
||||
forever begin
|
||||
if (packet_counter > packet_num) begin
|
||||
$display("[ERROR] -dut_read_output- Packet overflow detected. Number of data packets exceeds expected amount of packets");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (randomize_recv_delays)
|
||||
repeat($urandom_range(0, 500)) @(posedge clk_eth_phy);
|
||||
|
||||
timeout_flag = 0;
|
||||
fork : receive_packet_timeout
|
||||
begin
|
||||
request_ready = 1;
|
||||
vif.slave_recv(rx_packet);
|
||||
request_ready = 0;
|
||||
end
|
||||
begin
|
||||
repeat(REQUEST_TIMEOUT) @(posedge clk_eth_phy);
|
||||
timeout_flag = 1;
|
||||
end
|
||||
join_any
|
||||
|
||||
disable receive_packet_timeout;
|
||||
if (timeout_flag) begin
|
||||
$display("[ERROR] -dut_read_output- Timeout detected when receiving packet");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (rx_packet.size() != PACKET_SIZE) begin
|
||||
$display("[ERROR] -dut_read_output- Wrong packet size received: %0d bytes received, %0d bytes expected", rx_packet.size(), PACKET_SIZE);
|
||||
$finish;
|
||||
end
|
||||
|
||||
// unpack values
|
||||
data_packet = {<< byte {rx_packet}};
|
||||
data_packet = {<< ACCUM_WIDTH {data_packet}};
|
||||
|
||||
// copy and convert values
|
||||
for (int j = 0; j < data_packet.size(); j++) begin
|
||||
output_data[(packet_counter-1) * data_packet.size() + j] = int'(data_packet[j]);
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
begin
|
||||
// IP workflow completion event
|
||||
wait(workflow_done == 1);
|
||||
end
|
||||
join_any
|
||||
|
||||
disable recv_loop_proc;
|
||||
disable packet_counter_proc;
|
||||
|
||||
if (packet_counter != packet_num) begin
|
||||
$display("[ERROR] -dut_read_output- Wrong number of packets received: %0d received, %0d expected", packet_counter, packet_num);
|
||||
$finish;
|
||||
end
|
||||
|
||||
endtask
|
||||
|
||||
// Основная таска типового теста
|
||||
// todo
|
||||
|
||||
//------------------------------------------------------------
|
||||
// ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ
|
||||
//------------------------------------------------------------
|
||||
initial begin
|
||||
int output_data[];
|
||||
|
||||
automatic virtual axis_if.tb control_vif = axis_control_if.tb;
|
||||
automatic virtual axis_if.tb accumulator_vif = axis_accumulator_if.tb;
|
||||
|
||||
$display("[TB] DUT initializaton");
|
||||
// Инициализация
|
||||
request_ready = 0;
|
||||
rst_n = 0;
|
||||
#100;
|
||||
rst_n = 1;
|
||||
wait(mmcm_locked === 1'b1);
|
||||
#150;
|
||||
$display("[TB] MMCM locked");
|
||||
|
||||
dut_soft_reset(control_vif);
|
||||
#100;
|
||||
|
||||
// Тесты
|
||||
$display("[TB] Tests start");
|
||||
dut_send_system_config(
|
||||
.vif(control_vif),
|
||||
.pulse_width(32'd123),
|
||||
.pulse_period(32'd5000),
|
||||
.pulse_num(16'd1),
|
||||
.pulse_height(14'd15000), // 0V
|
||||
.pulse_period_adc(32'd2600),
|
||||
.window_size(1)
|
||||
);
|
||||
#100;
|
||||
dut_start(control_vif);
|
||||
|
||||
dut_read_output(
|
||||
.vif(accumulator_vif),
|
||||
.sample_num(2600),
|
||||
.randomize_recv_delays(0),
|
||||
.output_data(output_data)
|
||||
);
|
||||
#1000;
|
||||
|
||||
$display("Received %0d numbers", output_data.size());
|
||||
for (int i = 0; i < output_data.size(); i++) begin
|
||||
$write("%0d ", output_data[i]);
|
||||
end
|
||||
$display("");
|
||||
|
||||
$display("[TB] ALL PASSED");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<wave_config>
|
||||
<wave_state>
|
||||
</wave_state>
|
||||
<db_ref_list>
|
||||
<db_ref path="reflectometer_tb_behav.wdb" id="1">
|
||||
<top_modules>
|
||||
<top_module name="glbl" />
|
||||
<top_module name="reflectometer_tb" />
|
||||
</top_modules>
|
||||
</db_ref>
|
||||
</db_ref_list>
|
||||
<zoom_setting>
|
||||
<ZoomStartTime time="0.000 ns"></ZoomStartTime>
|
||||
<ZoomEndTime time="1,506.001 ns"></ZoomEndTime>
|
||||
<Cursor1Time time="1,000.000 ns"></Cursor1Time>
|
||||
</zoom_setting>
|
||||
<column_width_setting>
|
||||
<NameColumnWidth column_width="196"></NameColumnWidth>
|
||||
<ValueColumnWidth column_width="76"></ValueColumnWidth>
|
||||
</column_width_setting>
|
||||
<WVObjectSize size="7" />
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/rst_n">
|
||||
<obj_property name="ElementShortName">rst_n</obj_property>
|
||||
<obj_property name="ObjectShortName">rst_n</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/mmcm_locked">
|
||||
<obj_property name="ElementShortName">mmcm_locked</obj_property>
|
||||
<obj_property name="ObjectShortName">mmcm_locked</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="group" fp_name="group28">
|
||||
<obj_property name="label">Signal</obj_property>
|
||||
<obj_property name="DisplayName">label</obj_property>
|
||||
<wvobject type="array" fp_name="/reflectometer_tb/dac_data">
|
||||
<obj_property name="ElementShortName">dac_data[13:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">dac_data[13:0]</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="other" fp_name="/reflectometer_tb/signal_voltage">
|
||||
<obj_property name="ElementShortName">signal_voltage</obj_property>
|
||||
<obj_property name="ObjectShortName">signal_voltage</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="array" fp_name="/reflectometer_tb/adc_data">
|
||||
<obj_property name="ElementShortName">adc_data[11:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">adc_data[11:0]</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/adc_otr">
|
||||
<obj_property name="ElementShortName">adc_otr</obj_property>
|
||||
<obj_property name="ObjectShortName">adc_otr</obj_property>
|
||||
</wvobject>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/send_request">
|
||||
<obj_property name="ElementShortName">send_request</obj_property>
|
||||
<obj_property name="ObjectShortName">send_request</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/request_ready">
|
||||
<obj_property name="ElementShortName">request_ready</obj_property>
|
||||
<obj_property name="ObjectShortName">request_ready</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="group" fp_name="group51">
|
||||
<obj_property name="label">Controller</obj_property>
|
||||
<obj_property name="DisplayName">label</obj_property>
|
||||
<obj_property name="isExpanded"></obj_property>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/clk">
|
||||
<obj_property name="ElementShortName">clk</obj_property>
|
||||
<obj_property name="ObjectShortName">clk</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/rst_n">
|
||||
<obj_property name="ElementShortName">rst_n</obj_property>
|
||||
<obj_property name="ObjectShortName">rst_n</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="array" fp_name="/reflectometer_tb/axis_control_if/tdata">
|
||||
<obj_property name="ElementShortName">tdata[7:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">tdata[7:0]</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/tvalid">
|
||||
<obj_property name="ElementShortName">tvalid</obj_property>
|
||||
<obj_property name="ObjectShortName">tvalid</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/tlast">
|
||||
<obj_property name="ElementShortName">tlast</obj_property>
|
||||
<obj_property name="ObjectShortName">tlast</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_control_if/tready">
|
||||
<obj_property name="ElementShortName">tready</obj_property>
|
||||
<obj_property name="ObjectShortName">tready</obj_property>
|
||||
</wvobject>
|
||||
</wvobject>
|
||||
<wvobject type="group" fp_name="group52">
|
||||
<obj_property name="label">Accumulator</obj_property>
|
||||
<obj_property name="DisplayName">label</obj_property>
|
||||
<obj_property name="isExpanded"></obj_property>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/clk">
|
||||
<obj_property name="ElementShortName">clk</obj_property>
|
||||
<obj_property name="ObjectShortName">clk</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/rst_n">
|
||||
<obj_property name="ElementShortName">rst_n</obj_property>
|
||||
<obj_property name="ObjectShortName">rst_n</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="array" fp_name="/reflectometer_tb/axis_accumulator_if/tdata">
|
||||
<obj_property name="ElementShortName">tdata[7:0]</obj_property>
|
||||
<obj_property name="ObjectShortName">tdata[7:0]</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/tvalid">
|
||||
<obj_property name="ElementShortName">tvalid</obj_property>
|
||||
<obj_property name="ObjectShortName">tvalid</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/tlast">
|
||||
<obj_property name="ElementShortName">tlast</obj_property>
|
||||
<obj_property name="ObjectShortName">tlast</obj_property>
|
||||
</wvobject>
|
||||
<wvobject type="logic" fp_name="/reflectometer_tb/axis_accumulator_if/tready">
|
||||
<obj_property name="ElementShortName">tready</obj_property>
|
||||
<obj_property name="ObjectShortName">tready</obj_property>
|
||||
</wvobject>
|
||||
</wvobject>
|
||||
</wave_config>
|
||||
@@ -0,0 +1,4 @@
|
||||
**sim_build**
|
||||
**pycache**
|
||||
dump.vcd
|
||||
results.xml
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "external/verilog-axi"]
|
||||
path = external/verilog-axi
|
||||
url = https://github.com/alexforencich/verilog-axi
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
# RTL Libs
|
||||
|
||||
## AXI Defines
|
||||
@@ -0,0 +1,213 @@
|
||||
module axi4l_reg_map #(
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
parameter int unsigned N_REGS = 4,
|
||||
|
||||
parameter logic [N_REGS-1:0][31:0][2:0] REG_MODE = '{default:'0},
|
||||
parameter logic [N_REGS-1:0][31:0] REG_RST = '{default:'0}
|
||||
)(
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
axi4l_if.slave s_axil,
|
||||
|
||||
input logic [N_REGS-1:0][31:0] reg_i,
|
||||
output logic [N_REGS-1:0][31:0] reg_o,
|
||||
output logic [N_REGS-1:0][31:0] reg_pulse
|
||||
);
|
||||
import axi_pkg::*;
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
REG_BIT_RSVD = 3'd0,
|
||||
REG_BIT_RO = 3'd1,
|
||||
REG_BIT_RW = 3'd2,
|
||||
REG_BIT_W1S = 3'd3,
|
||||
REG_BIT_W1C = 3'd4
|
||||
} reg_bit_mode_t;
|
||||
|
||||
localparam int unsigned STRB_W = DATA_W/8;
|
||||
localparam int unsigned ADDR_LSB = $clog2(DATA_W/8);
|
||||
localparam int unsigned REG_INDEX_W = (N_REGS <= 1) ? 1 : $clog2(N_REGS);
|
||||
|
||||
logic [ADDR_W-1:0] awaddr_q;
|
||||
logic aw_seen_q;
|
||||
logic [DATA_W-1:0] wdata_q;
|
||||
logic [STRB_W-1:0] wstrb_q;
|
||||
logic w_seen_q;
|
||||
|
||||
logic bvalid_q;
|
||||
logic [1:0] bresp_q;
|
||||
|
||||
logic rvalid_q;
|
||||
logic [1:0] rresp_q;
|
||||
logic [DATA_W-1:0] rdata_q;
|
||||
|
||||
logic [REG_INDEX_W-1:0] wr_idx;
|
||||
logic [REG_INDEX_W-1:0] rd_idx;
|
||||
logic wr_addr_valid;
|
||||
logic rd_addr_valid;
|
||||
|
||||
integer b;
|
||||
logic [31:0] wr_mask;
|
||||
logic [31:0] wr_data32;
|
||||
logic [31:0] rw_cur;
|
||||
logic [31:0] rw_new;
|
||||
logic [31:0] rd_word;
|
||||
|
||||
always_comb begin
|
||||
wr_idx = '0;
|
||||
rd_idx = '0;
|
||||
wr_addr_valid = 1'b0;
|
||||
rd_addr_valid = 1'b0;
|
||||
|
||||
if (awaddr_q[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W] < N_REGS) begin
|
||||
wr_idx = awaddr_q[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W];
|
||||
wr_addr_valid = 1'b1;
|
||||
end
|
||||
|
||||
if (s_axil.req.ar.addr[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W] < N_REGS) begin
|
||||
rd_idx = s_axil.req.ar.addr[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W];
|
||||
rd_addr_valid = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
wr_mask = '0;
|
||||
for (int k = 0; k < STRB_W; k++) begin
|
||||
wr_mask[k*8 +: 8] = {8{wstrb_q[k]}};
|
||||
end
|
||||
wr_data32 = wdata_q[31:0];
|
||||
end
|
||||
|
||||
assign s_axil.resp.aw_ready = !aw_seen_q && !bvalid_q;
|
||||
assign s_axil.resp.w_ready = !w_seen_q && !bvalid_q;
|
||||
assign s_axil.resp.ar_ready = !rvalid_q;
|
||||
|
||||
assign s_axil.resp.b.valid = bvalid_q;
|
||||
assign s_axil.resp.b.resp = axi_resp_t'(bresp_q);
|
||||
assign s_axil.resp.b.user = '0;
|
||||
|
||||
assign s_axil.resp.r.valid = rvalid_q;
|
||||
assign s_axil.resp.r.resp = axi_resp_t'(rresp_q);
|
||||
assign s_axil.resp.r.data = rdata_q;
|
||||
assign s_axil.resp.r.user = '0;
|
||||
|
||||
always_ff @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
awaddr_q <= '0;
|
||||
aw_seen_q <= 1'b0;
|
||||
wdata_q <= '0;
|
||||
wstrb_q <= '0;
|
||||
w_seen_q <= 1'b0;
|
||||
bvalid_q <= 1'b0;
|
||||
bresp_q <= 2'b00;
|
||||
rvalid_q <= 1'b0;
|
||||
rresp_q <= 2'b00;
|
||||
rdata_q <= '0;
|
||||
reg_o <= REG_RST;
|
||||
end else begin
|
||||
reg_pulse <= '0;
|
||||
for (int r = 0; r < N_REGS; r++) begin
|
||||
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
|
||||
if (reg_bit_mode_t'(REG_MODE[r][bit_idx]) == REG_BIT_W1S)
|
||||
reg_o[r][bit_idx] <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
if (s_axil.req.aw.valid && s_axil.resp.aw_ready) begin
|
||||
awaddr_q <= s_axil.req.aw.addr;
|
||||
aw_seen_q <= 1'b1;
|
||||
end
|
||||
|
||||
if (s_axil.req.w.valid && s_axil.resp.w_ready) begin
|
||||
wdata_q <= s_axil.req.w.data;
|
||||
wstrb_q <= s_axil.req.w.strb;
|
||||
w_seen_q <= 1'b1;
|
||||
end
|
||||
|
||||
if (aw_seen_q && w_seen_q && !bvalid_q) begin
|
||||
bvalid_q <= 1'b1;
|
||||
bresp_q <= 2'b00;
|
||||
|
||||
if (!wr_addr_valid) begin
|
||||
bresp_q <= 2'b10;
|
||||
end else begin
|
||||
rw_cur = reg_o[wr_idx];
|
||||
rw_new = rw_cur;
|
||||
|
||||
for (b = 0; b < 32; b = b + 1) begin
|
||||
if (wr_mask[b]) begin
|
||||
unique case (reg_bit_mode_t'(REG_MODE[wr_idx][b]))
|
||||
REG_BIT_RSVD: begin
|
||||
end
|
||||
|
||||
REG_BIT_RO: begin
|
||||
bresp_q <= 2'b10;
|
||||
end
|
||||
|
||||
REG_BIT_RW: begin
|
||||
rw_new[b] = wr_data32[b];
|
||||
end
|
||||
|
||||
REG_BIT_W1S: begin
|
||||
if (wr_data32[b]) begin
|
||||
rw_new[b] = 1'b1;
|
||||
reg_pulse[wr_idx][b] <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
REG_BIT_W1C: begin
|
||||
if (wr_data32[b]) begin
|
||||
rw_new[b] = 1'b0;
|
||||
reg_pulse[wr_idx][b] <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
reg_o[wr_idx] <= rw_new;
|
||||
end
|
||||
|
||||
aw_seen_q <= 1'b0;
|
||||
w_seen_q <= 1'b0;
|
||||
end
|
||||
|
||||
if (bvalid_q && s_axil.req.b_ready) begin
|
||||
bvalid_q <= 1'b0;
|
||||
end
|
||||
|
||||
if (s_axil.req.ar.valid && s_axil.resp.ar_ready) begin
|
||||
rvalid_q <= 1'b1;
|
||||
rresp_q <= 2'b00;
|
||||
rd_word = '0;
|
||||
|
||||
if (!rd_addr_valid) begin
|
||||
rresp_q <= 2'b10;
|
||||
end else begin
|
||||
for (b = 0; b < 32; b = b + 1) begin
|
||||
unique case (reg_bit_mode_t'(REG_MODE[rd_idx][b]))
|
||||
REG_BIT_RSVD: rd_word[b] = 1'b0;
|
||||
REG_BIT_RO : rd_word[b] = reg_i[rd_idx][b];
|
||||
REG_BIT_RW : rd_word[b] = reg_o[rd_idx][b];
|
||||
REG_BIT_W1S : rd_word[b] = 1'b0;
|
||||
REG_BIT_W1C : rd_word[b] = reg_o[rd_idx][b];
|
||||
default : rd_word[b] = 1'b0;
|
||||
endcase
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
rdata_q <= rd_word;
|
||||
end
|
||||
|
||||
if (rvalid_q && s_axil.req.r_ready) begin
|
||||
rvalid_q <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,67 @@
|
||||
module axi4l_reg_map_example #(
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1
|
||||
)(
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
axi4l_if.slave s_axil,
|
||||
|
||||
output logic start_o,
|
||||
output logic soft_reset_o,
|
||||
output logic enable_o,
|
||||
output logic irq_enable_o,
|
||||
output logic [31:0] config_o,
|
||||
|
||||
input logic busy_i,
|
||||
input logic done_i,
|
||||
input logic error_i,
|
||||
input logic [7:0] error_code_i
|
||||
);
|
||||
import axi4l_reg_map_example_pkg::*;
|
||||
|
||||
localparam int unsigned N_REGS = AXI4L_REG_MAP_EXAMPLE_N_REGS;
|
||||
|
||||
logic [N_REGS-1:0][31:0] reg_i;
|
||||
logic [N_REGS-1:0][31:0] reg_o;
|
||||
logic [N_REGS-1:0][31:0] reg_pulse;
|
||||
|
||||
axi4l_reg_map #(
|
||||
.ADDR_W (ADDR_W),
|
||||
.DATA_W (DATA_W),
|
||||
.USER_W (USER_W),
|
||||
.N_REGS (N_REGS),
|
||||
.REG_MODE (AXI4L_REG_MAP_EXAMPLE_REG_MODE),
|
||||
.REG_RST (AXI4L_REG_MAP_EXAMPLE_REG_RST)
|
||||
) u_reg_map (
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.s_axil (s_axil),
|
||||
.reg_i (reg_i),
|
||||
.reg_o (reg_o),
|
||||
.reg_pulse (reg_pulse)
|
||||
);
|
||||
|
||||
always_comb begin
|
||||
reg_i = '0;
|
||||
|
||||
// REG_STATUS @ 0x04
|
||||
reg_i[REG_STATUS][STATUS_BUSY_BIT] = busy_i;
|
||||
reg_i[REG_STATUS][STATUS_DONE_BIT] = done_i;
|
||||
reg_i[REG_STATUS][STATUS_ERROR_BIT] = error_i;
|
||||
reg_i[REG_STATUS][STATUS_ERROR_CODE_MSB:STATUS_ERROR_CODE_LSB] = error_code_i;
|
||||
|
||||
// REG_VERSION @ 0x0c
|
||||
reg_i[REG_VERSION] = VERSION_VAL;
|
||||
end
|
||||
|
||||
// REG_CTRL @ 0x00
|
||||
assign start_o = reg_pulse[REG_CTRL][CTRL_START_BIT];
|
||||
assign soft_reset_o = reg_pulse[REG_CTRL][CTRL_SOFT_RESET_BIT];
|
||||
assign enable_o = reg_o[REG_CTRL][CTRL_ENABLE_BIT];
|
||||
assign irq_enable_o = reg_o[REG_CTRL][CTRL_IRQ_ENABLE_BIT];
|
||||
|
||||
// REG_CONFIG @ 0x08
|
||||
assign config_o = reg_o[REG_CONFIG];
|
||||
|
||||
endmodule : axi4l_reg_map_example
|
||||
@@ -0,0 +1,68 @@
|
||||
package axi4l_reg_map_example_pkg;
|
||||
import axi4l_reg_map_pkg::*;
|
||||
|
||||
localparam int unsigned AXI4L_REG_MAP_EXAMPLE_N_REGS = 4;
|
||||
|
||||
localparam int unsigned REG_CTRL = 0;
|
||||
localparam int unsigned REG_STATUS = 1;
|
||||
localparam int unsigned REG_CONFIG = 2;
|
||||
localparam int unsigned REG_VERSION = 3;
|
||||
|
||||
localparam logic [15:0] REG_CTRL_ADDR = 16'h0000;
|
||||
localparam logic [15:0] REG_STATUS_ADDR = 16'h0004;
|
||||
localparam logic [15:0] REG_CONFIG_ADDR = 16'h0008;
|
||||
localparam logic [15:0] REG_VERSION_ADDR = 16'h000c;
|
||||
|
||||
localparam int unsigned CTRL_START_BIT = 0;
|
||||
localparam int unsigned CTRL_SOFT_RESET_BIT = 1;
|
||||
localparam int unsigned CTRL_ENABLE_BIT = 2;
|
||||
localparam int unsigned CTRL_IRQ_ENABLE_BIT = 3;
|
||||
|
||||
localparam int unsigned STATUS_BUSY_BIT = 0;
|
||||
localparam int unsigned STATUS_DONE_BIT = 1;
|
||||
localparam int unsigned STATUS_ERROR_BIT = 2;
|
||||
|
||||
localparam int unsigned STATUS_ERROR_CODE_LSB = 8;
|
||||
localparam int unsigned STATUS_ERROR_CODE_MSB = 15;
|
||||
|
||||
localparam logic [31:0] CONFIG_RST = 32'h0000_0001;
|
||||
localparam logic [31:0] VERSION_VAL = 32'h0001_0000;
|
||||
|
||||
localparam logic [AXI4L_REG_MAP_EXAMPLE_N_REGS-1:0][31:0][2:0] AXI4L_REG_MAP_EXAMPLE_REG_MODE = '{
|
||||
REG_CTRL: '{
|
||||
CTRL_START_BIT : REG_BIT_W1S,
|
||||
CTRL_SOFT_RESET_BIT : REG_BIT_W1S,
|
||||
CTRL_ENABLE_BIT : REG_BIT_RW,
|
||||
CTRL_IRQ_ENABLE_BIT : REG_BIT_RW,
|
||||
default : REG_BIT_RSVD
|
||||
},
|
||||
REG_STATUS: '{
|
||||
STATUS_BUSY_BIT : REG_BIT_RO,
|
||||
STATUS_DONE_BIT : REG_BIT_RO,
|
||||
STATUS_ERROR_BIT : REG_BIT_RO,
|
||||
STATUS_ERROR_CODE_LSB : REG_BIT_RO,
|
||||
STATUS_ERROR_CODE_LSB+1 : REG_BIT_RO,
|
||||
STATUS_ERROR_CODE_LSB+2 : REG_BIT_RO,
|
||||
STATUS_ERROR_CODE_LSB+3 : REG_BIT_RO,
|
||||
STATUS_ERROR_CODE_LSB+4 : REG_BIT_RO,
|
||||
STATUS_ERROR_CODE_LSB+5 : REG_BIT_RO,
|
||||
STATUS_ERROR_CODE_LSB+6 : REG_BIT_RO,
|
||||
STATUS_ERROR_CODE_LSB+7 : REG_BIT_RO,
|
||||
default : REG_BIT_RSVD
|
||||
},
|
||||
REG_CONFIG: '{
|
||||
default: REG_BIT_RW
|
||||
},
|
||||
REG_VERSION: '{
|
||||
default: REG_BIT_RO
|
||||
}
|
||||
};
|
||||
|
||||
localparam logic [AXI4L_REG_MAP_EXAMPLE_N_REGS-1:0][31:0] AXI4L_REG_MAP_EXAMPLE_REG_RST = '{
|
||||
REG_CTRL : 32'h0000_0000,
|
||||
REG_STATUS : 32'h0000_0000,
|
||||
REG_CONFIG : CONFIG_RST,
|
||||
REG_VERSION : 32'h0000_0000
|
||||
};
|
||||
|
||||
endpackage : axi4l_reg_map_example_pkg
|
||||
@@ -0,0 +1,64 @@
|
||||
package dma_axil_reg_map_pkg;
|
||||
|
||||
localparam int unsigned DMA_AXIL_REG_MAP_N_REGS = 6;
|
||||
|
||||
localparam int unsigned DMA_WRITE_DESC_CONTROL_REG = 0;
|
||||
localparam int unsigned DMA_WRITE_DESC_ADDR_REG = 1;
|
||||
localparam int unsigned DMA_WRITE_DESC_LEN_REG = 2;
|
||||
localparam int unsigned DMA_READ_DESC_CONTROL_REG = 3;
|
||||
localparam int unsigned DMA_READ_DESC_ADDR_REG = 4;
|
||||
localparam int unsigned DMA_READ_DESC_LEN_REG = 5;
|
||||
|
||||
localparam logic [2:0] REG_BIT_RSVD = 3'd0;
|
||||
localparam logic [2:0] REG_BIT_RO = 3'd1;
|
||||
localparam logic [2:0] REG_BIT_RW = 3'd2;
|
||||
localparam logic [2:0] REG_BIT_W1S = 3'd3;
|
||||
|
||||
typedef logic [DMA_AXIL_REG_MAP_N_REGS-1:0][31:0][2:0] reg_mode_map_t;
|
||||
|
||||
function automatic reg_mode_map_t make_dma_reg_mode();
|
||||
reg_mode_map_t mode;
|
||||
|
||||
mode = '0;
|
||||
|
||||
// По умолчанию всё reserved
|
||||
for (int reg_idx = 0; reg_idx < DMA_AXIL_REG_MAP_N_REGS; reg_idx++) begin
|
||||
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
|
||||
mode[reg_idx][bit_idx] = REG_BIT_RSVD;
|
||||
end
|
||||
end
|
||||
|
||||
// WRITE CONTROL
|
||||
mode[DMA_WRITE_DESC_CONTROL_REG][0] = REG_BIT_RO;
|
||||
mode[DMA_WRITE_DESC_CONTROL_REG][1] = REG_BIT_W1S;
|
||||
|
||||
// WRITE ADDR
|
||||
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
|
||||
mode[DMA_WRITE_DESC_ADDR_REG][bit_idx] = REG_BIT_RW;
|
||||
end
|
||||
|
||||
// WRITE LEN
|
||||
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
|
||||
mode[DMA_WRITE_DESC_LEN_REG][bit_idx] = REG_BIT_RW;
|
||||
end
|
||||
|
||||
// READ CONTROL
|
||||
mode[DMA_READ_DESC_CONTROL_REG][0] = REG_BIT_RO;
|
||||
mode[DMA_READ_DESC_CONTROL_REG][1] = REG_BIT_W1S;
|
||||
|
||||
// READ ADDR
|
||||
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
|
||||
mode[DMA_READ_DESC_ADDR_REG][bit_idx] = REG_BIT_RW;
|
||||
end
|
||||
|
||||
// READ LEN
|
||||
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
|
||||
mode[DMA_READ_DESC_LEN_REG][bit_idx] = REG_BIT_RW;
|
||||
end
|
||||
|
||||
return mode;
|
||||
endfunction
|
||||
|
||||
localparam reg_mode_map_t DMA_AXIL_REG_MAP_REG_MODE = make_dma_reg_mode();
|
||||
|
||||
endpackage
|
||||
@@ -0,0 +1,97 @@
|
||||
module axi4_flat_to_if #(
|
||||
parameter int unsigned ADDR_W = 32,
|
||||
parameter int unsigned DATA_W = 64,
|
||||
parameter int unsigned ID_W = 4,
|
||||
parameter int unsigned USER_W = 1
|
||||
)(
|
||||
input logic [ID_W-1:0] s_axi_awid,
|
||||
input logic [ADDR_W-1:0] s_axi_awaddr,
|
||||
input logic [7:0] s_axi_awlen,
|
||||
input logic [2:0] s_axi_awsize,
|
||||
input logic [1:0] s_axi_awburst,
|
||||
input logic s_axi_awlock,
|
||||
input logic [3:0] s_axi_awcache,
|
||||
input logic [2:0] s_axi_awprot,
|
||||
input logic [3:0] s_axi_awqos,
|
||||
input logic [3:0] s_axi_awregion,
|
||||
input logic [USER_W-1:0] s_axi_awuser,
|
||||
input logic s_axi_awvalid,
|
||||
output logic s_axi_awready,
|
||||
input logic [DATA_W-1:0] s_axi_wdata,
|
||||
input logic [DATA_W/8-1:0] s_axi_wstrb,
|
||||
input logic s_axi_wlast,
|
||||
input logic [USER_W-1:0] s_axi_wuser,
|
||||
input logic s_axi_wvalid,
|
||||
output logic s_axi_wready,
|
||||
output logic [ID_W-1:0] s_axi_bid,
|
||||
output logic [1:0] s_axi_bresp,
|
||||
output logic [USER_W-1:0] s_axi_buser,
|
||||
output logic s_axi_bvalid,
|
||||
input logic s_axi_bready,
|
||||
input logic [ID_W-1:0] s_axi_arid,
|
||||
input logic [ADDR_W-1:0] s_axi_araddr,
|
||||
input logic [7:0] s_axi_arlen,
|
||||
input logic [2:0] s_axi_arsize,
|
||||
input logic [1:0] s_axi_arburst,
|
||||
input logic s_axi_arlock,
|
||||
input logic [3:0] s_axi_arcache,
|
||||
input logic [2:0] s_axi_arprot,
|
||||
input logic [3:0] s_axi_arqos,
|
||||
input logic [3:0] s_axi_arregion,
|
||||
input logic [USER_W-1:0] s_axi_aruser,
|
||||
input logic s_axi_arvalid,
|
||||
output logic s_axi_arready,
|
||||
output logic [ID_W-1:0] s_axi_rid,
|
||||
output logic [DATA_W-1:0] s_axi_rdata,
|
||||
output logic [1:0] s_axi_rresp,
|
||||
output logic s_axi_rlast,
|
||||
output logic [USER_W-1:0] s_axi_ruser,
|
||||
output logic s_axi_rvalid,
|
||||
input logic s_axi_rready,
|
||||
axi4_if.master m_axi
|
||||
);
|
||||
assign m_axi.req.aw.id = s_axi_awid;
|
||||
assign m_axi.req.aw.addr = s_axi_awaddr;
|
||||
assign m_axi.req.aw.len = s_axi_awlen;
|
||||
assign m_axi.req.aw.size = s_axi_awsize;
|
||||
assign m_axi.req.aw.burst = axi_pkg::axi_burst_t'(s_axi_awburst);
|
||||
assign m_axi.req.aw.lock = s_axi_awlock;
|
||||
assign m_axi.req.aw.cache = s_axi_awcache;
|
||||
assign m_axi.req.aw.prot = s_axi_awprot;
|
||||
assign m_axi.req.aw.qos = s_axi_awqos;
|
||||
assign m_axi.req.aw.region = s_axi_awregion;
|
||||
assign m_axi.req.aw.user = s_axi_awuser;
|
||||
assign m_axi.req.aw.valid = s_axi_awvalid;
|
||||
assign s_axi_awready = m_axi.resp.aw_ready;
|
||||
assign m_axi.req.w.data = s_axi_wdata;
|
||||
assign m_axi.req.w.strb = s_axi_wstrb;
|
||||
assign m_axi.req.w.last = s_axi_wlast;
|
||||
assign m_axi.req.w.user = s_axi_wuser;
|
||||
assign m_axi.req.w.valid = s_axi_wvalid;
|
||||
assign s_axi_wready = m_axi.resp.w_ready;
|
||||
assign s_axi_bid = m_axi.resp.b.id;
|
||||
assign s_axi_bresp = m_axi.resp.b.resp;
|
||||
assign s_axi_buser = m_axi.resp.b.user;
|
||||
assign s_axi_bvalid = m_axi.resp.b.valid;
|
||||
assign m_axi.req.b_ready = s_axi_bready;
|
||||
assign m_axi.req.ar.id = s_axi_arid;
|
||||
assign m_axi.req.ar.addr = s_axi_araddr;
|
||||
assign m_axi.req.ar.len = s_axi_arlen;
|
||||
assign m_axi.req.ar.size = s_axi_arsize;
|
||||
assign m_axi.req.ar.burst = axi_pkg::axi_burst_t'(s_axi_arburst);
|
||||
assign m_axi.req.ar.lock = s_axi_arlock;
|
||||
assign m_axi.req.ar.cache = s_axi_arcache;
|
||||
assign m_axi.req.ar.prot = s_axi_arprot;
|
||||
assign m_axi.req.ar.qos = s_axi_arqos;
|
||||
assign m_axi.req.ar.region = s_axi_arregion;
|
||||
assign m_axi.req.ar.user = s_axi_aruser;
|
||||
assign m_axi.req.ar.valid = s_axi_arvalid;
|
||||
assign s_axi_arready = m_axi.resp.ar_ready;
|
||||
assign s_axi_rid = m_axi.resp.r.id;
|
||||
assign s_axi_rdata = m_axi.resp.r.data;
|
||||
assign s_axi_rresp = m_axi.resp.r.resp;
|
||||
assign s_axi_rlast = m_axi.resp.r.last;
|
||||
assign s_axi_ruser = m_axi.resp.r.user;
|
||||
assign s_axi_rvalid = m_axi.resp.r.valid;
|
||||
assign m_axi.req.r_ready = s_axi_rready;
|
||||
endmodule
|
||||
@@ -0,0 +1,97 @@
|
||||
module axi4_if_to_flat #(
|
||||
parameter int unsigned ADDR_W = 32,
|
||||
parameter int unsigned DATA_W = 64,
|
||||
parameter int unsigned ID_W = 4,
|
||||
parameter int unsigned USER_W = 1
|
||||
)(
|
||||
axi4_if.slave s_axi,
|
||||
output logic [ID_W-1:0] m_axi_awid,
|
||||
output logic [ADDR_W-1:0] m_axi_awaddr,
|
||||
output logic [7:0] m_axi_awlen,
|
||||
output logic [2:0] m_axi_awsize,
|
||||
output logic [1:0] m_axi_awburst,
|
||||
output logic m_axi_awlock,
|
||||
output logic [3:0] m_axi_awcache,
|
||||
output logic [2:0] m_axi_awprot,
|
||||
output logic [3:0] m_axi_awqos,
|
||||
output logic [3:0] m_axi_awregion,
|
||||
output logic [USER_W-1:0] m_axi_awuser,
|
||||
output logic m_axi_awvalid,
|
||||
input logic m_axi_awready,
|
||||
output logic [DATA_W-1:0] m_axi_wdata,
|
||||
output logic [DATA_W/8-1:0] m_axi_wstrb,
|
||||
output logic m_axi_wlast,
|
||||
output logic [USER_W-1:0] m_axi_wuser,
|
||||
output logic m_axi_wvalid,
|
||||
input logic m_axi_wready,
|
||||
input logic [ID_W-1:0] m_axi_bid,
|
||||
input logic [1:0] m_axi_bresp,
|
||||
input logic [USER_W-1:0] m_axi_buser,
|
||||
input logic m_axi_bvalid,
|
||||
output logic m_axi_bready,
|
||||
output logic [ID_W-1:0] m_axi_arid,
|
||||
output logic [ADDR_W-1:0] m_axi_araddr,
|
||||
output logic [7:0] m_axi_arlen,
|
||||
output logic [2:0] m_axi_arsize,
|
||||
output logic [1:0] m_axi_arburst,
|
||||
output logic m_axi_arlock,
|
||||
output logic [3:0] m_axi_arcache,
|
||||
output logic [2:0] m_axi_arprot,
|
||||
output logic [3:0] m_axi_arqos,
|
||||
output logic [3:0] m_axi_arregion,
|
||||
output logic [USER_W-1:0] m_axi_aruser,
|
||||
output logic m_axi_arvalid,
|
||||
input logic m_axi_arready,
|
||||
input logic [ID_W-1:0] m_axi_rid,
|
||||
input logic [DATA_W-1:0] m_axi_rdata,
|
||||
input logic [1:0] m_axi_rresp,
|
||||
input logic m_axi_rlast,
|
||||
input logic [USER_W-1:0] m_axi_ruser,
|
||||
input logic m_axi_rvalid,
|
||||
output logic m_axi_rready
|
||||
);
|
||||
assign m_axi_awid = s_axi.req.aw.id;
|
||||
assign m_axi_awaddr = s_axi.req.aw.addr;
|
||||
assign m_axi_awlen = s_axi.req.aw.len;
|
||||
assign m_axi_awsize = s_axi.req.aw.size;
|
||||
assign m_axi_awburst = s_axi.req.aw.burst;
|
||||
assign m_axi_awlock = s_axi.req.aw.lock;
|
||||
assign m_axi_awcache = s_axi.req.aw.cache;
|
||||
assign m_axi_awprot = s_axi.req.aw.prot;
|
||||
assign m_axi_awqos = s_axi.req.aw.qos;
|
||||
assign m_axi_awregion = s_axi.req.aw.region;
|
||||
assign m_axi_awuser = s_axi.req.aw.user;
|
||||
assign m_axi_awvalid = s_axi.req.aw.valid;
|
||||
assign s_axi.resp.aw_ready = m_axi_awready;
|
||||
assign m_axi_wdata = s_axi.req.w.data;
|
||||
assign m_axi_wstrb = s_axi.req.w.strb;
|
||||
assign m_axi_wlast = s_axi.req.w.last;
|
||||
assign m_axi_wuser = s_axi.req.w.user;
|
||||
assign m_axi_wvalid = s_axi.req.w.valid;
|
||||
assign s_axi.resp.w_ready = m_axi_wready;
|
||||
assign s_axi.resp.b.id = m_axi_bid;
|
||||
assign s_axi.resp.b.resp = axi_pkg::axi_resp_t'(m_axi_bresp);
|
||||
assign s_axi.resp.b.user = m_axi_buser;
|
||||
assign s_axi.resp.b.valid= m_axi_bvalid;
|
||||
assign m_axi_bready = s_axi.req.b_ready;
|
||||
assign m_axi_arid = s_axi.req.ar.id;
|
||||
assign m_axi_araddr = s_axi.req.ar.addr;
|
||||
assign m_axi_arlen = s_axi.req.ar.len;
|
||||
assign m_axi_arsize = s_axi.req.ar.size;
|
||||
assign m_axi_arburst = s_axi.req.ar.burst;
|
||||
assign m_axi_arlock = s_axi.req.ar.lock;
|
||||
assign m_axi_arcache = s_axi.req.ar.cache;
|
||||
assign m_axi_arprot = s_axi.req.ar.prot;
|
||||
assign m_axi_arqos = s_axi.req.ar.qos;
|
||||
assign m_axi_arregion = s_axi.req.ar.region;
|
||||
assign m_axi_aruser = s_axi.req.ar.user;
|
||||
assign m_axi_arvalid = s_axi.req.ar.valid;
|
||||
assign s_axi.resp.ar_ready = m_axi_arready;
|
||||
assign s_axi.resp.r.id = m_axi_rid;
|
||||
assign s_axi.resp.r.data = m_axi_rdata;
|
||||
assign s_axi.resp.r.resp = axi_pkg::axi_resp_t'(m_axi_rresp);
|
||||
assign s_axi.resp.r.last = m_axi_rlast;
|
||||
assign s_axi.resp.r.user = m_axi_ruser;
|
||||
assign s_axi.resp.r.valid= m_axi_rvalid;
|
||||
assign m_axi_rready = s_axi.req.r_ready;
|
||||
endmodule
|
||||
@@ -0,0 +1,58 @@
|
||||
module axi4l_flat_to_if #(
|
||||
parameter int unsigned ADDR_W = 32,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1
|
||||
)(
|
||||
input logic aclk,
|
||||
input logic aresetn,
|
||||
input logic [ADDR_W-1:0] s_axil_awaddr,
|
||||
input logic [2:0] s_axil_awprot,
|
||||
input logic [USER_W-1:0] s_axil_awuser,
|
||||
input logic s_axil_awvalid,
|
||||
output logic s_axil_awready,
|
||||
input logic [DATA_W-1:0] s_axil_wdata,
|
||||
input logic [DATA_W/8-1:0] s_axil_wstrb,
|
||||
input logic [USER_W-1:0] s_axil_wuser,
|
||||
input logic s_axil_wvalid,
|
||||
output logic s_axil_wready,
|
||||
output logic [1:0] s_axil_bresp,
|
||||
output logic [USER_W-1:0] s_axil_buser,
|
||||
output logic s_axil_bvalid,
|
||||
input logic s_axil_bready,
|
||||
input logic [ADDR_W-1:0] s_axil_araddr,
|
||||
input logic [2:0] s_axil_arprot,
|
||||
input logic [USER_W-1:0] s_axil_aruser,
|
||||
input logic s_axil_arvalid,
|
||||
output logic s_axil_arready,
|
||||
output logic [DATA_W-1:0] s_axil_rdata,
|
||||
output logic [1:0] s_axil_rresp,
|
||||
output logic [USER_W-1:0] s_axil_ruser,
|
||||
output logic s_axil_rvalid,
|
||||
input logic s_axil_rready,
|
||||
axi4l_if.master m_axil
|
||||
);
|
||||
assign m_axil.req.aw.addr = s_axil_awaddr;
|
||||
assign m_axil.req.aw.prot = s_axil_awprot;
|
||||
assign m_axil.req.aw.user = s_axil_awuser;
|
||||
assign m_axil.req.aw.valid = s_axil_awvalid;
|
||||
assign s_axil_awready = m_axil.resp.aw_ready;
|
||||
assign m_axil.req.w.data = s_axil_wdata;
|
||||
assign m_axil.req.w.strb = s_axil_wstrb;
|
||||
assign m_axil.req.w.user = s_axil_wuser;
|
||||
assign m_axil.req.w.valid = s_axil_wvalid;
|
||||
assign s_axil_wready = m_axil.resp.w_ready;
|
||||
assign s_axil_bresp = m_axil.resp.b.resp;
|
||||
assign s_axil_buser = m_axil.resp.b.user;
|
||||
assign s_axil_bvalid = m_axil.resp.b.valid;
|
||||
assign m_axil.req.b_ready = s_axil_bready;
|
||||
assign m_axil.req.ar.addr = s_axil_araddr;
|
||||
assign m_axil.req.ar.prot = s_axil_arprot;
|
||||
assign m_axil.req.ar.user = s_axil_aruser;
|
||||
assign m_axil.req.ar.valid = s_axil_arvalid;
|
||||
assign s_axil_arready = m_axil.resp.ar_ready;
|
||||
assign s_axil_rdata = m_axil.resp.r.data;
|
||||
assign s_axil_rresp = m_axil.resp.r.resp;
|
||||
assign s_axil_ruser = m_axil.resp.r.user;
|
||||
assign s_axil_rvalid = m_axil.resp.r.valid;
|
||||
assign m_axil.req.r_ready = s_axil_rready;
|
||||
endmodule
|
||||
@@ -0,0 +1,56 @@
|
||||
module axi4l_if_to_flat #(
|
||||
parameter int unsigned ADDR_W = 32,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1
|
||||
)(
|
||||
axi4l_if.slave s_axil,
|
||||
output logic [ADDR_W-1:0] m_axil_awaddr,
|
||||
output logic [2:0] m_axil_awprot,
|
||||
output logic [USER_W-1:0] m_axil_awuser,
|
||||
output logic m_axil_awvalid,
|
||||
input logic m_axil_awready,
|
||||
output logic [DATA_W-1:0] m_axil_wdata,
|
||||
output logic [DATA_W/8-1:0] m_axil_wstrb,
|
||||
output logic [USER_W-1:0] m_axil_wuser,
|
||||
output logic m_axil_wvalid,
|
||||
input logic m_axil_wready,
|
||||
input logic [1:0] m_axil_bresp,
|
||||
input logic [USER_W-1:0] m_axil_buser,
|
||||
input logic m_axil_bvalid,
|
||||
output logic m_axil_bready,
|
||||
output logic [ADDR_W-1:0] m_axil_araddr,
|
||||
output logic [2:0] m_axil_arprot,
|
||||
output logic [USER_W-1:0] m_axil_aruser,
|
||||
output logic m_axil_arvalid,
|
||||
input logic m_axil_arready,
|
||||
input logic [DATA_W-1:0] m_axil_rdata,
|
||||
input logic [1:0] m_axil_rresp,
|
||||
input logic [USER_W-1:0] m_axil_ruser,
|
||||
input logic m_axil_rvalid,
|
||||
output logic m_axil_rready
|
||||
);
|
||||
assign m_axil_awaddr = s_axil.req.aw.addr;
|
||||
assign m_axil_awprot = s_axil.req.aw.prot;
|
||||
assign m_axil_awuser = s_axil.req.aw.user;
|
||||
assign m_axil_awvalid = s_axil.req.aw.valid;
|
||||
assign s_axil.resp.aw_ready = m_axil_awready;
|
||||
assign m_axil_wdata = s_axil.req.w.data;
|
||||
assign m_axil_wstrb = s_axil.req.w.strb;
|
||||
assign m_axil_wuser = s_axil.req.w.user;
|
||||
assign m_axil_wvalid = s_axil.req.w.valid;
|
||||
assign s_axil.resp.w_ready = m_axil_wready;
|
||||
assign s_axil.resp.b.resp = axi_pkg::axi_resp_t'(m_axil_bresp);
|
||||
assign s_axil.resp.b.user = m_axil_buser;
|
||||
assign s_axil.resp.b.valid = m_axil_bvalid;
|
||||
assign m_axil_bready = s_axil.req.b_ready;
|
||||
assign m_axil_araddr = s_axil.req.ar.addr;
|
||||
assign m_axil_arprot = s_axil.req.ar.prot;
|
||||
assign m_axil_aruser = s_axil.req.ar.user;
|
||||
assign m_axil_arvalid = s_axil.req.ar.valid;
|
||||
assign s_axil.resp.ar_ready = m_axil_arready;
|
||||
assign s_axil.resp.r.data = m_axil_rdata;
|
||||
assign s_axil.resp.r.resp = axi_pkg::axi_resp_t'(m_axil_rresp);
|
||||
assign s_axil.resp.r.user = m_axil_ruser;
|
||||
assign s_axil.resp.r.valid = m_axil_rvalid;
|
||||
assign m_axil_rready = s_axil.req.r_ready;
|
||||
endmodule
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
module axi4l_reg_map #(
|
||||
parameter int unsigned ADDR_W = 16,
|
||||
parameter int unsigned DATA_W = 32,
|
||||
parameter int unsigned USER_W = 1,
|
||||
parameter int unsigned N_REGS = 4,
|
||||
|
||||
parameter logic [N_REGS-1:0][31:0][2:0] REG_MODE = '{default:'0},
|
||||
parameter logic [N_REGS-1:0][31:0] REG_RST = '{default:'0}
|
||||
)(
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
axi4l_if.slave s_axil,
|
||||
|
||||
input logic [N_REGS-1:0][31:0] reg_i,
|
||||
output logic [N_REGS-1:0][31:0] reg_o
|
||||
);
|
||||
import axi_pkg::*;
|
||||
|
||||
typedef enum logic [2:0] {
|
||||
REG_BIT_RSVD = 3'd0,
|
||||
REG_BIT_RO = 3'd1,
|
||||
REG_BIT_RW = 3'd2,
|
||||
REG_BIT_W1S = 3'd3,
|
||||
REG_BIT_W1C = 3'd4
|
||||
} reg_bit_mode_t;
|
||||
|
||||
localparam int unsigned STRB_W = DATA_W/8;
|
||||
localparam int unsigned ADDR_LSB = $clog2(DATA_W/8);
|
||||
localparam int unsigned REG_INDEX_W = (N_REGS <= 1) ? 1 : $clog2(N_REGS);
|
||||
|
||||
logic [ADDR_W-1:0] awaddr_q;
|
||||
logic aw_seen_q;
|
||||
logic [DATA_W-1:0] wdata_q;
|
||||
logic [STRB_W-1:0] wstrb_q;
|
||||
logic w_seen_q;
|
||||
|
||||
logic bvalid_q;
|
||||
logic [1:0] bresp_q;
|
||||
|
||||
logic rvalid_q;
|
||||
logic [1:0] rresp_q;
|
||||
logic [DATA_W-1:0] rdata_q;
|
||||
|
||||
logic [REG_INDEX_W-1:0] wr_idx;
|
||||
logic [REG_INDEX_W-1:0] rd_idx;
|
||||
logic wr_addr_valid;
|
||||
logic rd_addr_valid;
|
||||
|
||||
integer b;
|
||||
logic [31:0] wr_mask;
|
||||
logic [31:0] wr_data32;
|
||||
logic [31:0] rw_cur;
|
||||
logic [31:0] rw_new;
|
||||
logic [31:0] rd_word;
|
||||
|
||||
always_comb begin
|
||||
wr_idx = '0;
|
||||
rd_idx = '0;
|
||||
wr_addr_valid = 1'b0;
|
||||
rd_addr_valid = 1'b0;
|
||||
|
||||
if (awaddr_q[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W] < N_REGS) begin
|
||||
wr_idx = awaddr_q[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W];
|
||||
wr_addr_valid = 1'b1;
|
||||
end
|
||||
|
||||
if (s_axil.req.ar.addr[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W] < N_REGS) begin
|
||||
rd_idx = s_axil.req.ar.addr[ADDR_LSB + REG_INDEX_W - 1 -: REG_INDEX_W];
|
||||
rd_addr_valid = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always_comb begin
|
||||
wr_mask = '0;
|
||||
for (int k = 0; k < STRB_W; k++) begin
|
||||
wr_mask[k*8 +: 8] = {8{wstrb_q[k]}};
|
||||
end
|
||||
wr_data32 = wdata_q[31:0];
|
||||
end
|
||||
|
||||
assign s_axil.resp.aw_ready = !aw_seen_q && !bvalid_q;
|
||||
assign s_axil.resp.w_ready = !w_seen_q && !bvalid_q;
|
||||
assign s_axil.resp.ar_ready = !rvalid_q;
|
||||
|
||||
assign s_axil.resp.b.valid = bvalid_q;
|
||||
assign s_axil.resp.b.resp = axi_resp_t'(bresp_q);
|
||||
assign s_axil.resp.b.user = '0;
|
||||
|
||||
assign s_axil.resp.r.valid = rvalid_q;
|
||||
assign s_axil.resp.r.resp = axi_resp_t'(rresp_q);
|
||||
assign s_axil.resp.r.data = rdata_q;
|
||||
assign s_axil.resp.r.user = '0;
|
||||
|
||||
always_ff @(posedge clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
awaddr_q <= '0;
|
||||
aw_seen_q <= 1'b0;
|
||||
wdata_q <= '0;
|
||||
wstrb_q <= '0;
|
||||
w_seen_q <= 1'b0;
|
||||
bvalid_q <= 1'b0;
|
||||
bresp_q <= 2'b00;
|
||||
rvalid_q <= 1'b0;
|
||||
rresp_q <= 2'b00;
|
||||
rdata_q <= '0;
|
||||
reg_o <= REG_RST;
|
||||
end else begin
|
||||
for (int r = 0; r < N_REGS; r++) begin
|
||||
for (int bit_idx = 0; bit_idx < 32; bit_idx++) begin
|
||||
if (reg_bit_mode_t'(REG_MODE[r][bit_idx]) == REG_BIT_W1S)
|
||||
reg_o[r][bit_idx] <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
if (s_axil.req.aw.valid && s_axil.resp.aw_ready) begin
|
||||
awaddr_q <= s_axil.req.aw.addr;
|
||||
aw_seen_q <= 1'b1;
|
||||
end
|
||||
|
||||
if (s_axil.req.w.valid && s_axil.resp.w_ready) begin
|
||||
wdata_q <= s_axil.req.w.data;
|
||||
wstrb_q <= s_axil.req.w.strb;
|
||||
w_seen_q <= 1'b1;
|
||||
end
|
||||
|
||||
if (aw_seen_q && w_seen_q && !bvalid_q) begin
|
||||
bvalid_q <= 1'b1;
|
||||
bresp_q <= 2'b00;
|
||||
|
||||
if (!wr_addr_valid) begin
|
||||
bresp_q <= 2'b10;
|
||||
end else begin
|
||||
rw_cur = reg_o[wr_idx];
|
||||
rw_new = rw_cur;
|
||||
|
||||
for (b = 0; b < 32; b = b + 1) begin
|
||||
if (wr_mask[b]) begin
|
||||
unique case (reg_bit_mode_t'(REG_MODE[wr_idx][b]))
|
||||
REG_BIT_RSVD: begin end
|
||||
REG_BIT_RO : begin bresp_q <= 2'b10; end
|
||||
REG_BIT_RW : rw_new[b] = wr_data32[b];
|
||||
REG_BIT_W1S : if (wr_data32[b]) rw_new[b] = 1'b1;
|
||||
REG_BIT_W1C : if (wr_data32[b]) rw_new[b] = 1'b0;
|
||||
default : begin end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
reg_o[wr_idx] <= rw_new;
|
||||
end
|
||||
|
||||
aw_seen_q <= 1'b0;
|
||||
w_seen_q <= 1'b0;
|
||||
end
|
||||
|
||||
if (bvalid_q && s_axil.req.b_ready) begin
|
||||
bvalid_q <= 1'b0;
|
||||
end
|
||||
|
||||
if (s_axil.req.ar.valid && s_axil.resp.ar_ready) begin
|
||||
rvalid_q <= 1'b1;
|
||||
rresp_q <= 2'b00;
|
||||
rd_word = '0;
|
||||
|
||||
if (!rd_addr_valid) begin
|
||||
rresp_q <= 2'b10;
|
||||
end else begin
|
||||
for (b = 0; b < 32; b = b + 1) begin
|
||||
unique case (reg_bit_mode_t'(REG_MODE[rd_idx][b]))
|
||||
REG_BIT_RSVD: rd_word[b] = 1'b0;
|
||||
REG_BIT_RO : rd_word[b] = reg_i[rd_idx][b];
|
||||
REG_BIT_RW : rd_word[b] = reg_o[rd_idx][b];
|
||||
REG_BIT_W1S : rd_word[b] = 1'b0;
|
||||
REG_BIT_W1C : rd_word[b] = reg_o[rd_idx][b];
|
||||
default : rd_word[b] = 1'b0;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
rdata_q <= rd_word;
|
||||
end
|
||||
|
||||
if (rvalid_q && s_axil.req.r_ready) begin
|
||||
rvalid_q <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user