`timescale 1ns/1ps
module top(
input clock, // system clock
input reset, // BTNR
input version, // BTNU
input adc_n, adc_p, // VCAUX 6, P and N
input [15:0] sw, // slide switches
output [15:0] led, // 16 onboard LEDs above the switches
output [6:0] segment, // 4 digit LED display
output dp, // "." next to each LED digit
output [3:0] digit, // 7-segment display anode select
output reg [7:0] JB, // PMOD JB for debugging
output [7:0] JA, // PMOD JA for debugging
input rx, // UART receive
output tx // UART transmit
);
parameter VERSION = 'h0011;
//
// generate a 25MHz and 8MHz clock for the UART and FIFO
//
wire locked, clock25, clock8;
clocks MYCLOCKS (
.reset(reset),
.clk_in1(clock),
.locked(locked),
.clk_out1(clock25),
.clk_out2(clock8)
);
//
// divide clock8 by 8 to get the 1MHz ADC clock
//
reg [2:0] count8;
always @ (posedge clock8) count8 <= count8 + 1;
wire clock1;
BUFG clk1buf (.I(count8[2]), .O(clock1));
//
// next drive the 4 7-segment displays
//
wire [15:0] display_this;
display4 DISPLAY (
.clk100(clock),
.number(display_this),
.digit(digit),
.segments(segment),
.period(dp)
);
//
// instantiate the UART receiver. run with the 50MHz clock so that
// we can run the transmitter FSM at 100MHz and not get lost
//
wire dv;
wire [7:0] rx_data;
uart_rx RECEIVER (
.i_Clocks_per_Bit('d25),
.i_Clock(clock25),
.i_Reset(reset),
.i_Rx_Serial(rx), // tied to FPGA rx output
.o_Rx_DV(dv),
.o_Rx_Byte(rx_data)
);
//
// instantiate a fifo for the UART receiving from the RPi
// tie rx_wr_en to dv so that we can have the fifo write clock
// always going. read will be controlled by the read/write FSM
// in the controller.v module which has clocks running at 1MHz.
//
wire rx_wr_en = dv;
wire rx_full, rx_empty;
wire rx_rd_en;
wire [8:0] rx_dout;
rxfifo FIFO_RX ( // this fifo is 9 bits wide
.rst(reset),
.wr_clk(clock25),
.rd_clk(clock1),
.din({1'b0,rx_data}), // remember, 9 bits in!
.wr_en(rx_wr_en),
.rd_en(rx_rd_en),
.dout(rx_dout), // and 9 bits out
.full(rx_full),
.empty(rx_empty)
);
//
// instantiate the UART transmitter
//
wire tx_active, tx_done;
wire do_transmit;
wire [7:0] transmit_byte;
uart_tx TRANSMITTER (
.i_Clocks_per_Bit('d25),
.i_Clock(clock25),
.i_Reset(reset),
.i_Tx_DV(do_transmit),
.i_Tx_Byte(transmit_byte),
.o_Tx_Active(tx_active),
.o_Tx_Serial(tx), // tied to FPGA tx output
.o_Tx_Done(tx_done)
);
//
// note that the OUT FSM in controller waits for tx_done, which comes from uart_tx which
// runs with a 25HMz clock whereas this FSM here runs with a 1MHz clock
// (so that it can be in sync with the data fifo). so we will need to
// stretch out the tx_done signal, which is only 40ns wide, to make it
// 1us wide so the OUT FSM doesn't miss it
//
wire tx_done_1us;
stretch TX_STRETCH (
.clock(clock25),.reset(reset),.ticks('d25),.sigin(tx_done),.sigout(tx_done_1us)
);
//
// here is the XADC block
//
wire [6:0] daddr_in = 7'h16;
wire adc_ready, isbusy, adc_data_ready, eos_out, alarm;
wire [15:0] adc_data;
wire [4:0] channel_out;
myxadc XADC_INST (
.daddr_in(7'h16), // specifies vcaux6 pints to digitize
.dclk_in(clock), // 50MHz clock
.den_in(adc_ready), // tied to adc_ready, tells adc to convert, tieing causes continuous conversions
.di_in(16'h0), // to set the data to something, not used here
.dwe_in(1'b0), // set to enable writing to di_in, which we don't want to do
.vauxp6(adc_p), // positive input to digitize
.vauxn6(adc_n), // negative input to digitize
.busy_out(isbusy), // tells you the adc is busy converting
.channel_out(channel_out[4:0]), // for using more than 1 channel, tells you which one. not used here
.do_out(adc_data), // adc value from conversion
.drdy_out(adc_data_ready), // tells you valid data is ready to be latched
.eoc_out(adc_ready), // specifies that the ADC is ready (conversion complete)
.eos_out(eos_out), // specifies that conversion sequence is complete
.alarm_out(alarm), // OR's output of all internal alarms, not used here
.vp_in(1'b0), // dedicated analog input pair for differential, tied to 0 if not used
.vn_in(1'b0)
);
//
// Wait for XADC to tell you something is ready to latch, and latch it into the
// r_adc_data bus. Note this means continuous latching
//
reg [15:0] r_adc_data;
always @ (posedge adc_data_ready) begin
if (reset) r_adc_data <= 16'h0;
else r_adc_data <= adc_data;
end
//
// make a ~1Hz clock so we can run the LED display slower
//
reg [19:0] counter;
reg [15:0] s_adc_data;
always @ (posedge clock1) begin
if (reset) counter <= 0;
else counter <= counter + 1;
end
wire clock_1hz = counter[19];
always @ (posedge clock_1hz) s_adc_data <= r_adc_data;
assign display_this = version ? VERSION : s_adc_data;
//
// instantiate our data fifo next
//
wire triggered; // comes out of the controller
wire [17:0] din = {triggered,1'b0,r_adc_data}; // feed this directly into the FIFO data input
wire [17:0] dout;
wire [12:0] fifo_adc_out = {dout[17],dout[15:4]}; // send to controller the ADC bits and whether this triggered
wire wr_en;
wire rd_en, fifo_full, fifo_empty, wr_rst_busy, rd_rst_busy;
wire [15:0] fifo_data_count;
myfifo DATA_FIFO (
.rst(reset),
.wr_clk(clock1),
.rd_clk(clock1),
.din(din),
.wr_en(wr_en),
.rd_en(rd_en),
.dout(dout),
.full(fifo_full),
.empty(fifo_empty),
.rd_data_count(fifo_data_count),
.wr_rst_busy(wr_rst_busy),
.rd_rst_busy(rd_rst_busy)
);
//
// now make a state machine to deal with transmitting 2 bytes at a
// time, including the FIFO value that is present.
//
reg [2:0] tx_state; // 8 states so 3 bits will do
localparam [2:0] TX_IDLE=0, TX_BYTE1=1, TX_DO1=2, TX_WAIT1=3, TX_BYTE2=4,
TX_DO2=5, TX_WAIT2=6, TX_DONE=7;
reg doit;
wire [15:0] transmit_word;
wire begin_transfer;
reg [7:0] tx_data;
always @ (posedge clock25) begin
if (reset) begin
tx_state <= TX_IDLE;
doit <= 0;
tx_data <= 0;
end
else
case (tx_state)
TX_IDLE: begin
//
// wait for begin_transfer to start
//
if (begin_transfer) tx_state <= TX_BYTE1;
else tx_state <= TX_IDLE;
doit <= 0;
tx_data <= 0;
end
TX_BYTE1: begin
//
// latch the first byte of the transmit_word
//
tx_data <= transmit_word[7:0];
tx_state <= TX_DO1;
end
TX_DO1: begin
//
// turn on uart_tx
//
doit <= 1;
tx_state <= TX_WAIT1;
end
TX_WAIT1: begin
//
// turn off doit and wait for uart_tx to finish
//
doit <= 0;
if (tx_done) tx_state <= TX_BYTE2;
else tx_state <= TX_WAIT1;
end
TX_BYTE2: begin
//
// latch the 2nd byte to transfer
//
tx_data <= transmit_word[15:8];
tx_state <= TX_DO2;
end
TX_DO2: begin
//
// turn on uart_tx
//
doit <= 1;
tx_state <= TX_WAIT2;
end
TX_WAIT2: begin
//
// wait for the 2nd byte to finish begin sent
//
doit <= 0;
if (tx_done) tx_state <= TX_DONE;
else tx_state <= TX_WAIT2;
end
TX_DONE: begin
//
// wait for begin_transfer to go away
//
if (do_transmit) tx_state <= TX_DONE;
else tx_state <= TX_IDLE;
end
default: begin
tx_state <= TX_IDLE;
end
endcase
end
assign do_transmit = doit;
assign transmit_byte = tx_data;
//
// instantiate the controller that handles uart rx, and the data fifo
//
wire [31:0] c_debug;
controller CONTROL (
.clock(clock1),
.reset(reset),
.rx_fifo_empty(rx_empty),
.rx_fifo_data(rx_dout[7:0]),
.rx_fifo_rd(rx_rd_en),
.tx_done(tx_done_1us),
.tx_transmit(begin_transfer),
.tx_out(transmit_word),
.firmware_version(VERSION),
.test_vector(sw),
.r_adc_data(r_adc_data),
.data_fifo_rd_en(rd_en),
.data_fifo_wr_en(wr_en),
.data_fifo_empty(fifo_empty),
.data_fifo_full(fifo_full),
.data_fifo_data(fifo_adc_out),
.data_fifo_count(fifo_data_count),
.led(led),
.triggered(triggered),
.debug(c_debug)
);
//
// use the output ports JA and JB, and the slide switches to get different
// debug data for the logic analyzer
//
// c_debug:
//
//
// 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 count_fill
// 30 data_fifo_empty
// 31 data_fifo_full
assign JA = {rx_rd_en,rx_empty,begin_transfer,tx_done,tx,dv,rx,clock25};
always @*
case (sw[15:14])
2'b00: JB = {c_debug[15:12],c_debug[6],c_debug[2:0]}; // in_state,do_incoming,rx_state
2'b01: JB = {c_debug[19:16],c_debug[5],c_debug[2:0]}; // out_state,do_outgoing,rx_state
2'b10: JB = c_debug[31:24]; // data_fifo_full,data_fifo_empty,count_fill,rd_en,wr_en,f_state
2'b11: JB = {c_debug[6],c_debug[5],c_debug[11:7],clock1}; //do_in,do_out,rx_instructions,clock
endcase
endmodule