Compare commits

..
Author SHA1 Message Date
Phil 2d4a5af40a sw: update UI 2026-09-07 18:55:42 +03:00
Phil 0526157bfc sw: change units 2026-09-07 18:54:01 +03:00
Phil 09e8ade74c sw: more information + auto-update feature 2026-09-07 18:48:20 +03:00
Phil 8d8b409807 sw: add load/save options, re-work adc/dac ratio setting 2026-09-07 17:41:23 +03:00
158 changed files with 2092 additions and 33105 deletions
+1 -6
View File
@@ -16,7 +16,6 @@
.Xil
xvlog.pb
*vivado_pid*
**/work/*
# some generated files (they annoy me)
update_config.tcl
@@ -27,8 +26,4 @@ run_sim.tcl
*.bit
*.xsa
*.ltx
*.bin
# slang files
.slang
files.f
*.bin
-1
View File
@@ -27,7 +27,6 @@ XDC_FILES += ../../constraints/ax7102.xdc
XDC_FILES += debug.xdc
SYN_FILES += tb_sync_top.sv
SIM_TOP = tb_top
+7 -9
View File
@@ -1,12 +1,10 @@
# Primary clocks
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]
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]
# 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}]
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*]]]
# Asynchronous clock groups
set_clock_groups -name ASYNC_ETH_ACC -asynchronous \
-group [get_clocks eth_clk] \
-group [get_clocks acc_clk]
+79 -100
View File
@@ -2,137 +2,113 @@
module sync_top
#(
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
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
)
(
input clk_adc,
input rst_adc,
input clk_dac,
input rst_dac,
input start,
input out_of_range,
input adc_clk_in,
input adc_rst,
input dac_clk_in,
input dac_rst,
input dac_start,
input [31:0] pulse_width,
input [31:0] pulse_period, // DAC counter limit
input [31:0] pulse_period,
input [DAC_DATA_WIDTH-1:0] pulse_height,
input [15:0] pulse_num,
input [31:0] smp_num, // ADC counter limit
output [ADC_DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata,
output m_axis_tvalid
input [31:0] smp_num,
output logic [ADC_DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata,
output logic 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;
// 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_req;
(* MARK_DEBUG="true" *) logic sample_req_sync1;
(* MARK_DEBUG="true" *) logic sample_req_sync2;
(* MARK_DEBUG="true" *) logic sample_req_sync3;
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
(* 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;
//------------------------------------------------------------
// DAC -> ADC CDC
//------------------------------------------------------------
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;
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
else begin
stretch[0] <= dac_done;
stretch[1] <= stretch[0];
stretch[2] <= stretch[1];
sample_req_sync2 <= sample_req_sync1;
sample_req_sync3 <= sample_req_sync2;
sample_req <= sample_req_sync3;
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
//------------------------------------------------------------
logic [1:0] sync_AD;
always_ff @(posedge clk_dac or posedge rst_dac) begin
if (rst_dac)
sync_AD <= 0;
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
else begin
sync_AD[0] <= adc_done;
sync_AD[1] <= sync_AD[0];
sample_done_sync2 <= sample_done_sync1;
sample_done_sync3 <= sample_done_sync2;
sample_done <= sample_done_sync3;
end
end
assign dac_request = sync_AD[1];
//------------------------------------------------------------
// Generator
//------------------------------------------------------------
generator #(
.DATA_WIDTH(DAC_DATA_WIDTH),
.ZERO_LEVEL(ZERO_LEVEL)
.DATA_WIDTH(DAC_DATA_WIDTH)
) generator_inst (
.clk_dac(clk_dac),
.rst(rst_dac),
.start(start),
.clk_in(dac_clk_in),
.rst(dac_rst),
.start(dac_start),
.pulse_width(pulse_width),
.pulse_period(pulse_period),
.pulse_height(pulse_height),
.pulse_num(pulse_num),
.dac_out(dac_signal),
.request(dac_request),
.done(dac_done)
.sample_done(sample_done),
.pulse(pulse),
.pulse_height_out(pulse_height_out),
.sample_req(sample_req_sync1)
);
//------------------------------------------------------------
@@ -143,15 +119,18 @@ module sync_top
.PACK_FACTOR(PACK_FACTOR),
.PROCESS_MODE(PROCESS_MODE)
) sampler_inst (
.clk_in(clk_adc),
.rst(rst_adc),
.data_in(adc_signal),
.clk_in(adc_clk_in),
.rst(adc_rst),
.data_in(data_in),
.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),
.request(adc_request),
.done(adc_done)
.sample_done(sample_done_sync1)
);
endmodule
+116 -521
View File
@@ -2,50 +2,39 @@
module tb_top;
//------------------------------------------------------------
// Параметры
//------------------------------------------------------------
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
localparam DAC_DATA_WIDTH = 14;
localparam ADC_DATA_WIDTH = 12;
localparam PACK_FACTOR = 1;
localparam PROCESS_MODE = 0;
//------------------------------------------------------------
// Тактовые сигналы и сброс
// clocks / reset
//------------------------------------------------------------
logic clk_dac;
logic rst_dac;
logic clk_adc;
logic rst_adc;
logic adc_clk_in;
logic adc_rst;
logic dac_clk_in;
logic dac_rst;
//------------------------------------------------------------
// Управление и конфиг
// 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
//------------------------------------------------------------
reg out_of_range;
//------------------------------------------------------------
// Выходы
//------------------------------------------------------------
wire [ADC_DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata;
wire m_axis_tvalid;
logic [ADC_DATA_WIDTH*PACK_FACTOR-1:0] m_axis_tdata;
logic m_axis_tvalid;
integer valid_count;
//------------------------------------------------------------
// DUT
//------------------------------------------------------------
@@ -53,521 +42,127 @@ module tb_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),
.USE_DELAY_LINE(USE_DELAY_LINE)
.PROCESS_MODE(PROCESS_MODE)
) dut (
.clk_adc(clk_adc),
.clk_dac(clk_dac),
.rst_adc(rst_adc),
.rst_dac(rst_dac),
.start(dac_start),
.adc_clk_in(adc_clk_in),
.adc_rst(adc_rst),
.dac_clk_in(dac_clk_in),
.dac_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),
.out_of_range(out_of_range)
.m_axis_tvalid(m_axis_tvalid)
);
// Тактовые сигналы
//------------------------------------------------------------
// ADC clock
//------------------------------------------------------------
initial begin
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;
adc_clk_in = 1'b0;
forever #5 adc_clk_in = ~adc_clk_in; // 100 MHz
end
// === Таски для тестирования ===
// Функция модуля
function automatic real fabs(real val);
return (val < 0.0) ? -val : val;
endfunction
`define MIN(x, y) (((x) < (y)) ? (x) : (y))
// Таска сброса 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
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
// Таска
// --- ОСНОВНОЙ ПРОЦЕСС ТЕСТИРОВАНИЯ ---
//------------------------------------------------------------
// DAC clock
//------------------------------------------------------------
initial begin
$display("[TB] Tests start");
dac_clk_in = 1'b0;
forever #8 dac_clk_in = ~dac_clk_in; // slower domain
end
//------------------------------------------------------------
// monitor output stream
//------------------------------------------------------------
always @(posedge adc_clk_in) begin
if (m_axis_tvalid) begin
valid_count = valid_count + 1;
$display("[%0t] VALID: data=%0d",
$time,
m_axis_tdata);
end
end
//------------------------------------------------------------
// test
//------------------------------------------------------------
initial begin
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;
#100; // init
valid_count = 0;
$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)
);
//--------------------------------------------------------
// reset
//--------------------------------------------------------
repeat (10) @(posedge adc_clk_in);
repeat (10) @(posedge dac_clk_in);
$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)
);
adc_rst = 1'b0;
dac_rst = 1'b0;
$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)
);
repeat (5) @(posedge dac_clk_in);
// Ожидание окончания работы генератора. Т.к. конец работы определяется по tvalid сэмплера, а он завершается сильно раньше. Чтобы не пропустить start следующей таски, ждем
wait(dut.generator_inst.enable == 0);
#50;
//--------------------------------------------------------
// config
//--------------------------------------------------------
pulse_width = 32'd3;
pulse_period = 32'd8;
pulse_height = 14'd200;
pulse_num = 16'd4;
smp_num = 32'd8;
$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");
//--------------------------------------------------------
// start
//--------------------------------------------------------
@(posedge dac_clk_in);
dac_start = 1'b1;
$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;
@(posedge dac_clk_in);
dac_start = 1'b0;
// Генерируем параметры
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 случайным
$display("==================================");
$display("TEST START");
$display("==================================");
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)
);
//--------------------------------------------------------
// wait
//--------------------------------------------------------
repeat (600) @(posedge adc_clk_in);
wait(dut.generator_inst.enable == 0); // Проверка на завершение работы
#50;
//--------------------------------------------------------
// check
//--------------------------------------------------------
if (valid_count > 0) begin
$display("==================================");
$display("TEST PASSED");
$display("valid_count = %0d", valid_count);
$display("==================================");
end
$display("[TB] Test 3 complete");
$display("[TB] ALL PASSED");
$display("[TB] Maximum clock deviation of stats %0.2f", CLOCK_DEVIATION);
else begin
$display("==================================");
$display("TEST FAILED");
$display("No valid output detected");
$display("==================================");
end
$finish;
end
@@ -1,189 +0,0 @@
// 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
@@ -1,60 +0,0 @@
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
@@ -1,193 +0,0 @@
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
@@ -1,231 +0,0 @@
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
@@ -1,48 +0,0 @@
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
@@ -1,61 +0,0 @@
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
@@ -1,199 +0,0 @@
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
@@ -1,568 +0,0 @@
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("========================================")
@@ -1,13 +0,0 @@
# 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]
@@ -1,298 +0,0 @@
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
@@ -1,194 +0,0 @@
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
@@ -1,13 +0,0 @@
# 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]
@@ -1,199 +0,0 @@
// 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
@@ -1,67 +0,0 @@
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
@@ -1,101 +0,0 @@
// 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
@@ -1,87 +0,0 @@
//
// (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 ---------
@@ -1,60 +0,0 @@
# 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
@@ -1,2 +0,0 @@
#--------------------Physical Constraints-----------------
@@ -1,231 +0,0 @@
// 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
@@ -1,58 +0,0 @@
# 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]
@@ -1,290 +0,0 @@
// 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
@@ -1,215 +0,0 @@
-- 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;
@@ -1,26 +0,0 @@
// 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
@@ -1,34 +0,0 @@
-- 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;
@@ -1,260 +0,0 @@
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.
@@ -1,671 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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
@@ -1,531 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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
@@ -1,671 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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
@@ -1,530 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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
@@ -1,861 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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
@@ -1,536 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
//
// 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
@@ -1,177 +0,0 @@
`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
@@ -1,245 +0,0 @@
`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
@@ -1,67 +0,0 @@
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
@@ -1,59 +0,0 @@
// 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
@@ -1,58 +0,0 @@
// 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,191 +0,0 @@
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)
@@ -1,175 +0,0 @@
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("========================================")
@@ -1,253 +0,0 @@
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
@@ -1,54 +0,0 @@
# 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
@@ -1,40 +0,0 @@
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
@@ -1,861 +0,0 @@
`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
@@ -1,322 +0,0 @@
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
@@ -1,261 +0,0 @@
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
@@ -1,55 +0,0 @@
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
@@ -1,67 +0,0 @@
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
@@ -1,142 +0,0 @@
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
@@ -1,204 +0,0 @@
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
@@ -1,546 +0,0 @@
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("========================================")
@@ -1,7 +0,0 @@
# 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
@@ -1,231 +0,0 @@
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
@@ -1,59 +0,0 @@
// 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
@@ -1,58 +0,0 @@
// 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,9 +0,0 @@
# 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
@@ -1,130 +0,0 @@
`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`
@@ -1,373 +0,0 @@
`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
@@ -1,117 +0,0 @@
<?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>
@@ -1,46 +0,0 @@
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
@@ -1,199 +0,0 @@
// 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
@@ -1,67 +0,0 @@
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
@@ -1,175 +0,0 @@
`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
@@ -1,213 +0,0 @@
`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
@@ -1,138 +0,0 @@
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
@@ -1,65 +0,0 @@
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
@@ -1,59 +0,0 @@
// 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
@@ -1,58 +0,0 @@
// 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,185 +0,0 @@
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)
@@ -1,174 +0,0 @@
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("========================================")
@@ -1,253 +0,0 @@
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
@@ -1,54 +0,0 @@
# 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
@@ -1,40 +0,0 @@
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
@@ -1,263 +0,0 @@
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
-8
View File
@@ -10,21 +10,13 @@
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'))
-59
View File
@@ -1,59 +0,0 @@
// 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
-58
View File
@@ -1,58 +0,0 @@
// 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 -9
View File
@@ -1,9 +1 @@
# 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
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]
-130
View File
@@ -1,130 +0,0 @@
`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
+220 -152
View File
@@ -1,115 +1,128 @@
`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 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 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
)(
input wire clk_in,
input wire rst_n,
output wire locked,
input sys_clk,
input rst_n,
// Accumulator AXI-S bus
input wire clk_axis_accumulator, // GMII PHY RX clock
axis_if.master axis_accumulator,
output [3:0] led,
// 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
input gmii_rx_clk,
input gmii_tx_clk,
// Status signals
output wire workflow_done,
output wire processing_done,
(* 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,
// RTL-MAC handshake
input wire request_ready,
output wire send_request,
(* 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,
// DAC
output wire dac_clk_o,
output wire [DAC_DATA_WIDTH-1:0] dac_data,
output wire dac_wrt,
output wire p2_clk,
(* MARK_DEBUG="true" *) output wire [DAC_DATA_WIDTH-1:0] p2_data,
(* MARK_DEBUG="true" *) output wire p2_wrt,
// ADC
output wire adc_clk_o,
input wire [ADC_DATA_WIDTH-1:0] adc_data,
input wire adc_otr
output ch2_clk,
(* MARK_DEBUG="true" *) input [ADC_DATA_WIDTH-1:0] ch2_data,
input ch2_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
// IDELAYCTRL
// -------------------------------------------------------------------------
wire clk_sampler, clk_generator, clk_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)
(* IODELAY_GROUP = "rgmii_idelay_group" *)
IDELAYCTRL IDELAYCTRL_inst (
.RDY (),
.REFCLK (sys_clk),
.RST (1'b0)
);
assign locked = clk_locked;
// -------------------------------------------------------------------------
// Generated clocks for controller
// Need to create this IP in Vivado:
// input : 200 MHz
// output0: 130 MHz
// output1: 65 MHz
// -------------------------------------------------------------------------
wire dac_clk;
wire adc_clk;
wire clk_wiz_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)
);
// -------------------------------------------------------------------------
// axis_mac interface
// RX stream from Ethernet goes into controller
// TX stream is unused for now
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
// Controller reset
// Use both external reset and clk_wiz lock
// -------------------------------------------------------------------------
wire ctrl_rst_n = rst_n & clk_locked;
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;
// -------------------------------------------------------------------------
// 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 (clk_axis_control),
.dac_clk_in (clk_generator),
.adc_clk_in (clk_sampler),
.eth_clk_in (gmii_rx_clk),
.dac_clk_in (dac_clk),
.adc_clk_in (adc_clk),
.rst_n (ctrl_rst_n),
.s_axis_tdata (axis_control.tdata),
.s_axis_tvalid (axis_control.tvalid),
.s_axis_tready (axis_control.tready),
.s_axis_tlast (axis_control.tlast),
.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),
.finish (finish),
@@ -128,125 +141,180 @@ 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
//------------------------------------------------------------
(* 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;
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
else begin
stretch[0] <= generator_done;
stretch[1] <= stretch[0];
stretch[2] <= stretch[1];
sample_req_sync2 <= sample_req_sync1;
sample_req_sync3 <= sample_req_sync2;
sample_req <= sample_req_sync3;
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;
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
else begin
sync_AD[0] <= sampler_done;
sync_AD[1] <= sync_AD[0];
sample_done_sync2 <= sample_done_sync1;
sample_done_sync3 <= sample_done_sync2;
sample_done <= sample_done_sync3;
end
end
assign generator_request = sync_AD[1];
//------------------------------------------------------------
// Generator
//------------------------------------------------------------
// Generator (DAC)
//------------------------------------------------------------
generator #(
.DATA_WIDTH(DAC_DATA_WIDTH),
.ZERO_LEVEL(ZERO_LEVEL)
) generator_inst (
.clk_dac(clk_generator),
.clk_in(dac_clk),
.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)
.pulse(p2_wrt),
.pulse_height_out(p2_data),
.sample_done(sample_done),
.sample_req(sample_req_sync1)
);
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;
wire ch2_clk_oddr;
sampler #(
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
// -------------------------------------------------------------------------
(* MARK_DEBUG="true" *) logic [ADC_DATA_WIDTH*PACK_FACTOR-1:0] accum_m_axis_tdata;
(* MARK_DEBUG="true" *) logic acum_m_axis_tvalid;
sampler
#(
.DATA_WIDTH(ADC_DATA_WIDTH),
.PACK_FACTOR(PACK_FACTOR),
.PROCESS_MODE(PROCESS_MODE)
) 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),
)
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),
.smp_num(adc_pulse_period),
.done(sampler_done),
.request(sampler_request)
.sample_req(sample_req),
.sample_done(sample_done_sync1)
);
// -------------------------------------------------------------------------
// Accumulator
// -------------------------------------------------------------------------
assign workflow_done = finish;
accumulator_top #(
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(clk_sampler),
)
accumulator_top_dut
(
.clk_in(adc_clk),
.rst(adc_rst),
.s_axis_tdata(sampler_m_axis_tdata),
.s_axis_tvalid(sampler_m_axis_tvalid),
.s_axis_tdata(accum_m_axis_tdata),
.s_axis_tvalid(acum_m_axis_tvalid),
.start(adc_start),
.smp_num(adc_pulse_period),
.seq_num(adc_pulse_num),
.window_size(window_size),
.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),
.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),
.finish(finish), // full reflectometer workflow complete (with transaction)
.accum_done(processing_done) // signal generation, sampling and processing complete
.finish(finish)
);
endmodule
// -------------------------------------------------------------------------
// Simple LED status
// -------------------------------------------------------------------------
assign led[0] = clk_wiz_locked;
assign led[1] = m_axis_rx_tvalid;
assign led[2] = dac_start;
endmodule
@@ -1,373 +0,0 @@
`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
@@ -1,117 +0,0 @@
<?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>
-4
View File
@@ -1,4 +0,0 @@
**sim_build**
**pycache**
dump.vcd
results.xml
-3
View File
@@ -1,3 +0,0 @@
[submodule "external/verilog-axi"]
path = external/verilog-axi
url = https://github.com/alexforencich/verilog-axi
-3
View File
@@ -1,3 +0,0 @@
# RTL Libs
## AXI Defines
-213
View File
@@ -1,213 +0,0 @@
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
@@ -1,67 +0,0 @@
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
@@ -1,68 +0,0 @@
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
@@ -1,64 +0,0 @@
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
-97
View File
@@ -1,97 +0,0 @@
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
-97
View File
@@ -1,97 +0,0 @@
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
-58
View File
@@ -1,58 +0,0 @@
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
-56
View File
@@ -1,56 +0,0 @@
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
View File
@@ -1,189 +0,0 @@
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
-59
View File
@@ -1,59 +0,0 @@
module axi4l_to_axi4 #(
parameter int unsigned ADDR_W = 32,
parameter int unsigned DATA_W = 32,
parameter int unsigned ID_W = 4,
parameter int unsigned USER_W = 1,
parameter logic [ID_W-1:0] AXI_ID_CONST = '0,
parameter logic [3:0] AXI_CACHE_CONST = 4'b0000,
parameter logic [3:0] AXI_QOS_CONST = 4'b0000,
parameter logic [3:0] AXI_REGION_CONST = 4'b0000
)(
axi4l_if.slave s_axil,
axi4_if.master m_axi
);
assign m_axi.req.aw.id = AXI_ID_CONST;
assign m_axi.req.aw.addr = s_axil.req.aw.addr;
assign m_axi.req.aw.len = 8'd0;
assign m_axi.req.aw.size = axi_pkg::axi_size_from_bytes(DATA_W/8);
assign m_axi.req.aw.burst = axi_pkg::AXI_BURST_INCR;
assign m_axi.req.aw.lock = 1'b0;
assign m_axi.req.aw.cache = AXI_CACHE_CONST;
assign m_axi.req.aw.prot = s_axil.req.aw.prot;
assign m_axi.req.aw.qos = AXI_QOS_CONST;
assign m_axi.req.aw.region = AXI_REGION_CONST;
assign m_axi.req.aw.user = s_axil.req.aw.user;
assign m_axi.req.aw.valid = s_axil.req.aw.valid;
assign s_axil.resp.aw_ready = m_axi.resp.aw_ready;
assign m_axi.req.w.data = s_axil.req.w.data;
assign m_axi.req.w.strb = s_axil.req.w.strb;
assign m_axi.req.w.last = 1'b1;
assign m_axi.req.w.user = s_axil.req.w.user;
assign m_axi.req.w.valid = s_axil.req.w.valid;
assign s_axil.resp.w_ready = m_axi.resp.w_ready;
assign s_axil.resp.b.resp = m_axi.resp.b.resp;
assign s_axil.resp.b.user = m_axi.resp.b.user;
assign s_axil.resp.b.valid = m_axi.resp.b.valid;
assign m_axi.req.b_ready = s_axil.req.b_ready;
assign m_axi.req.ar.id = AXI_ID_CONST;
assign m_axi.req.ar.addr = s_axil.req.ar.addr;
assign m_axi.req.ar.len = 8'd0;
assign m_axi.req.ar.size = axi_pkg::axi_size_from_bytes(DATA_W/8);
assign m_axi.req.ar.burst = axi_pkg::AXI_BURST_INCR;
assign m_axi.req.ar.lock = 1'b0;
assign m_axi.req.ar.cache = AXI_CACHE_CONST;
assign m_axi.req.ar.prot = s_axil.req.ar.prot;
assign m_axi.req.ar.qos = AXI_QOS_CONST;
assign m_axi.req.ar.region = AXI_REGION_CONST;
assign m_axi.req.ar.user = s_axil.req.ar.user;
assign m_axi.req.ar.valid = s_axil.req.ar.valid;
assign s_axil.resp.ar_ready = m_axi.resp.ar_ready;
assign s_axil.resp.r.data = m_axi.resp.r.data;
assign s_axil.resp.r.resp = m_axi.resp.r.resp;
assign s_axil.resp.r.user = m_axi.resp.r.user;
assign s_axil.resp.r.valid = m_axi.resp.r.valid;
assign m_axi.req.r_ready = s_axil.req.r_ready;
endmodule

Some files were not shown because too many files have changed in this diff Show More