module axi_lite_to_arinc429_rx ( // AXI-Lite Interface input wire s_axi_aclk, input wire s_axi_aresetn, // AXI-Lite Write Address Channel input wire [31:0] s_axi_awaddr, input wire s_axi_awvalid, output wire s_axi_awready, // AXI-Lite Write Data Channel input wire [31:0] s_axi_wdata, input wire [3:0] s_axi_wstrb, input wire s_axi_wvalid, output wire s_axi_wready, // AXI-Lite Write Response Channel output wire [1:0] s_axi_bresp, output wire s_axi_bvalid, input wire s_axi_bready, // AXI-Lite Read Address Channel input wire [31:0] s_axi_araddr, input wire s_axi_arvalid, output wire s_axi_arready, // AXI-Lite Read Data Channel output wire [31:0] s_axi_rdata, output wire [1:0] s_axi_rresp, output wire s_axi_rvalid, input wire s_axi_rready, // ARINC 429 Receiver Interface input wire rx_clk, input wire arinc429_in, // Status Interrupt output wire irq ); // Register Address Map localparam REG_CONTROL = 8'h00; localparam REG_STATUS = 8'h04; localparam REG_DATA_COUNT = 8'h08; localparam REG_DATA = 8'h0C; localparam REG_SPEED = 8'h10; // Control Register Bits localparam CTRL_ENABLE = 0; localparam CTRL_RESET = 1; localparam CTRL_IRQ_EN = 2; // Status Register Bits localparam STATUS_EMPTY = 0; localparam STATUS_FULL = 1; localparam STATUS_OVERRUN = 2; localparam STATUS_ERROR = 3; // Speed Settings localparam SPEED_12_5KHZ = 2'b00; localparam SPEED_50KHZ = 2'b01; localparam SPEED_100KHZ = 2'b10; // FIFO Parameters localparam FIFO_DEPTH = 1024; localparam FIFO_ADDR_WIDTH = 10; // AXI-Lite Internal Signals reg [31:0] control_reg; reg [31:0] status_reg; reg [31:0] data_count_reg; reg [31:0] speed_reg; wire write_en; wire read_en; wire [31:0] read_data; // FIFO Signals wire [31:0] fifo_data_out; wire fifo_read_en; wire fifo_write_en; wire fifo_empty; wire fifo_full; wire [FIFO_ADDR_WIDTH:0] fifo_count; // ARINC 429 Receiver Signals reg rx_enable; reg [1:0] rx_speed; wire [31:0] rx_data; wire rx_data_valid; wire rx_error; // Clock Domain Crossing Signals reg [2:0] control_cdc_sync; reg [2:0] status_cdc_sync; reg [FIFO_ADDR_WIDTH:0] data_count_cdc_sync; // ============================================================================ // AXI-Lite Interface Logic // ============================================================================ // Write Address Ready assign s_axi_awready = s_axi_awvalid && s_axi_wvalid; assign s_axi_wready = s_axi_awvalid && s_axi_wvalid; // Write Response assign s_axi_bresp = 2'b00; // Always OK assign s_axi_bvalid = s_axi_awready; // Read Address Ready assign s_axi_arready = s_axi_arvalid; // Read Data Response assign s_axi_rresp = 2'b00; // Always OK // Write Enable assign write_en = s_axi_awready && s_axi_wvalid; // Read Enable assign read_en = s_axi_arready && s_axi_rready; // Register Write always @(posedge s_axi_aclk) begin if (!s_axi_aresetn) begin control_reg <= 32'h0; speed_reg <= 32'h0; end else if (write_en) begin case (s_axi_awaddr[7:0]) REG_CONTROL: control_reg <= s_axi_wdata; REG_SPEED: speed_reg <= s_axi_wdata; endcase end end // Register Read reg [31:0] read_data_mux; always @(*) begin case (s_axi_araddr[7:0]) REG_CONTROL: read_data_mux = control_reg; REG_STATUS: read_data_mux = status_reg; REG_DATA_COUNT: read_data_mux = data_count_reg; REG_DATA: read_data_mux = fifo_data_out; REG_SPEED: read_data_mux = speed_reg; default: read_data_mux = 32'h0; endcase end assign s_axi_rdata = read_data_mux; assign s_axi_rvalid = s_axi_arready; // ============================================================================ // Clock Domain Crossing - Control to RX domain // ============================================================================ always @(posedge rx_clk) begin control_cdc_sync <= {control_cdc_sync[1:0], control_reg[2:0]}; end always @(posedge rx_clk) begin if (control_cdc_sync[2]) begin // Reset from AXI domain rx_enable <= 1'b0; rx_speed <= SPEED_12_5KHZ; end else begin rx_enable <= control_cdc_sync[0]; // Enable bit rx_speed <= speed_reg[1:0]; // Speed selection end end // ============================================================================ // ARINC 429 Receiver Core // ============================================================================ arinc429_rx_core arinc429_rx_inst ( .clk(rx_clk), .reset(!control_cdc_sync[2]), // Active high reset .enable(rx_enable), .speed(rx_speed), .arinc429_in(arinc429_in), .data_out(rx_data), .data_valid(rx_data_valid), .error(rx_error) ); // ============================================================================ // FIFO for Received Data // ============================================================================ async_fifo #( .DATA_WIDTH(32), .FIFO_DEPTH(FIFO_DEPTH), .ADDR_WIDTH(FIFO_ADDR_WIDTH) ) rx_fifo ( // Write Interface (RX clock domain) .wr_clk(rx_clk), .wr_reset(!control_cdc_sync[2]), .wr_en(fifo_write_en), .wr_data(rx_data), .full(fifo_full), // Read Interface (AXI clock domain) .rd_clk(s_axi_aclk), .rd_reset(!s_axi_aresetn), .rd_en(fifo_read_en), .rd_data(fifo_data_out), .empty(fifo_empty), // Status .data_count(fifo_count) ); assign fifo_write_en = rx_data_valid && !fifo_full; assign fifo_read_en = read_en && (s_axi_araddr[7:0] == REG_DATA) && !fifo_empty; // ============================================================================ // Clock Domain Crossing - Status to AXI domain // ============================================================================ // Synchronize FIFO status always @(posedge s_axi_aclk) begin status_cdc_sync <= {status_cdc_sync[1:0], {fifo_empty, fifo_full, rx_error}}; data_count_cdc_sync <= fifo_count; end // Status register update always @(posedge s_axi_aclk) begin if (!s_axi_aresetn) begin status_reg <= 32'h0; data_count_reg <= 32'h0; end else begin status_reg <= { 28'h0, // Reserved status_cdc_sync[2], // Error flag fifo_write_en && fifo_full, // Overrun flag status_cdc_sync[1], // Full flag status_cdc_sync[0] // Empty flag }; data_count_reg <= {22'h0, data_count_cdc_sync}; end end // ============================================================================ // Interrupt Generation // ============================================================================ reg irq_enable; reg data_available_irq; always @(posedge s_axi_aclk) begin if (!s_axi_aresetn) begin irq_enable <= 1'b0; data_available_irq <= 1'b0; end else begin irq_enable <= control_reg[CTRL_IRQ_EN]; // Generate interrupt when data becomes available if (fifo_count > 0 && !data_available_irq) begin data_available_irq <= 1'b1; end else if (read_en && (s_axi_araddr[7:0] == REG_DATA)) begin data_available_irq <= (fifo_count > 1); // Keep asserted if more data end end end assign irq = irq_enable && data_available_irq; endmodule // ============================================================================ // ARINC 429 Receiver Core Module // ============================================================================ module arinc429_rx_core ( input wire clk, input wire reset, input wire enable, input wire [1:0] speed, input wire arinc429_in, output reg [31:0] data_out, output reg data_valid, output reg error ); // Speed settings: clock cycles per bit localparam [15:0] BIT_TIME_12_5KHZ = 16'd800; // 100MHz / 12.5kHz = 8000 cycles, 1 bit = 32+8+1=41 bits? Adjust as needed localparam [15:0] BIT_TIME_50KHZ = 16'd200; localparam [15:0] BIT_TIME_100KHZ = 16'd100; reg [15:0] bit_time; reg [15:0] bit_counter; reg [5:0] bit_index; reg [31:0] shift_reg; enum logic [2:0] { IDLE, SYNC, RECEIVE_DATA, RECEIVE_PARITY, CHECK_PARITY } state; reg arinc_sync; reg arinc_prev; // Edge detection always @(posedge clk) begin if (reset) begin arinc_prev <= 1'b0; arinc_sync <= 1'b0; end else begin arinc_prev <= arinc429_in; arinc_sync <= arinc429_in && !arinc_prev; // Positive edge detection end end // Bit time selection always @(*) begin case (speed) SPEED_12_5KHZ: bit_time = BIT_TIME_12_5KHZ; SPEED_50KHZ: bit_time = BIT_TIME_50KHZ; SPEED_100KHZ: bit_time = BIT_TIME_100KHZ; default: bit_time = BIT_TIME_12_5KHZ; endcase end // Receiver state machine always @(posedge clk) begin if (reset) begin state <= IDLE; data_out <= 32'h0; data_valid <= 1'b0; error <= 1'b0; bit_counter <= 16'h0; bit_index <= 6'h0; shift_reg <= 32'h0; end else if (enable) begin case (state) IDLE: begin data_valid <= 1'b0; error <= 1'b0; if (arinc_sync) begin state <= SYNC; bit_counter <= 16'h0; end end SYNC: begin if (bit_counter >= (bit_time / 2)) begin state <= RECEIVE_DATA; bit_counter <= 16'h0; bit_index <= 6'd0; shift_reg <= 32'h0; end else begin bit_counter <= bit_counter + 16'h1; end end RECEIVE_DATA: begin if (bit_counter >= bit_time) begin shift_reg <= {shift_reg[30:0], arinc429_in}; bit_index <= bit_index + 6'h1; bit_counter <= 16'h0; if (bit_index >= 31) begin state <= RECEIVE_PARITY; end end else begin bit_counter <= bit_counter + 16'h1; end end RECEIVE_PARITY: begin if (bit_counter >= bit_time) begin // Basic parity check (odd parity) if (^shift_reg == arinc429_in) begin data_out <= shift_reg; data_valid <= 1'b1; error <= 1'b0; end else begin error <= 1'b1; end state <= IDLE; end else begin bit_counter <= bit_counter + 16'h1; end end default: state <= IDLE; endcase end else begin state <= IDLE; data_valid <= 1'b0; error <= 1'b0; end end endmodule // ============================================================================ // Asynchronous FIFO Module // ============================================================================ module async_fifo #( parameter DATA_WIDTH = 32, parameter FIFO_DEPTH = 1024, parameter ADDR_WIDTH = 10 )( // Write Interface input wire wr_clk, input wire wr_reset, input wire wr_en, input wire [DATA_WIDTH-1:0] wr_data, output wire full, // Read Interface input wire rd_clk, input wire rd_reset, input wire rd_en, output wire [DATA_WIDTH-1:0] rd_data, output wire empty, // Status output wire [ADDR_WIDTH:0] data_count ); reg [DATA_WIDTH-1:0] mem [0:FIFO_DEPTH-1]; reg [ADDR_WIDTH:0] wr_ptr; reg [ADDR_WIDTH:0] rd_ptr; reg [ADDR_WIDTH:0] wr_ptr_gray; reg [ADDR_WIDTH:0] rd_ptr_gray; // CDC synchronizers reg [ADDR_WIDTH:0] wr_ptr_gray_sync [1:0]; reg [ADDR_WIDTH:0] rd_ptr_gray_sync [1:0]; // Write logic always @(posedge wr_clk) begin if (wr_reset) begin wr_ptr <= 0; wr_ptr_gray <= 0; end else if (wr_en && !full) begin mem[wr_ptr[ADDR_WIDTH-1:0]] <= wr_data; wr_ptr <= wr_ptr + 1; wr_ptr_gray <= bin_to_gray(wr_ptr + 1); end end // Read logic always @(posedge rd_clk) begin if (rd_reset) begin rd_ptr <= 0; rd_ptr_gray <= 0; end else if (rd_en && !empty) begin rd_ptr <= rd_ptr + 1; rd_ptr_gray <= bin_to_gray(rd_ptr + 1); end end // CDC for write pointer to read domain always @(posedge rd_clk) begin if (rd_reset) begin wr_ptr_gray_sync[0] <= 0; wr_ptr_gray_sync[1] <= 0; end else begin wr_ptr_gray_sync[0] <= wr_ptr_gray; wr_ptr_gray_sync[1] <= wr_ptr_gray_sync[0]; end end // CDC for read pointer to write domain always @(posedge wr_clk) begin if (wr_reset) begin rd_ptr_gray_sync[0] <= 0; rd_ptr_gray_sync[1] <= 0; end else begin rd_ptr_gray_sync[0] <= rd_ptr_gray; rd_ptr_gray_sync[1] <= rd_ptr_gray_sync[0]; end end // Status flags assign full = (wr_ptr_gray == {~rd_ptr_gray_sync[1][ADDR_WIDTH:ADDR_WIDTH-1], rd_ptr_gray_sync[1][ADDR_WIDTH-2:0]}); assign empty = (rd_ptr_gray == wr_ptr_gray_sync[1]); // Data output assign rd_data = mem[rd_ptr[ADDR_WIDTH-1:0]]; // Data count (synchronized to read clock) assign data_count = wr_ptr - gray_to_bin(rd_ptr_gray_sync[1]); // Gray code functions function [ADDR_WIDTH:0] bin_to_gray(input [ADDR_WIDTH:0] bin); bin_to_gray = bin ^ (bin >> 1); endfunction function [ADDR_WIDTH:0] gray_to_bin(input [ADDR_WIDTH:0] gray); integer i; begin gray_to_bin[ADDR_WIDTH] = gray[ADDR_WIDTH]; for (i = ADDR_WIDTH-1; i >= 0; i = i - 1) begin gray_to_bin[i] = gray_to_bin[i+1] ^ gray[i]; end end endfunction endmodule