`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: // // Create Date: 10/24/2023 01:55:27 PM // Design Name: // Module Name: controller // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// // // this module assumes that in the level above, there's a FIFO that buffers all // UART receive transmissions. // // the byte receive in the rx_fifo_data input to this module // contains the relevant data to decode: // // to make things easier, the uart rx instruction will be 1 byte but the data coming // into the FPGA or out of the FPGA will be 2 bytes. // // control register: we probably only need 8 bits. will pack the LSB to MSB // // status register: ditto // // threshold register: the data is only 12 bits long and we likely won't // need a threshold that is in the first 4 bits so we really only need 8 bits. // so we will use the bottom 8 bits of the threshold data sent and compare that // to the upper 8 bits of the ADC data // // prefill register: use all bits, to get the trigger to land in the middle of the // fifo, set this to 16'hFFFF FFFE; (that is all but the LSB set) // // bit 0 asserted means that the RPi is sending instructions for what data it will be sending // next so that the FPGA knows where to put it // if bit 0 = 1, then the next bits tell the FPGA what data is coming in: // bits 2:0 = // 001 control register (16 bits, but probably don't need very many) // 011 threshold register (16 bits, but probably only the upper 8 bits are necessary) // 101 prefill register (16 bits) // // if bit 0 = 0 then the RPi is reading from the FPGA, so the FPGA has to transmit // bits 7:0 = // 7654 3210 // 0000 0000 control register // 0000 0010 status register // 0000 0100 threshold register // 0000 0110 prefill register // 0000 1000 r_adc_data // 0000 1010 firmware version // 0000 1100 test vector // 0001 0000 16 bits of data from the ADC fifo. note that the upper 12 bits will // be the ADC data, and we will pack the bottom 4 bits with information // that will tell us things about the status and use the LSB to tell the // RPi that the FIFO is empty // 0001 0010 16 bits of fifo data count (not really needed by the RPi but....) // any other value will cause the FPGA to send back 16'hdeadbeef as an error indicator // module controller( input clock, input reset, input rx_fifo_empty, input [7:0] rx_fifo_data, output rx_fifo_rd, input tx_done, output reg tx_transmit, output reg [15:0] tx_out, input [15:0] firmware_version, input [15:0] test_vector, input [15:0] r_adc_data, output data_fifo_rd_en, output data_fifo_wr_en, input data_fifo_empty, input data_fifo_full, input [12:0] data_fifo_data, // MSB is triggered, next 12 bits are ADC input [15:0] data_fifo_count, output [15:0] led, output triggered, output [31:0] debug ); // // control register. bits are: // 0 set to 1 to enable writing into the data FIFO // 1 set to 1 to enable comparing incoming data to the trigger threshold // reg [15:0] control; wire global_start = control[0]; wire trigger_start = control[1]; // // threshold and prefill registers // for threshold triggering, compare the 12 bits of ADC data in r_adc_data // to the bottom 12 bits of threshold // reg [15:0] threshold; wire trigger = trigger_start && (r_adc_data[15:4] > threshold[11:0]); assign triggered = trigger; reg [15:0] prefill; // // status register. bits are: // 0 global start enabled // 1 trigger start enabled // 2 rx fifo empty // 3 data fifo empty // 4 data fifo full // 5 event triggered // wire [15:0] status = {trigger,data_fifo_full,data_fifo_empty,rx_fifo_empty,trigger_start,global_start}; // // here is the rx state machine, it looks at the rx fifo empty flag to know if it has // anything to process // wire incoming = ~rx_fifo_empty; // this is the signal that the fifo has something in it to process localparam [2:0] RX_WAIT=0, RX_READ_EN1=1, RX_READ_EN0=2, RX_LATCH_FIFO=3, RX_BRANCH=4, RX_INCOMING=5, RX_OUTGOING=6; reg [2:0] rx_state; reg [7:0] rx_instructions; reg do_read_fifo, do_incoming, do_outgoing; wire read_fifo_done, incoming_done, outgoing_done; wire branch_to_incoming = rx_instructions[0]; // incoming or outgoing wire [1:0] incoming_what = rx_instructions[2:1]; // what incoming is coming in wire [3:0] outgoing_what = rx_instructions[3:0]; // what is going out wire out_from_data_fifo = rx_instructions[4]; always @ (posedge clock) if (reset) begin rx_state <= RX_WAIT; do_read_fifo <= 0; do_incoming <= 0; do_outgoing <= 0; rx_instructions <= 0; end else case (rx_state) RX_WAIT: begin rx_instructions <= 0; do_read_fifo <= 0; do_incoming <= 0; do_outgoing <= 0; rx_state <= incoming ? RX_READ_EN1 : RX_WAIT; end RX_READ_EN1: begin do_read_fifo <= 1; rx_state <= RX_READ_EN0; end RX_READ_EN0: begin do_read_fifo <= 0; rx_state <= RX_LATCH_FIFO; end RX_LATCH_FIFO: begin rx_instructions <= rx_fifo_data; rx_state <= RX_BRANCH; end RX_BRANCH: begin rx_state <= branch_to_incoming ? RX_INCOMING : RX_OUTGOING; end RX_INCOMING: begin do_incoming <= 1; rx_state <= incoming_done ? RX_WAIT : RX_INCOMING; end RX_OUTGOING: begin do_outgoing <= 1; rx_state <= outgoing_done ? RX_WAIT : RX_OUTGOING; end default: begin rx_state <= RX_WAIT; end endcase // // here is the "incoming" FSM that responds to the RPi sending data to the FPGA // localparam [3:0] IN_WAIT=0, IN_WAIT_NOT_EMPTY1=1, IN_READ1_EN1=2, IN_READ1_EN0=3, IN_READ1_LATCH=4, IN_WAIT_NOT_EMPTY2=5, IN_READ2_EN1=6, IN_READ2_EN0=7, IN_READ2_LATCH=8, IN_DONE=9; reg [3:0] in_state; reg in_read_fifo; reg in_done; reg [15:0] in_data; always @ (posedge clock) if (reset) begin in_state <= IN_WAIT; in_read_fifo <= 0; in_data <= 0; in_done <= 0; end else case (in_state) IN_WAIT: begin in_read_fifo <= 0; in_data <= 0; in_done <= 0; in_state <= do_incoming ? IN_WAIT_NOT_EMPTY1 : IN_WAIT; end IN_WAIT_NOT_EMPTY1: begin in_state <= incoming ? IN_READ1_EN1 : IN_WAIT_NOT_EMPTY1; end IN_READ1_EN1: begin in_read_fifo <= 1; in_state <= IN_READ1_EN0; end IN_READ1_EN0: begin in_read_fifo <= 0; in_state <= IN_READ1_LATCH; end IN_READ1_LATCH: begin in_data[7:0] <= rx_fifo_data; in_state <= IN_WAIT_NOT_EMPTY2; end IN_WAIT_NOT_EMPTY2: begin in_state <= incoming ? IN_READ2_EN1 : IN_WAIT_NOT_EMPTY2; end IN_READ2_EN1: begin in_read_fifo <= 1; in_state <= IN_READ2_EN0; end IN_READ2_EN0: begin in_read_fifo <= 0; in_state <= IN_READ2_LATCH; end IN_READ2_LATCH: begin in_data[15:8] <= rx_fifo_data; in_state <= IN_DONE; end IN_DONE: begin in_done <= 1; case (incoming_what) 2'b00: control <= in_data; 2'b01: threshold <= in_data; 2'b10: prefill <= in_data; 2'b11: in_data <= in_data; // should be an error condition!!! endcase in_state <= do_incoming ? IN_DONE : IN_WAIT; end endcase assign incoming_done = in_done; // // rx_fifo_read driver // assign rx_fifo_rd = do_read_fifo | in_read_fifo; // // now make the state machine to handle sending 16 bit words to the RPi // localparam [3:0] OUT_WAIT=0, OUT_CHECK=1, OUT_LATCH=2, OUT_FIFO1=3, OUT_FIFO0=4, OUT_FIFO_LATCH=5, OUT_TRANSMIT=6, OUT_TRANSMIT_WAIT1=7, OUT_TRANSMIT_WAIT2=8, OUT_DONE=9; reg [3:0] out_state; reg out_done; reg out_read_fifo; wire fifo_last = (data_fifo_count == 16'h1); always @ (posedge clock) if (reset) begin out_state <= OUT_WAIT; tx_transmit <= 0; out_done <= 0; tx_out <= 0; out_read_fifo <= 0; end else case (out_state) OUT_WAIT: begin tx_transmit <= 0; tx_out <= 0; out_done <= 0; out_read_fifo <= 0; out_state <= do_outgoing ? OUT_CHECK : OUT_WAIT; end OUT_CHECK: begin // // check if we are going to send data from the ADC FIFO // out_state <= out_from_data_fifo ? OUT_FIFO1 : OUT_LATCH; end OUT_FIFO1: begin // // issue a fifo read and then latch the result // out_read_fifo <= 1; out_state <= OUT_FIFO0; end OUT_FIFO0: begin out_read_fifo <= 0; out_state <= OUT_FIFO_LATCH; end OUT_FIFO_LATCH: begin case (outgoing_what) // // for sending back data, pack the upper 12 bits with adc value and the next 4 bits // with triggered,global_start,data_fifo_empty,fifo_last // // the RPi will look at the LSB fifo_last to know if this is the last word in the fifo // 4'b0000: tx_out <= {data_fifo_data[11:0],data_fifo_data[12],global_start,data_fifo_empty,fifo_last}; 4'b0001: tx_out <= data_fifo_count; default: tx_out <= tx_out; endcase out_state <= OUT_TRANSMIT; end OUT_LATCH: begin // 7654 3210 // 0000 0000 control register // 0000 0010 status register // 0000 0100 threshold register // 0000 0110 prefill register // 0000 1000 r_adc_data // 0000 1010 firmware version // 0000 1100 test vector case (outgoing_what) 4'b0000: tx_out <= control; 4'b0010: tx_out <= status; 4'b0100: tx_out <= threshold; 4'b0110: tx_out <= prefill; 4'b1000: tx_out <= r_adc_data; 4'b1010: tx_out <= firmware_version; 4'b1100: tx_out <= test_vector; default: tx_out <= tx_out; endcase out_state <= OUT_TRANSMIT; end OUT_TRANSMIT: begin tx_transmit <= 1; out_state <= OUT_TRANSMIT_WAIT1; end OUT_TRANSMIT_WAIT1: begin tx_transmit <= 0; out_state <= tx_done ? OUT_TRANSMIT_WAIT2 : OUT_TRANSMIT_WAIT1 ; end OUT_TRANSMIT_WAIT2: begin out_state <= tx_done ? OUT_DONE : OUT_TRANSMIT_WAIT2; end OUT_DONE: begin out_done <= 1; out_state <= do_outgoing ? OUT_DONE : OUT_WAIT; end endcase assign outgoing_done = out_done; // // here is a state machine that takes care of filling the data fifo // reg [2:0] f_state; localparam [2:0] DF_WAIT=0, DF_PREFILL=1, DF_WAIT_TRIGGER=2, DF_WAIT_FULL=3, DF_WAIT_EMPTY=4, DF_READ1=5, DF_WAIT_ACK=6; reg df_rd_en, df_wr_en; reg [15:0] count_fill; wire counted = count_fill == prefill; always @ (posedge clock) begin if (reset) begin count_fill <= 0; df_rd_en <= 0; df_wr_en <= 0; f_state <= DF_WAIT; end else case (f_state) DF_WAIT: begin // // wait for global_start // count_fill <= 0; df_rd_en <= 0; df_wr_en <= 0; f_state <= global_start ? DF_PREFILL : DF_WAIT; end DF_PREFILL: begin // // prefill number of data equal to value of prefill register // this means prefill should never be zero! // prefill means enable write but not read // df_wr_en <= 1; count_fill <= count_fill + 1; f_state <= counted ? DF_WAIT_TRIGGER : DF_PREFILL; end DF_WAIT_TRIGGER: begin // // prefill reached. start reading on every clock tick so that // the number of words remains constant. then wait for a // trigger // df_rd_en <= 1; f_state <= trigger ? DF_WAIT_FULL : DF_WAIT_TRIGGER; end DF_WAIT_FULL: begin // // trigger! stop reading and wait for the fifo to fill up // df_rd_en <= 0; f_state <= data_fifo_full ? DF_WAIT_EMPTY : DF_WAIT_FULL; end DF_WAIT_EMPTY: begin // // fifo is full. wait for it to be emptied via UART. here is where // we also have to control the fifo read enable, waiting for a signal // from rx_state to read 1 data from the fifo // df_wr_en <= 0; f_state <= data_fifo_empty ? DF_WAIT : DF_WAIT_EMPTY; end default: begin count_fill <= 0; df_rd_en <= 0; df_wr_en <= 0; f_state <= DF_WAIT; end endcase end assign data_fifo_wr_en = df_wr_en; assign data_fifo_rd_en = out_read_fifo | df_rd_en; // // drive the output led signals // // 0 global_start // 1 trigger_start // 2 data_fifo_empty // 3 data_fifo_full // 6:4 rx_state // 9:7 f_state // 14:10 rx_instructions assign led = {1'b0,rx_instructions[4:0],f_state[2:0],rx_state[2:0], data_fifo_full,data_fifo_empty,trigger_start,global_start}; // // 2:0 rx_state // 3 outgoing_done // 4 incoming_done // 5 do_outgoing // 6 do_incoming // 11:7 rx_instructions // 15:12 in_state // 19:16 out_state // 20 tx_transmit // 21 out_read_fifo which is for the ADC fifo // 22 in_read_fifo which is for the rx fifo // 23 do_read_fifo also for the rx fifo // 26:24 f_state // 27 df_wr_en // 28 df_rd_en // 29 counted // 30 data_fifo_empty // 31 data_fifo_full assign debug = {data_fifo_full,data_fifo_empty,counted,df_rd_en,df_wr_en, //31:27 f_state[2:0],do_read_fifo,in_read_fifo,out_read_fifo,tx_transmit, //26:20 out_state[3:0],in_state[3:0],rx_instructions[4:0], //19:7 do_incoming,do_outgoing,incoming_done,outgoing_done,rx_state[2:0]}; //6:0 endmodule