transferring new controller design
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
module axi4l_reg_map_controller #(
|
||||
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,
|
||||
// dac adc registers
|
||||
output logic start_o,
|
||||
output logic cfg_bus_valid_o,
|
||||
output logic [31:0] pulse_width_o,
|
||||
output logic [31:0] pulse_period_o,
|
||||
output logic [31:0] pulse_num_o,
|
||||
output logic [31:0] pulse_height_raw_o,
|
||||
output logic [31:0] pulse_period_ADC_o,
|
||||
output logic [31:0] window_size_o,
|
||||
|
||||
// DMA CONTROL SIGNALS
|
||||
output logic send_desc_read_o,
|
||||
output logic send_desc_write_o,
|
||||
output logic take_status_read_o,
|
||||
output logic take_status_write_o,
|
||||
|
||||
input logic desc_read_dma_busy_i,
|
||||
input logic desc_write_dma_busy_i,
|
||||
input logic status_read_dma_busy_i,
|
||||
input logic status_write_dma_busy_i,
|
||||
|
||||
input logic desc_read_dma_hs_i,
|
||||
input logic desc_write_dma_hs_i,
|
||||
input logic status_read_dma_hs_i,
|
||||
input logic status_write_dma_hs_i,
|
||||
|
||||
// DMA read descriptors and status register
|
||||
|
||||
output logic [31:0] desc_read_addr_o,
|
||||
output logic [31:0] desc_read_len_o,
|
||||
output logic [31:0] desc_read_config_o,
|
||||
|
||||
input logic [31:0] status_read_i,
|
||||
|
||||
// DMA write descriptors and status register
|
||||
output logic [31:0] desc_write_addr_o,
|
||||
output logic [31:0] desc_write_len_and_tag_o,
|
||||
|
||||
input logic [31:0] status_write_len_i,
|
||||
input logic [31:0] status_write_config_i,
|
||||
|
||||
output logic rst_soft_o,
|
||||
input logic busy_i,
|
||||
input logic [7:0] error_code_i
|
||||
);
|
||||
import axi4l_reg_map_controller_pkg::*;
|
||||
localparam int unsigned N_REGS = CTRL_REG_MAP_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 (CTRL_REG_MAP_REG_MODE),
|
||||
.REG_RST (CTRL_REG_MAP_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_i[REG_STATUS][0] = busy_i;
|
||||
|
||||
reg_i[REG_STATUS][1] = desc_read_dma_busy_i;
|
||||
reg_i[REG_STATUS][2] = desc_write_dma_busy_i;
|
||||
reg_i[REG_STATUS][3] = status_read_dma_busy_i;
|
||||
reg_i[REG_STATUS][4] = status_write_dma_busy_i;
|
||||
|
||||
reg_i[REG_STATUS][5] = desc_read_dma_hs_i;
|
||||
reg_i[REG_STATUS][6] = desc_write_dma_hs_i;
|
||||
reg_i[REG_STATUS][7] = status_read_dma_hs_i;
|
||||
reg_i[REG_STATUS][8] = status_write_dma_hs_i;
|
||||
|
||||
reg_i[REG_ERROR][7:0] = error_code_i;
|
||||
|
||||
reg_i[REG_READ_STATUS] = status_read_i;
|
||||
reg_i[REG_STATUS_WRITE_LEN] = status_write_len_i;
|
||||
reg_i[REG_STATUS_WRITE_CONFIG] = status_write_config_i;
|
||||
|
||||
end
|
||||
|
||||
assign start_o = reg_pulse[REG_CONTROL][0];
|
||||
assign rst_soft_o = reg_pulse[REG_CONTROL][1];
|
||||
assign cfg_bus_valid_o = reg_pulse[REG_CONTROL][2];
|
||||
|
||||
assign send_desc_read_o = reg_pulse[REG_CONTROL][3];
|
||||
assign send_desc_write_o = reg_pulse[REG_CONTROL][4];
|
||||
assign take_status_read_o = reg_pulse[REG_CONTROL][5];
|
||||
assign take_status_write_o = reg_pulse[REG_CONTROL][6];
|
||||
|
||||
assign pulse_width_o = reg_o[REG_DAC_WIDTH];
|
||||
assign pulse_period_o = reg_o[REG_DAC_PERIOD];
|
||||
assign pulse_num_o = reg_o[REG_DAC_PULSE_NUM];
|
||||
assign pulse_height_raw_o = reg_o[REG_DAC_PULSE_HEIGHT];
|
||||
assign pulse_period_ADC_o = reg_o[REG_ADC_PERIOD];
|
||||
assign window_size_o = reg_o[REG_WINDOW_SIZE];
|
||||
|
||||
assign desc_read_addr_o = reg_o[REG_DESC_READ_ADDR];
|
||||
assign desc_read_len_o = reg_o[REG_DESC_READ_LEN];
|
||||
assign desc_read_config_o = reg_o[REG_DESC_READ_CONFIG];
|
||||
assign desc_write_addr_o = reg_o[REG_DESC_WRITE_ADDR];
|
||||
assign desc_write_len_and_tag_o = reg_o[REG_DESC_WRITE_LEN_AND_TAG];
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,109 @@
|
||||
package axi4l_reg_map_controller_pkg;
|
||||
|
||||
localparam int unsigned CTRL_REG_MAP_N_REGS = 17;
|
||||
|
||||
/*
|
||||
dac adc configuration registers
|
||||
*/
|
||||
localparam logic [31:0] REG_CONTROL = 32'd0;
|
||||
localparam logic [31:0] REG_STATUS = 32'd1;
|
||||
localparam logic [31:0] REG_DAC_WIDTH = 32'd2;
|
||||
localparam logic [31:0] REG_DAC_PERIOD = 32'd3;
|
||||
localparam logic [31:0] REG_DAC_PULSE_NUM = 32'd4;
|
||||
localparam logic [31:0] REG_DAC_PULSE_HEIGHT = 32'd5;
|
||||
localparam logic [31:0] REG_ADC_PERIOD = 32'd6;
|
||||
localparam logic [31:0] REG_WINDOW_SIZE = 32'd7;
|
||||
localparam logic [31:0] REG_ERROR = 32'd8;
|
||||
|
||||
/*
|
||||
AXI read descriptor input and AXI read descriptor status output configuration registers
|
||||
*/
|
||||
localparam logic [31:0] REG_DESC_READ_ADDR = 32'd9;
|
||||
localparam logic [31:0] REG_DESC_READ_LEN = 32'd10;
|
||||
localparam logic [31:0] REG_DESC_READ_CONFIG = 32'd11;
|
||||
|
||||
localparam logic [31:0] REG_READ_STATUS = 32'd12;
|
||||
|
||||
/*
|
||||
AXI write descriptor input and AXI write descriptor status output configuration registers
|
||||
*/
|
||||
localparam logic [31:0] REG_DESC_WRITE_ADDR = 32'd13;
|
||||
localparam logic [31:0] REG_DESC_WRITE_LEN_AND_TAG = 32'd14;
|
||||
|
||||
localparam logic [31:0] REG_STATUS_WRITE_LEN = 32'd15;
|
||||
localparam logic [31:0] REG_STATUS_WRITE_CONFIG = 32'd16;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
localparam logic [CTRL_REG_MAP_N_REGS-1:0][31:0][2:0] CTRL_REG_MAP_REG_MODE = '{
|
||||
default: '{default: REG_BIT_RSVD},
|
||||
|
||||
REG_CONTROL: '{
|
||||
0 : REG_BIT_W1S,
|
||||
1 : REG_BIT_W1S,
|
||||
2 : REG_BIT_W1S,
|
||||
3 : REG_BIT_W1S,
|
||||
4 : REG_BIT_W1S,
|
||||
5 : REG_BIT_W1S,
|
||||
6 : REG_BIT_W1S,
|
||||
default: REG_BIT_RSVD
|
||||
},
|
||||
|
||||
REG_STATUS: '{
|
||||
0 : REG_BIT_RO,
|
||||
1 : REG_BIT_RO,
|
||||
2 : REG_BIT_RO,
|
||||
3 : REG_BIT_RO,
|
||||
4 : REG_BIT_RO,
|
||||
5 : REG_BIT_RO,
|
||||
6 : REG_BIT_RO,
|
||||
7 : REG_BIT_RO,
|
||||
8 : REG_BIT_RO,
|
||||
default: REG_BIT_RSVD
|
||||
},
|
||||
|
||||
REG_DAC_WIDTH: '{default: REG_BIT_RW},
|
||||
REG_DAC_PERIOD: '{default: REG_BIT_RW},
|
||||
REG_DAC_PULSE_NUM: '{default: REG_BIT_RW},
|
||||
REG_DAC_PULSE_HEIGHT: '{default: REG_BIT_RW},
|
||||
REG_ADC_PERIOD: '{default: REG_BIT_RW},
|
||||
REG_WINDOW_SIZE: '{default: REG_BIT_RW},
|
||||
|
||||
REG_ERROR: '{default: REG_BIT_RO},
|
||||
|
||||
REG_DESC_READ_ADDR: '{default: REG_BIT_RW},
|
||||
REG_DESC_READ_LEN: '{default: REG_BIT_RW},
|
||||
REG_DESC_READ_CONFIG: '{default: REG_BIT_RW},
|
||||
REG_READ_STATUS: '{default: REG_BIT_RO},
|
||||
|
||||
REG_DESC_WRITE_ADDR: '{default: REG_BIT_RW},
|
||||
REG_DESC_WRITE_LEN_AND_TAG: '{default: REG_BIT_RW},
|
||||
REG_STATUS_WRITE_LEN: '{default: REG_BIT_RO},
|
||||
REG_STATUS_WRITE_CONFIG: '{default: REG_BIT_RO}
|
||||
};
|
||||
|
||||
localparam logic [CTRL_REG_MAP_N_REGS-1:0][31:0] CTRL_REG_MAP_REG_RST = '{
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000,
|
||||
32'h0000_0000
|
||||
};
|
||||
|
||||
endpackage
|
||||
@@ -0,0 +1,13 @@
|
||||
module axis_defaults_master
|
||||
(
|
||||
axis_if.master axis
|
||||
);
|
||||
|
||||
assign axis.req.t.keep = '1;
|
||||
assign axis.req.t.strb = '1;
|
||||
assign axis.req.t.last = 1'b1;
|
||||
assign axis.req.t.id = '0;
|
||||
assign axis.req.t.dest = '0;
|
||||
assign axis.req.t.user = '0;
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,338 @@
|
||||
module control #(
|
||||
parameter int unsigned DAC_DATA_WIDTH = 12
|
||||
) (
|
||||
input logic ctrl_clk,
|
||||
input logic dac_clk_in,
|
||||
input logic adc_clk_in,
|
||||
|
||||
input logic rst_n,
|
||||
input logic rst_soft,
|
||||
|
||||
// adc_clk_in domain
|
||||
input logic finish,
|
||||
input logic [159:0] cfg_bus_input,
|
||||
input logic cfg_bus_valid,
|
||||
input logic start,
|
||||
|
||||
// status signals
|
||||
output logic busy,
|
||||
|
||||
// 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,
|
||||
output logic [31:0] adc_window_size,
|
||||
|
||||
// pulse outputs
|
||||
output logic dac_start,
|
||||
output logic adc_start,
|
||||
output logic dac_rst,
|
||||
output logic adc_rst
|
||||
);
|
||||
|
||||
// static checks
|
||||
initial begin
|
||||
if (DAC_DATA_WIDTH > 16) begin
|
||||
$error("DAC_DATA_WIDTH must be <= 16");
|
||||
end
|
||||
if (DAC_DATA_WIDTH == 0) begin
|
||||
$error("DAC_DATA_WIDTH must be > 0");
|
||||
end
|
||||
end
|
||||
|
||||
// reset synchronizers: async assert, sync deassert in each domain
|
||||
logic rst_ff1, rst_ff2;
|
||||
logic dac_rst_ff1, dac_rst_ff2;
|
||||
logic adc_rst_ff1, adc_rst_ff2;
|
||||
|
||||
logic ctrl_rst;
|
||||
logic dac_rst_int;
|
||||
logic adc_rst_int;
|
||||
|
||||
always_ff @(posedge ctrl_clk or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
rst_ff1 <= 1'b1;
|
||||
rst_ff2 <= 1'b1;
|
||||
end else begin
|
||||
rst_ff1 <= 1'b0;
|
||||
rst_ff2 <= rst_ff1;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge dac_clk_in or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
dac_rst_ff1 <= 1'b1;
|
||||
dac_rst_ff2 <= 1'b1;
|
||||
end else begin
|
||||
dac_rst_ff1 <= 1'b0;
|
||||
dac_rst_ff2 <= dac_rst_ff1;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge adc_clk_in or negedge rst_n) begin
|
||||
if (!rst_n) begin
|
||||
adc_rst_ff1 <= 1'b1;
|
||||
adc_rst_ff2 <= 1'b1;
|
||||
end else begin
|
||||
adc_rst_ff1 <= 1'b0;
|
||||
adc_rst_ff2 <= adc_rst_ff1;
|
||||
end
|
||||
end
|
||||
|
||||
assign ctrl_rst = rst_ff2;
|
||||
assign dac_rst_int = dac_rst_ff2;
|
||||
assign adc_rst_int = adc_rst_ff2;
|
||||
|
||||
// Pending ACKs for config delivery
|
||||
logic cfg_wait_dac_ack;
|
||||
logic cfg_wait_adc_ack;
|
||||
|
||||
// Event toggles cntrl -> DAC/ADC
|
||||
logic start_toggle;
|
||||
logic rst_toggle;
|
||||
|
||||
// Config request toggles cntrl -> DAC/ADC
|
||||
logic cfg_req_toggle_dac;
|
||||
logic cfg_req_toggle_adc;
|
||||
|
||||
// ACK toggles DAC/ADC -> cntrl
|
||||
logic cfg_ack_toggle_dac;
|
||||
logic cfg_ack_toggle_adc;
|
||||
|
||||
(* ASYNC_REG = "TRUE" *) logic cfg_ack_toggle_dac_meta, cfg_ack_toggle_dac_sync, cfg_ack_toggle_dac_sync_d;
|
||||
(* ASYNC_REG = "TRUE" *) logic cfg_ack_toggle_adc_meta, cfg_ack_toggle_adc_sync, cfg_ack_toggle_adc_sync_d;
|
||||
|
||||
wire cfg_ack_pulse_dac = cfg_ack_toggle_dac_sync ^ cfg_ack_toggle_dac_sync_d;
|
||||
wire cfg_ack_pulse_adc = cfg_ack_toggle_adc_sync ^ cfg_ack_toggle_adc_sync_d;
|
||||
|
||||
always_ff @(posedge ctrl_clk or posedge ctrl_rst) begin
|
||||
if (ctrl_rst) begin
|
||||
cfg_ack_toggle_dac_meta <= 1'b0;
|
||||
cfg_ack_toggle_dac_sync <= 1'b0;
|
||||
cfg_ack_toggle_dac_sync_d <= 1'b0;
|
||||
|
||||
cfg_ack_toggle_adc_meta <= 1'b0;
|
||||
cfg_ack_toggle_adc_sync <= 1'b0;
|
||||
cfg_ack_toggle_adc_sync_d <= 1'b0;
|
||||
end else begin
|
||||
cfg_ack_toggle_dac_meta <= cfg_ack_toggle_dac;
|
||||
cfg_ack_toggle_dac_sync <= cfg_ack_toggle_dac_meta;
|
||||
cfg_ack_toggle_dac_sync_d <= cfg_ack_toggle_dac_sync;
|
||||
|
||||
cfg_ack_toggle_adc_meta <= cfg_ack_toggle_adc;
|
||||
cfg_ack_toggle_adc_sync <= cfg_ack_toggle_adc_meta;
|
||||
cfg_ack_toggle_adc_sync_d <= cfg_ack_toggle_adc_sync;
|
||||
end
|
||||
end
|
||||
|
||||
// finish event: ADC -> cntrl via toggle CDC
|
||||
logic finish_toggle_adc;
|
||||
logic finish_meta, finish_sync, finish_sync_d;
|
||||
|
||||
wire finish_pulse = finish_sync ^ finish_sync_d;
|
||||
|
||||
always_ff @(posedge adc_clk_in or posedge adc_rst_int) begin
|
||||
if (adc_rst_int) begin
|
||||
finish_toggle_adc <= 1'b0;
|
||||
end else if (finish) begin
|
||||
finish_toggle_adc <= ~finish_toggle_adc;
|
||||
end
|
||||
end
|
||||
|
||||
always_ff @(posedge ctrl_clk or posedge ctrl_rst) begin
|
||||
if (ctrl_rst) begin
|
||||
finish_meta <= 1'b0;
|
||||
finish_sync <= 1'b0;
|
||||
finish_sync_d <= 1'b0;
|
||||
end else begin
|
||||
finish_meta <= finish_toggle_adc;
|
||||
finish_sync <= finish_meta;
|
||||
finish_sync_d <= finish_sync;
|
||||
end
|
||||
end
|
||||
|
||||
logic [159:0] cfg_bus;
|
||||
|
||||
always_ff @(posedge ctrl_clk or posedge ctrl_rst) begin
|
||||
if (ctrl_rst) begin
|
||||
cfg_bus <= '0;
|
||||
busy <= 0;
|
||||
|
||||
start_toggle <= 0;
|
||||
rst_toggle <= 0;
|
||||
|
||||
cfg_req_toggle_dac <= 0;
|
||||
cfg_req_toggle_adc <= 0;
|
||||
|
||||
cfg_wait_dac_ack <= 0;
|
||||
cfg_wait_adc_ack <= 0;
|
||||
end else begin
|
||||
if (finish_pulse) begin
|
||||
busy <= 0;
|
||||
end
|
||||
if (cfg_ack_pulse_dac) begin
|
||||
cfg_wait_dac_ack <= 1'b0;
|
||||
end
|
||||
if (cfg_ack_pulse_adc) begin
|
||||
cfg_wait_adc_ack <= 1'b0;
|
||||
end
|
||||
|
||||
if (cfg_bus_valid && !busy && !cfg_wait_dac_ack && !cfg_wait_adc_ack) begin
|
||||
cfg_bus <= cfg_bus_input;
|
||||
|
||||
cfg_req_toggle_dac <= ~cfg_req_toggle_dac;
|
||||
cfg_req_toggle_adc <= ~cfg_req_toggle_adc;
|
||||
|
||||
cfg_wait_dac_ack <= 1;
|
||||
cfg_wait_adc_ack <= 1;
|
||||
end
|
||||
|
||||
if (start && !busy && !cfg_wait_dac_ack && !cfg_wait_adc_ack) begin
|
||||
start_toggle <= ~start_toggle;
|
||||
busy <= 1;
|
||||
end
|
||||
if (rst_soft) begin
|
||||
rst_toggle <= ~rst_toggle;
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
// cntrl -> DAC: start/reset event sync
|
||||
(* ASYNC_REG = "TRUE" *) logic start_meta_dac, start_sync_dac;
|
||||
logic start_sync_dac_d;
|
||||
(* ASYNC_REG = "TRUE" *) logic rst_meta_dac, rst_sync_dac;
|
||||
logic rst_sync_dac_d;
|
||||
|
||||
wire dac_start_pulse = start_sync_dac ^ start_sync_dac_d;
|
||||
wire dac_rst_pulse = rst_sync_dac ^ rst_sync_dac_d;
|
||||
|
||||
always_ff @(posedge dac_clk_in or posedge dac_rst_int) begin
|
||||
if (dac_rst_int) begin
|
||||
start_meta_dac <= 1'b0;
|
||||
start_sync_dac <= 1'b0;
|
||||
start_sync_dac_d <= 1'b0;
|
||||
|
||||
rst_meta_dac <= 1'b0;
|
||||
rst_sync_dac <= 1'b0;
|
||||
rst_sync_dac_d <= 1'b0;
|
||||
|
||||
dac_start <= 1'b0;
|
||||
dac_rst <= 1'b0;
|
||||
end else begin
|
||||
start_meta_dac <= start_toggle;
|
||||
start_sync_dac <= start_meta_dac;
|
||||
start_sync_dac_d <= start_sync_dac;
|
||||
|
||||
rst_meta_dac <= rst_toggle;
|
||||
rst_sync_dac <= rst_meta_dac;
|
||||
rst_sync_dac_d <= rst_sync_dac;
|
||||
|
||||
dac_start <= dac_start_pulse;
|
||||
dac_rst <= dac_rst_pulse;
|
||||
end
|
||||
end
|
||||
|
||||
// cntrl -> ADC: start/reset event sync
|
||||
(* ASYNC_REG = "TRUE" *) logic start_meta_adc, start_sync_adc;
|
||||
logic start_sync_adc_d;
|
||||
(* ASYNC_REG = "TRUE" *) logic rst_meta_adc, rst_sync_adc;
|
||||
logic rst_sync_adc_d;
|
||||
|
||||
wire adc_start_pulse = start_sync_adc ^ start_sync_adc_d;
|
||||
wire adc_rst_pulse = rst_sync_adc ^ rst_sync_adc_d;
|
||||
|
||||
always_ff @(posedge adc_clk_in or posedge adc_rst_int) begin
|
||||
if (adc_rst_int) begin
|
||||
start_meta_adc <= 1'b0;
|
||||
start_sync_adc <= 1'b0;
|
||||
start_sync_adc_d <= 1'b0;
|
||||
|
||||
rst_meta_adc <= 1'b0;
|
||||
rst_sync_adc <= 1'b0;
|
||||
rst_sync_adc_d <= 1'b0;
|
||||
|
||||
adc_start <= 1'b0;
|
||||
adc_rst <= 1'b0;
|
||||
end else begin
|
||||
start_meta_adc <= start_toggle;
|
||||
start_sync_adc <= start_meta_adc;
|
||||
start_sync_adc_d <= start_sync_adc;
|
||||
|
||||
rst_meta_adc <= rst_toggle;
|
||||
rst_sync_adc <= rst_meta_adc;
|
||||
rst_sync_adc_d <= rst_sync_adc;
|
||||
|
||||
adc_start <= adc_start_pulse;
|
||||
adc_rst <= adc_rst_pulse;
|
||||
end
|
||||
end
|
||||
|
||||
// contrl -> DAC config CDC
|
||||
// cfg_bus is kept stable in contrl domain until DAC and ADC both ACK.
|
||||
(* ASYNC_REG = "TRUE" *) logic cfg_req_meta_dac, cfg_req_sync_dac;
|
||||
logic cfg_req_sync_dac_d;
|
||||
wire cfg_req_pulse_dac = cfg_req_sync_dac ^ cfg_req_sync_dac_d;
|
||||
|
||||
always_ff @(posedge dac_clk_in or posedge dac_rst_int) begin
|
||||
if (dac_rst_int) begin
|
||||
cfg_req_meta_dac <= 1'b0;
|
||||
cfg_req_sync_dac <= 1'b0;
|
||||
cfg_req_sync_dac_d<= 1'b0;
|
||||
cfg_ack_toggle_dac<= 1'b0;
|
||||
|
||||
dac_pulse_width <= '0;
|
||||
dac_pulse_period <= '0;
|
||||
dac_pulse_num <= '0;
|
||||
dac_pulse_height <= '0;
|
||||
end else begin
|
||||
cfg_req_meta_dac <= cfg_req_toggle_dac;
|
||||
cfg_req_sync_dac <= cfg_req_meta_dac;
|
||||
cfg_req_sync_dac_d <= cfg_req_sync_dac;
|
||||
|
||||
if (cfg_req_pulse_dac) begin
|
||||
dac_pulse_width <= cfg_bus[31:0];
|
||||
dac_pulse_period <= cfg_bus[63:32];
|
||||
dac_pulse_num <= cfg_bus[79:64];
|
||||
dac_pulse_height <= cfg_bus[80 +: DAC_DATA_WIDTH];
|
||||
|
||||
cfg_ack_toggle_dac <= ~cfg_ack_toggle_dac;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// cntrl -> ADC config CDC
|
||||
logic cfg_req_meta_adc, cfg_req_sync_adc, cfg_req_sync_adc_d;
|
||||
wire cfg_req_pulse_adc = cfg_req_sync_adc ^ cfg_req_sync_adc_d;
|
||||
|
||||
always_ff @(posedge adc_clk_in or posedge adc_rst_int) begin
|
||||
if (adc_rst_int) begin
|
||||
cfg_req_meta_adc <= 1'b0;
|
||||
cfg_req_sync_adc <= 1'b0;
|
||||
cfg_req_sync_adc_d <= 1'b0;
|
||||
cfg_ack_toggle_adc <= 1'b0;
|
||||
|
||||
adc_pulse_period <= '0;
|
||||
adc_pulse_num <= '0;
|
||||
adc_window_size <= '0;
|
||||
end else begin
|
||||
cfg_req_meta_adc <= cfg_req_toggle_adc;
|
||||
cfg_req_sync_adc <= cfg_req_meta_adc;
|
||||
cfg_req_sync_adc_d <= cfg_req_sync_adc;
|
||||
|
||||
if (cfg_req_pulse_adc) begin
|
||||
adc_pulse_period <= cfg_bus[127:96];
|
||||
adc_pulse_num <= cfg_bus[79:64];
|
||||
adc_window_size <= cfg_bus[159:128];
|
||||
|
||||
cfg_ack_toggle_adc <= ~cfg_ack_toggle_adc;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,221 @@
|
||||
import dma_reg_pkg::*;
|
||||
|
||||
module 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
|
||||
)
|
||||
(
|
||||
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 DMA
|
||||
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
|
||||
);
|
||||
|
||||
logic start, rst_soft, send_desc_read, send_desc_write, take_status_read, take_status_write, cfg_bus_valid, busy;
|
||||
logic [31:0] pulse_width, pulse_period, pulse_num, pulse_height_raw, pulse_period_ADC, window_size;
|
||||
logic [7:0] error_code;
|
||||
logic [31:0] desc_read_addr, desc_read_len, desc_read_config, status_read;
|
||||
logic [31:0] desc_write_addr, desc_write_len_and_tag, status_write_len, status_write_config;
|
||||
|
||||
logic desc_read_dma_busy, desc_write_dma_busy, status_read_dma_busy, status_write_dma_busy;
|
||||
logic desc_read_dma_hs, desc_write_dma_hs, status_read_dma_hs, status_write_dma_hs;
|
||||
|
||||
axi4l_reg_map_controller #(
|
||||
.ADDR_W(ADDR_W),
|
||||
.DATA_W(DATA_W),
|
||||
.USER_W(USER_W)
|
||||
) axi4l_reg_map_controller_inst (
|
||||
.clk(ctrl_clk),
|
||||
.rst_n(rst_n),
|
||||
.s_axil(s_axil),
|
||||
// CONTROLLER ADC/ DAC
|
||||
.start_o(start),
|
||||
.cfg_bus_valid_o(cfg_bus_valid),
|
||||
|
||||
.pulse_width_o(pulse_width),
|
||||
.pulse_period_o(pulse_period),
|
||||
.pulse_num_o(pulse_num),
|
||||
.pulse_height_raw_o(pulse_height_raw),
|
||||
.pulse_period_ADC_o(pulse_period_ADC),
|
||||
.window_size_o(window_size),
|
||||
|
||||
.rst_soft_o(rst_soft),
|
||||
.busy_i(busy),
|
||||
.error_code_i(error_code),
|
||||
|
||||
// CONTROLLER DMA
|
||||
.send_desc_read_o(send_desc_read),
|
||||
.send_desc_write_o(send_desc_write),
|
||||
.take_status_read_o(take_status_read),
|
||||
.take_status_write_o(take_status_write),
|
||||
|
||||
.desc_read_addr_o(desc_read_addr),
|
||||
.desc_read_len_o(desc_read_len),
|
||||
.desc_read_config_o(desc_read_config),
|
||||
|
||||
.status_read_i(status_read),
|
||||
|
||||
.desc_write_addr_o(desc_write_addr),
|
||||
.desc_write_len_and_tag_o(desc_write_len_and_tag),
|
||||
|
||||
.status_write_len_i(status_write_len),
|
||||
.status_write_config_i(status_write_config),
|
||||
|
||||
.desc_read_dma_busy_i(desc_read_dma_busy),
|
||||
.desc_write_dma_busy_i(desc_write_dma_busy),
|
||||
.status_read_dma_busy_i(status_read_dma_busy),
|
||||
.status_write_dma_busy_i(status_write_dma_busy),
|
||||
|
||||
.desc_read_dma_hs_i(desc_read_dma_hs),
|
||||
.desc_write_dma_hs_i(desc_write_dma_hs),
|
||||
.status_read_dma_hs_i(status_read_dma_hs),
|
||||
.status_write_dma_hs_i(status_write_dma_hs)
|
||||
);
|
||||
|
||||
// CONTROLLER DAC ADC
|
||||
// -------------------------------------------------------------------------
|
||||
// Field layout inside cfg_bus:
|
||||
// [31:0] pulse_width
|
||||
// [63:32] pulse_period
|
||||
// [79:64] pulse_num
|
||||
// [95:80] pulse_height_raw[15:0]
|
||||
// [127:96] pulse_period_ADC
|
||||
// [159:128] window_size
|
||||
// -------------------------------------------------------------------------
|
||||
(* MARK_DEBUG="true" *) logic [159:0] cfg_bus;
|
||||
assign cfg_bus = {window_size, pulse_period_ADC, pulse_height_raw[15:0], pulse_num[15:0], pulse_period, pulse_width};
|
||||
|
||||
control #(
|
||||
.DAC_DATA_WIDTH(DAC_DATA_WIDTH)
|
||||
)
|
||||
controller (
|
||||
.ctrl_clk(ctrl_clk),
|
||||
.dac_clk_in(dac_clk_in),
|
||||
.adc_clk_in(adc_clk_in),
|
||||
.rst_n(rst_n),
|
||||
.rst_soft(rst_soft),
|
||||
.finish(finish),
|
||||
.cfg_bus_input(cfg_bus),
|
||||
.cfg_bus_valid(cfg_bus_valid),
|
||||
.start(start),
|
||||
|
||||
.busy(busy),
|
||||
|
||||
.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),
|
||||
.adc_window_size(adc_window_size),
|
||||
.dac_start(dac_start),
|
||||
.adc_start(adc_start),
|
||||
.dac_rst(dac_rst),
|
||||
.adc_rst(adc_rst)
|
||||
);
|
||||
|
||||
// CONTROLLER DMA
|
||||
|
||||
dma_read_desc_t desc_read_cmd, desc_read_cmd_out;
|
||||
assign desc_read_cmd.addr = desc_read_addr;
|
||||
assign desc_read_cmd.len = desc_read_len;
|
||||
assign desc_read_cmd.tag = desc_read_config[TAG_WIDTH-1:0];
|
||||
assign desc_read_cmd.id = desc_read_config[TAG_WIDTH +: AXIS_ID_WIDTH];
|
||||
assign desc_read_cmd.dest = desc_read_config[TAG_WIDTH+AXIS_ID_WIDTH +: AXIS_DEST_WIDTH];
|
||||
assign desc_read_cmd.user = desc_read_config[TAG_WIDTH+AXIS_ID_WIDTH+AXIS_DEST_WIDTH +: AXIS_USER_WIDTH];
|
||||
|
||||
dma_write_desc_t desc_write_cmd, desc_write_cmd_out;
|
||||
assign desc_write_cmd.addr = desc_write_addr;
|
||||
assign desc_write_cmd.len = desc_write_len_and_tag[LEN_WIDTH-1:0];
|
||||
assign desc_write_cmd.tag = desc_write_len_and_tag[LEN_WIDTH +: TAG_WIDTH];
|
||||
|
||||
dma_read_status_t status_read_cmd, status_read_cmd_in;
|
||||
assign status_read = { status_read_cmd.error, status_read_cmd.tag};
|
||||
|
||||
dma_write_status_t status_write_cmd, status_write_cmd_in;
|
||||
assign status_write_len = status_write_cmd.len;
|
||||
assign status_write_config = { status_write_cmd.error, status_write_cmd.user,
|
||||
status_write_cmd.dest, status_write_cmd.id, status_write_cmd.tag};
|
||||
|
||||
dma_controller dma_controller_inst
|
||||
(
|
||||
.dma_clk(ctrl_clk),
|
||||
.rst_n(rst_n),
|
||||
|
||||
.send_desc_read(send_desc_read),
|
||||
.send_desc_write(send_desc_write),
|
||||
.take_status_read(take_status_read),
|
||||
.take_status_write(take_status_write),
|
||||
|
||||
.desc_read_cmd(desc_read_cmd),
|
||||
.desc_write_cmd(desc_write_cmd),
|
||||
.status_read_cmd(status_read_cmd),
|
||||
.status_write_cmd(status_write_cmd),
|
||||
|
||||
.desc_read_cmd_out(desc_read_cmd_out),
|
||||
.desc_write_cmd_out(desc_write_cmd_out),
|
||||
.status_read_cmd_in(status_read_cmd_in),
|
||||
.status_write_cmd_in(status_write_cmd_in),
|
||||
|
||||
.ready_desc_read(m_axis_desc_read.resp.ready),
|
||||
.ready_desc_write(m_axis_desc_write.resp.ready),
|
||||
.ready_status_read(s_axis_status_read.resp.ready),
|
||||
.ready_status_write(s_axis_status_write.resp.ready),
|
||||
|
||||
.valid_desc_read(m_axis_desc_read.req.t.valid),
|
||||
.valid_desc_write(m_axis_desc_write.req.t.valid),
|
||||
.valid_status_read(s_axis_status_read.req.t.valid),
|
||||
.valid_status_write(s_axis_status_write.req.t.valid),
|
||||
|
||||
.desc_read_dma_busy(desc_read_dma_busy),
|
||||
.desc_write_dma_busy(desc_write_dma_busy),
|
||||
.status_read_dma_busy(status_read_dma_busy),
|
||||
.status_write_dma_busy(status_write_dma_busy),
|
||||
|
||||
.desc_read_dma_hs(desc_read_dma_hs),
|
||||
.desc_write_dma_hs(desc_write_dma_hs),
|
||||
.status_read_dma_hs(status_read_dma_hs),
|
||||
.status_write_dma_hs(status_write_dma_hs)
|
||||
);
|
||||
|
||||
axis_defaults_master defaults_rd (.axis(m_axis_desc_read));
|
||||
axis_defaults_master defaults_wr (.axis(m_axis_desc_write));
|
||||
|
||||
assign m_axis_desc_read.req.t.data = desc_read_cmd_out;
|
||||
assign m_axis_desc_write.req.t.data = desc_write_cmd_out;
|
||||
assign status_read_cmd_in = s_axis_status_read.req.t.data;
|
||||
assign status_write_cmd_in = s_axis_status_write.req.t.data;
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,111 @@
|
||||
import dma_reg_pkg::*;
|
||||
|
||||
module dma_controller
|
||||
(
|
||||
input dma_clk,
|
||||
input rst_n,
|
||||
input logic send_desc_read,
|
||||
input logic send_desc_write,
|
||||
input logic take_status_read,
|
||||
input logic take_status_write,
|
||||
|
||||
input logic ready_desc_read,
|
||||
input logic ready_desc_write,
|
||||
|
||||
output logic ready_status_read,
|
||||
output logic ready_status_write,
|
||||
|
||||
input dma_read_desc_t desc_read_cmd,
|
||||
input dma_write_desc_t desc_write_cmd,
|
||||
|
||||
output dma_read_status_t status_read_cmd,
|
||||
output dma_write_status_t status_write_cmd,
|
||||
|
||||
input dma_read_status_t status_read_cmd_in,
|
||||
input dma_write_status_t status_write_cmd_in,
|
||||
|
||||
output logic desc_read_dma_busy,
|
||||
output logic desc_write_dma_busy,
|
||||
output logic status_read_dma_busy,
|
||||
output logic status_write_dma_busy,
|
||||
|
||||
output logic desc_read_dma_hs,
|
||||
output logic desc_write_dma_hs,
|
||||
output logic status_read_dma_hs,
|
||||
output logic status_write_dma_hs,
|
||||
|
||||
output logic valid_desc_read,
|
||||
output logic valid_desc_write,
|
||||
|
||||
input logic valid_status_read,
|
||||
input logic valid_status_write,
|
||||
|
||||
output dma_read_desc_t desc_read_cmd_out,
|
||||
output dma_write_desc_t desc_write_cmd_out
|
||||
);
|
||||
|
||||
shaper_axis_desc
|
||||
#(
|
||||
.DATA_WIDTH($bits(dma_read_desc_t))
|
||||
) shaper_axis_desc_read
|
||||
(
|
||||
.clk(dma_clk),
|
||||
.rst_n(rst_n),
|
||||
.data_in(desc_read_cmd),
|
||||
.send(send_desc_read),
|
||||
.ready(ready_desc_read),
|
||||
.busy(desc_read_dma_busy),
|
||||
.handshake(desc_read_dma_hs),
|
||||
.data_out(desc_read_cmd_out),
|
||||
.valid(valid_desc_read)
|
||||
);
|
||||
|
||||
shaper_axis_desc
|
||||
#(
|
||||
.DATA_WIDTH($bits(dma_write_desc_t))
|
||||
) shaper_axis_desc_write
|
||||
(
|
||||
.clk(dma_clk),
|
||||
.rst_n(rst_n),
|
||||
.data_in(desc_write_cmd),
|
||||
.send(send_desc_write),
|
||||
.ready(ready_desc_write),
|
||||
.busy(desc_write_dma_busy),
|
||||
.handshake(desc_write_dma_hs),
|
||||
.data_out(desc_write_cmd_out),
|
||||
.valid(valid_desc_write)
|
||||
);
|
||||
|
||||
shaper_axis_status
|
||||
#(
|
||||
.DATA_WIDTH($bits(dma_read_status_t))
|
||||
) shaper_axis_status_read
|
||||
(
|
||||
.clk(dma_clk),
|
||||
.rst_n(rst_n),
|
||||
.data_in(status_read_cmd_in),
|
||||
.take(take_status_read),
|
||||
.valid(valid_status_read),
|
||||
.ready(ready_status_read),
|
||||
.busy(status_read_dma_busy),
|
||||
.handshake(status_read_dma_hs),
|
||||
.data_out(status_read_cmd)
|
||||
);
|
||||
|
||||
shaper_axis_status
|
||||
#(
|
||||
.DATA_WIDTH($bits(dma_write_status_t))
|
||||
) shaper_axis_status_write
|
||||
(
|
||||
.clk(dma_clk),
|
||||
.rst_n(rst_n),
|
||||
.data_in(status_write_cmd_in),
|
||||
.take(take_status_write),
|
||||
.valid(valid_status_write),
|
||||
.ready(ready_status_write),
|
||||
.busy(status_write_dma_busy),
|
||||
.handshake(status_write_dma_hs),
|
||||
.data_out(status_write_cmd)
|
||||
);
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,42 @@
|
||||
package dma_reg_pkg;
|
||||
parameter int unsigned AXI_ADDR_WIDTH = 16;
|
||||
parameter int unsigned LEN_WIDTH = 20;
|
||||
parameter int unsigned TAG_WIDTH = 8;
|
||||
parameter int unsigned AXIS_ID_WIDTH = 8;
|
||||
parameter int unsigned AXIS_DEST_WIDTH = 8;
|
||||
parameter int unsigned AXIS_USER_WIDTH = 1;
|
||||
|
||||
typedef struct packed {
|
||||
logic [AXIS_USER_WIDTH-1:0] user;
|
||||
logic [AXIS_DEST_WIDTH-1:0] dest;
|
||||
logic [AXIS_ID_WIDTH-1:0] id;
|
||||
logic [TAG_WIDTH-1:0] tag;
|
||||
logic [LEN_WIDTH-1:0] len;
|
||||
logic [AXI_ADDR_WIDTH-1:0] addr;
|
||||
|
||||
} dma_read_desc_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [TAG_WIDTH-1:0] tag;
|
||||
logic [LEN_WIDTH-1:0] len;
|
||||
logic [AXI_ADDR_WIDTH-1:0] addr;
|
||||
|
||||
} dma_write_desc_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [3:0] error;
|
||||
logic [TAG_WIDTH-1:0] tag;
|
||||
|
||||
} dma_read_status_t;
|
||||
|
||||
typedef struct packed {
|
||||
logic [3:0] error;
|
||||
logic [AXIS_USER_WIDTH-1:0] user;
|
||||
logic [AXIS_DEST_WIDTH-1:0] dest;
|
||||
logic [AXIS_ID_WIDTH-1:0] id;
|
||||
logic [TAG_WIDTH-1:0] tag;
|
||||
logic [LEN_WIDTH-1:0] len;
|
||||
|
||||
} dma_write_status_t;
|
||||
|
||||
endpackage
|
||||
@@ -0,0 +1,54 @@
|
||||
module shaper_axis_desc #(
|
||||
parameter DATA_WIDTH = 128
|
||||
) (
|
||||
input clk,
|
||||
input rst_n,
|
||||
input logic [DATA_WIDTH-1:0] data_in,
|
||||
input logic send,
|
||||
input logic ready,
|
||||
|
||||
output logic busy,
|
||||
output logic handshake,
|
||||
output logic [DATA_WIDTH-1:0] data_out,
|
||||
output logic valid
|
||||
);
|
||||
|
||||
typedef enum logic [0:0] {
|
||||
IDLE,
|
||||
WAIT_READY
|
||||
} wr_state;
|
||||
|
||||
wr_state state;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!rst_n) begin
|
||||
state <= IDLE;
|
||||
busy <= 1'b0;
|
||||
handshake <= 1'b0;
|
||||
data_out <= 1'b0;
|
||||
valid <= 1'b0;
|
||||
end else begin
|
||||
case (state)
|
||||
IDLE: begin
|
||||
handshake <= 1'b0;
|
||||
if (send) begin
|
||||
valid <= 1'b1;
|
||||
data_out <= data_in;
|
||||
busy <= 1'b1;
|
||||
state <= WAIT_READY;
|
||||
end
|
||||
end
|
||||
WAIT_READY: begin
|
||||
if (ready) begin
|
||||
valid <= 1'b0;
|
||||
handshake <= 1'b1;
|
||||
busy <= 1'b0;
|
||||
state <= IDLE;
|
||||
end
|
||||
end
|
||||
default: state <= IDLE;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -0,0 +1,59 @@
|
||||
module shaper_axis_status #(
|
||||
parameter int unsigned DATA_WIDTH = 128
|
||||
)(
|
||||
input logic clk,
|
||||
input logic rst_n,
|
||||
|
||||
input logic [DATA_WIDTH-1:0] data_in,
|
||||
input logic take,
|
||||
input logic valid,
|
||||
output logic ready,
|
||||
|
||||
output logic busy,
|
||||
output logic handshake,
|
||||
output logic [DATA_WIDTH-1:0] data_out
|
||||
);
|
||||
|
||||
typedef enum logic [0:0] {
|
||||
IDLE,
|
||||
WAIT_TAKE
|
||||
} wr_state;
|
||||
|
||||
wr_state state;
|
||||
|
||||
logic [31:0] data_reg;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!rst_n) begin
|
||||
state <= IDLE;
|
||||
ready <= 1'b0;
|
||||
busy <= 1'b0;
|
||||
handshake <= 1'b0;
|
||||
data_out <= '0;
|
||||
data_reg <= '0;
|
||||
end else begin
|
||||
case (state)
|
||||
IDLE: begin
|
||||
ready <= 1'b1;
|
||||
if (valid) begin
|
||||
busy <= 1'b0;
|
||||
data_reg <= data_in;
|
||||
handshake <= 1'b1;
|
||||
state <= WAIT_TAKE;
|
||||
end
|
||||
end
|
||||
WAIT_TAKE: begin
|
||||
if (take) begin
|
||||
data_out <= data_reg;
|
||||
ready <= 1'b0;
|
||||
handshake <= 1'b0;
|
||||
busy <= 1'b1;
|
||||
state <= IDLE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user