diff --git a/rtl/controller_new/README.md b/rtl/controller_new/README.md new file mode 100644 index 0000000..3b7abca --- /dev/null +++ b/rtl/controller_new/README.md @@ -0,0 +1,63 @@ +# Системный контроллер + +Контроллер принимает входные пакеты udp с ethernet, передаваемые по axi stream, и выполняет настройку выходных регистров в соотвествии с содержимым этого пакета, а также синхронизирует сигналы между тремя clock domains - есть clk от ethernet, clk для ЦАП и clk для АЦП + +## Список параметров: +- dac_data_width - битность данных ЦАП, <= 16bit + +## Список входных портов: +- eth_clk_in - базовая входная частота +- dac_clk_in - входная частота ЦАП +- adc_clk_in - входная частота АЦП +- rst_n - общий reset +- s_axis [8 bit] - AXI stream slave для приема данных от ethernet udp (уже разобранный payload по байтам) - домен eth_clk +- finish - сигнал окончания приема данных с АЦП, домен adc_clk ! + +## Список выходных портов: +- dac_pulse_width[31:0] - выход pulse_width в домене dac_clk +- dac_pulse_period[31:0] - выход pulse_period в домене dac_clk +- dac_pulse_height[dac_data_width-1:0] - выход pulse_height в домене dac_clk +- dac_pulse_num[15:0] - выход pulse_num в домене dac_clk +--- +- adc_pulse_period[31:0] - выход pulse_period в домене adc_clk +- adc_pulse_num[15:0] - выход pulse_num в домене adc_clk +--- +- dac_start - start в домене dac_clk +- adc_start - start в домене adc_clk +--- +- dac_rst - rst в домене dac_clk +- adc_rst - rst в домене adc_clk + +## Логика работы: +по умолчанию после инициализации блок встает в состояние ожидания (*idle*), и становится *ready* для приема данных по axis. +далее ждет контрольный пакет. всего есть 3 вариации контрольных пакетов (в любом порядке), получаемых по axi stream: +``` +8'b00001111 - soft reset +8'b11110000 - start +8'b10001000 - set_data +``` + +*soft reset* отправляет пульс rst на dac_rst и adc_rst, синхронизировав пульсы в их доменах. при этом сброс самого контроллера не происходит, значения остаются как и были + +*start* отправляет пульс start на dac_start и adc_start в их доменах. при этом после этого блок перестает быть ready и ждет, пока не придет пульс finish, после этого он возвращается снова в *idle* состояние + +*set_data* значит, что следующие 128 бит = 16*8 байт, пришедшии по axis - это конфигурационная информация и ее нужно записать в внутренний регистр на 128 бит. + +конфигурационный регистр на 128 бит делится так: +``` +reg[31:0] - pulse_width +reg[63:32] - pulse_period +reg[79:64] - pulse_num +reg[79+dac_data_width:80] - pulse_height +reg[127:96] - pulse_period_adc +``` + +соотвественно эти записанные значения выставляются на соотвествующие выходные сигналы в доменах dac_clk и adc_clk. выходы обновляются каждый раз, когда происходит set_data, и сигналы сохраняют своё значение до следующего set_data. + +## Симуляция +Тесты запускаются автоматически через make. +``` +cd tests +make sim +``` +Должно выдать "All tests done" в конце симуляции. \ No newline at end of file diff --git a/rtl/controller_new/src/axi4l_reg_map_controller.sv b/rtl/controller_new/src/axi4l_reg_map_controller.sv new file mode 100644 index 0000000..7600019 --- /dev/null +++ b/rtl/controller_new/src/axi4l_reg_map_controller.sv @@ -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 diff --git a/rtl/controller_new/src/axi4l_reg_map_controller_pkg.sv b/rtl/controller_new/src/axi4l_reg_map_controller_pkg.sv new file mode 100644 index 0000000..89a593e --- /dev/null +++ b/rtl/controller_new/src/axi4l_reg_map_controller_pkg.sv @@ -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 diff --git a/rtl/controller_new/src/axis_defaults_helper.sv b/rtl/controller_new/src/axis_defaults_helper.sv new file mode 100644 index 0000000..dee900a --- /dev/null +++ b/rtl/controller_new/src/axis_defaults_helper.sv @@ -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 \ No newline at end of file diff --git a/rtl/controller_new/src/controller.sv b/rtl/controller_new/src/controller.sv new file mode 100644 index 0000000..f6b9275 --- /dev/null +++ b/rtl/controller_new/src/controller.sv @@ -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 \ No newline at end of file diff --git a/rtl/controller_new/src/controller_wrapper_axil.sv b/rtl/controller_new/src/controller_wrapper_axil.sv new file mode 100644 index 0000000..f2745ba --- /dev/null +++ b/rtl/controller_new/src/controller_wrapper_axil.sv @@ -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 \ No newline at end of file diff --git a/rtl/controller_new/src/dma_controller.sv b/rtl/controller_new/src/dma_controller.sv new file mode 100644 index 0000000..a07f4a4 --- /dev/null +++ b/rtl/controller_new/src/dma_controller.sv @@ -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 \ No newline at end of file diff --git a/rtl/controller_new/src/dma_reg_pkg.sv b/rtl/controller_new/src/dma_reg_pkg.sv new file mode 100644 index 0000000..2daacd9 --- /dev/null +++ b/rtl/controller_new/src/dma_reg_pkg.sv @@ -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 \ No newline at end of file diff --git a/rtl/controller_new/src/shaper_axis_desc.sv b/rtl/controller_new/src/shaper_axis_desc.sv new file mode 100644 index 0000000..7d61c93 --- /dev/null +++ b/rtl/controller_new/src/shaper_axis_desc.sv @@ -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 \ No newline at end of file diff --git a/rtl/controller_new/src/shaper_axis_status.sv b/rtl/controller_new/src/shaper_axis_status.sv new file mode 100644 index 0000000..5bad170 --- /dev/null +++ b/rtl/controller_new/src/shaper_axis_status.sv @@ -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 \ No newline at end of file