SPQI Computer Interface - Verilog Code
Verilog Code
module RS232_V3m( sysclk, rad_triggers_in, RxD, TxD, Switches, LEDs, sevenSegLED_out, sevenSegPos_out, JB_U);
// Nexys3: Family: Spartan 6; Device: XC6SLX16; Package: CSG324; Speed: -3
(* LOC = "V10" *) input sysclk;
(* CLOCK_DEDICATED_ROUTE = "FALSE", LOC = "E11 G11 P11 T12" *) input [3:0] rad_triggers_in;
//trigger (counter) signal 0 is pin JA_U[0]
//trigger (counter) signal 1 is pin JA_U[3]
//trigger (counter) signal 2 is pin JD_U[0]
//trigger (counter) signal 3 is pin JD_U[3]
(* LOC = "J6" *)input RxD; //JC_L[2] //need external RS232 connector
(* LOC = "F2" *) output TxD; //JC_L[3]
(* LOC = "T5 V8 U8 N8 M8 V9 T9 T10" *) input [7:0] Switches;
(* LOC = "L14 N14 M14 U18 U17 T18 T17" *) output [6:0] sevenSegLED_out;
(* LOC = "P17 P18 N15 N16" *) output [3:0] sevenSegPos_out;
(* LOC = "T11 R11 N11 M11 V15 U15 V16 U16" *)output [7:0] LEDs;
(* LOC = "L3 L4 K1 K2" *) output [3:0] JB_U;
parameter SYS_CLOCK_FREQ = 100_000_000; //system clock speed in Hz (check reg clk_div width!)
parameter MYVERSION = 16'h1112;
parameter BIG_COUNTER = 31;
//localparam SYS_CLOCK_FREQ = 50_000_000; //system clock speed in Hz (check reg clk_div width!)
defparam MyHHMMSS.SYS_CLOCK_FREQ = SYS_CLOCK_FREQ;
defparam my_rs232receiver.SYS_CLOCK_FREQ = SYS_CLOCK_FREQ;
defparam my_rs232transmitter.SYS_CLOCK_FREQ = SYS_CLOCK_FREQ;
wire master_reset; //master reset for all counters and one shots
wire [15:0] sysclkfreqMHz = SYS_CLOCK_FREQ / 1_000_000; //sys_clock frequency in MHz
/*******setup the reference clocks ************************************/
/* DAY::HH:MM:SS Clock Code ***************************************/
wire clk_miliseconds, clk_seconds, clk_minutes, clk_hours, clk_days;
wire [15:0] miliseconds;
wire [15:0] seconds;
wire [15:0] minutes;
wire [15:0] hours;
wire [15:0] days;
HHMMSS2a MyHHMMSS(sysclk, master_reset, clk_miliseconds, miliseconds, clk_seconds, seconds, clk_minutes, minutes, clk_hours, hours, clk_days, days);
/**************SET COINCIDENCE WINDOW **************************************************/
//
// Byte Sent: ~ Tau = 1 sysclk cycle which is the shortest and the default!
// The coincidence window is set through the one shot's clock. This clock is set
// the RS232 byte received from the computer.
// The byte send by the computer corresponds to:
// window = 1: Byte Sent: A Tau = 2 sysclk cycle
// window = 2: Byte Sent: B Tau = 4 sysclk cycle
// window = 3: Byte Sent: C Tau = 6 sysclk cycle
// etc. i.e. n sysclck cycle = 2(winow -1)
// window = 0: Byte Sent: ~ Tau = 1 sysclk cycle which is the shortest and the default!
reg [5:0] ntau_sysclk = 61; //number of sysclock cycles for coincidence window
reg [5:0] onesh_sysclk_counter = 0;
reg one_shot_clk_reg = 0;
wire one_shot_clk;
always @ (posedge sysclk)begin
if (onesh_sysclk_counter == ntau_sysclk ) begin //reset each ntau_sysclk
onesh_sysclk_counter <= 0;
one_shot_clk_reg <= ~one_shot_clk_reg;
end
else begin
onesh_sysclk_counter <= onesh_sysclk_counter + 1;
end
end
assign one_shot_clk =( ntau_sysclk == 61 ) ? sysclk: //input from RS232: 'p'
one_shot_clk_reg;
/********* set up the one-shots for all the trigger inputs **********************/
OneShotV2 OneShotC0( one_shot_clk, rad_triggers_in[0], oneshot0_out);
OneShotV2 OneShotC1( one_shot_clk, rad_triggers_in[1], oneshot1_out);
OneShotV2 OneShotC2( one_shot_clk, rad_triggers_in[2], oneshot2_out);
OneShotV2 OneShotC3( one_shot_clk, rad_triggers_in[3], oneshot3_out);
//OneShotV2( clk, asynctrigger_in, trig_out);
//OneShot OneShotC3( one_shot_clk, master_reset, miliseconds[0], oneshot3_out);
/********* set up the counters for all the straight trigger inputs **********************/
wire [BIG_COUNTER:0] finalcount0_out;
wire [BIG_COUNTER:0] finalcount1_out;
wire [BIG_COUNTER:0] finalcount2_out;
wire [BIG_COUNTER:0] finalcount3_out;
CECounter32 myCECounter0(one_shot_clk, master_reset, oneshot0_out, finalcount0_out);
CECounter32 myCECounter1(one_shot_clk, master_reset, oneshot1_out, finalcount1_out);
CECounter32 myCECounter2(one_shot_clk, master_reset, oneshot2_out, finalcount2_out);
CECounter32 myCECounter3(one_shot_clk, master_reset, oneshot3_out, finalcount3_out);
//testing only
assign JB_U = {clk_miliseconds, sysclk, one_shot_clk, oneshot3_out};
/********* set up the counters for all the 2 counter coincidence inputs **********************/
wire [BIG_COUNTER:0] final_coinc_01_out;
wire [BIG_COUNTER:0] final_coinc_02_out;
wire [BIG_COUNTER:0] final_coinc_03_out;
wire [BIG_COUNTER:0] final_coinc_12_out;
wire [BIG_COUNTER:0] final_coinc_13_out;
wire [BIG_COUNTER:0] final_coinc_23_out;
wire coinc_01, coinc_02, coinc_03, coinc_12, coinc_13, coinc_23;
assign coinc_01 = oneshot0_out & oneshot1_out;
assign coinc_02 = oneshot0_out & oneshot2_out;
assign coinc_03 = oneshot0_out & oneshot3_out;
assign coinc_12 = oneshot1_out & oneshot2_out;
assign coinc_13 = oneshot1_out & oneshot3_out;
assign coinc_23 = oneshot2_out & oneshot3_out;
CECounter32 myCECoincCounter01(one_shot_clk, master_reset, coinc_01, final_coinc_01_out);
CECounter32 myCECoincCounter02(one_shot_clk, master_reset, coinc_02, final_coinc_02_out);
CECounter32 myCECoincCounter03(one_shot_clk, master_reset, coinc_03, final_coinc_03_out);
CECounter32 myCECoincCounter12(one_shot_clk, master_reset, coinc_12, final_coinc_12_out);
CECounter32 myCECoincCounter13(one_shot_clk, master_reset, coinc_13, final_coinc_13_out);
CECounter32 myCECoincCounter23(one_shot_clk, master_reset, coinc_23, final_coinc_23_out);
/********* set up the counters for all the 3 counter coincidence inputs **********************/
wire [BIG_COUNTER:0] final_coinc_012_out;
wire [BIG_COUNTER:0] final_coinc_013_out;
wire [BIG_COUNTER:0] final_coinc_023_out;
wire [BIG_COUNTER:0] final_coinc_123_out;
wire coinc_012, coinc_013, coinc_023, coinc_123;
assign coinc_012 = oneshot0_out & oneshot1_out & oneshot2_out;
assign coinc_013 = oneshot0_out & oneshot1_out & oneshot3_out;
assign coinc_023 = oneshot0_out & oneshot2_out & oneshot3_out;
assign coinc_123 = oneshot1_out & oneshot2_out & oneshot3_out;
CECounter32 myCECoincCounter012(one_shot_clk, master_reset, coinc_012, final_coinc_012_out);
CECounter32 myCECoincCounter013(one_shot_clk, master_reset, coinc_013, final_coinc_013_out);
CECounter32 myCECoincCounter023(one_shot_clk, master_reset, coinc_023, final_coinc_023_out);
CECounter32 myCECoincCounter123(one_shot_clk, master_reset, coinc_123, final_coinc_123_out);
/********* set up the counters for all the 4 counter coincidence inputs **********************/
wire [BIG_COUNTER:0] final_coinc_0123_out;
wire coinc_0123;
assign coinc_0123 = oneshot0_out & oneshot1_out & oneshot2_out & oneshot3_out;
CECounter32 myCECoincCounter0123(one_shot_clk, master_reset, coinc_0123, final_coinc_0123_out);
/***************END OF COINCIDENCE COUNTER SETUP **********************************/
/***********************************************************************************/
/* **************** RS 232 PORT STUFF ************************** */
//RECEIVER ////////////////////////////////////////////////
wire RxD_data_ready;
wire [7:0] RxD_data;
//receiver
async_receiver my_rs232receiver(.clk(sysclk), .RxD(RxD), .RxD_data_ready(RxD_data_ready), .RxD_data(RxD_data));
// Trigger Oneshot for byte received
reg datarec = 0;
reg datarec_reset = 0;
always @(posedge RxD_data_ready or posedge datarec_reset)
if (datarec_reset) begin
datarec <= 0;
end
else begin
datarec <= 1;
end
// TRANSMITTER /////////////////////////////////////////////////
reg [7:0] GPin;
wire TxD_Transmit;
wire TxD_BUSY;
async_transmitter my_rs232transmitter(.clk(sysclk), .TxD(TxD), .TxD_start(TxD_Transmit), .TxD_data(GPin), .TxD_busy( TxD_BUSY));
/***********************************FSM For RS232***********************/
/* RS232 OUTPUT FORMAT: ALL are 2 byte blocks separated by comma: (without blank spaces); at the end a CR.
/: DAYS, HH, MM, SEC, MilisSEC, Counter0, Counter1, Counter 2, Counter3, Coincidence01, Coincidence 12 <CR> */
parameter TWOBYTECOUNTERS = 21; //number of FOUR!!!! byte pairs to be sent out:
// 15 from rad counters, 5 from clock + 1 sys clock frequency info
parameter BYTESOUT = 4*TWOBYTECOUNTERS; //counter bytes to be sent out
parameter BYTESMAX = 2*BYTESOUT+TWOBYTECOUNTERS-1; //total bytes to be sent including commas
reg [7:0] bytecounter = 0;
reg [8*BYTESOUT-1:0] DataOut = 0;
reg [2:0] state = 0;
parameter STATE_IDLE = 0;
parameter STATE_COUNTER = 1;
parameter STATE_RS232_TRANSMIT = 2;
parameter COMMA = 8'h2c;
parameter CR = 8'h0d;
parameter LF = 8'h0a;
reg [3:0] commactr = 0; //counts space to send out commas after every two bytes
reg counter_resets = 0;
//works and sends out two bytes of data via RS232
always@( posedge sysclk )
case( state)
STATE_IDLE: begin
if( datarec) begin //trigger data received; reset everything and get ready to send out data
datarec_reset <= 1;
counter_resets <= 1;
DataOut <= {16'h0000, days, 16'h0000, hours,16'h0000, minutes,16'h0000, seconds, 16'h0000, miliseconds, 16'h0000, sysclkfreqMHz,
finalcount0_out, finalcount1_out, finalcount2_out, finalcount3_out,
final_coinc_01_out, final_coinc_02_out, final_coinc_03_out,
final_coinc_12_out, final_coinc_13_out, final_coinc_23_out,
final_coinc_012_out, final_coinc_013_out, final_coinc_023_out, final_coinc_123_out,
final_coinc_0123_out
};
bytecounter <= 0;
state <= STATE_COUNTER;
commactr <= 0;
//Store value sent from compute in RS232Data_FromComputer register to set coincidence window
//subtract 65 ('A') from it to find mulitple of sys_clk coincidence window, i.e.,
//tau = (RxD_data-65 + 1)*tau_sysclock
ntau_sysclk <= RxD_data-65; //watch for upper / lower case letters!
end
else
state <= STATE_IDLE;
end
STATE_COUNTER: begin
if( (bytecounter < BYTESMAX) & ( commactr < 8) ) begin //do it by nibbles to convert to ASCII
datarec_reset <= 0; //maybe move to end to prevent retrigger?
counter_resets <= 0;
//GPin <= tmpradcounts0[8*BYTESOUT-1:8*(BYTESOUT-1)];
DataOut <= {DataOut[8*(BYTESOUT-1)-1+4:0 ],4'h0};
state <= STATE_RS232_TRANSMIT;
commactr <= commactr + 1;
if(DataOut[8*BYTESOUT-1:8*(BYTESOUT-1)+4]< 10) //check for numbers or letteres
GPin <= DataOut[8*BYTESOUT-1:8*(BYTESOUT-1)+4]+48;
else
GPin <= DataOut[8*BYTESOUT-1:8*(BYTESOUT-1)+4]+55;
end
else if( (bytecounter < BYTESMAX) & ( commactr == 8) ) begin //send out a comma after every 4 bytes
GPin <= COMMA;
state <= STATE_RS232_TRANSMIT;
commactr <= 0;
end
else if( bytecounter == BYTESMAX ) begin //send out CR and finish
GPin <= CR;
state <= STATE_RS232_TRANSMIT;
end
else begin
state <= STATE_IDLE; //check???????????????????????
end
bytecounter <= bytecounter + 1;
end
STATE_RS232_TRANSMIT: begin
if( TxD_BUSY)
state <= STATE_RS232_TRANSMIT;
else begin
state <= STATE_COUNTER;
end
end
endcase
assign TxD_Transmit = (state == STATE_RS232_TRANSMIT )&(! TxD_BUSY);
//assign BNC2 = TxD; //_Transmit; // signal from board to computer
OneShotV2 OneShotMasterReset( one_shot_clk, counter_resets, master_reset);
//assign master_reset = counter_resets;
//set up for display and instantiate it
//assign LEDs = miliseconds_counter[14:6]; //helpful for debugging
assign LEDs = Switches[7] ? 8'h00 : 8'h00 ; //finalcount1_out; // miliseconds_counter[14:6]; //helpful for debugging
wire [15:0] display_value;
assign display_value =(Switches[5:0] == 6'b00_0000 ) ? miliseconds: //miliseconds
(Switches[5:0] == 6'b00_0001 ) ? seconds: // seconds
(Switches[5:0] == 6'b00_0010 ) ? minutes: //minutes
(Switches[5:0] == 6'b00_0011 ) ? hours: //hours
(Switches[5:0] == 6'b00_0100 ) ? finalcount0_out: //
(Switches[5:0] == 6'b00_0101 ) ? finalcount1_out: //
(Switches[5:0] == 6'b00_0110 ) ? finalcount2_out: //
(Switches[5:0] == 6'b00_0111 ) ? finalcount3_out: //
(Switches[5:0] == 6'b00_1000 ) ? final_coinc_01_out: //
(Switches[5:0] == 6'b00_1001 ) ? final_coinc_02_out: //
(Switches[5:0] == 6'b00_1010 ) ? final_coinc_03_out: //
(Switches[5:0] == 6'b00_1011 ) ? final_coinc_12_out: //
(Switches[5:0] == 6'b00_1100 ) ? final_coinc_13_out: //
(Switches[5:0] == 6'b00_1101 ) ? final_coinc_23_out: //
(Switches[5:0] == 6'b00_1110 ) ? final_coinc_012_out: //
(Switches[5:0] == 6'b00_1111 ) ? final_coinc_013_out: //
(Switches[5:0] == 6'b01_0000 ) ? final_coinc_023_out: //
(Switches[5:0] == 6'b01_0001 ) ? final_coinc_123_out: //
(Switches[5:0] == 6'b01_0011 ) ? final_coinc_0123_out: //
(Switches[5:0] == 6'b11_1111 ) ? MYVERSION: //
16'hFFFF; //default value
HexDisplayV1 myHexDisp(sysclk, display_value, Switches[6], Switches[7], sevenSegLED_out, sevenSegPos_out);
endmodule
module OneShotV2( clk, asynctrigger_in, trig_out);
input clk;
input asynctrigger_in;
output trig_out; //lasts exactly one clock cycle
reg trig_set = 0;
reg trig_reset = 0;
/*************** ASYNC INPUT to ONE SHOT *****************************/
// One Shot Part: sets output (oneshot_out) HI for one cycle when "asynctrigger_in" is HI
// during posedge sysclk. Otherwise, "oneshot_out" stays LO.
// Therefore, one shot output is synced with sysclk.
always@(posedge asynctrigger_in or posedge trig_reset)
if( trig_reset)
trig_set <= 0;
else
trig_set <=1;
always@( posedge clk)
if( trig_set)
trig_reset <= 1;
else
trig_reset <=0;
assign trig_out = trig_reset;
/************** END of ONE SHOT *******************************/
endmodule
module CECounter32(sysclk, reset, CE_in, finalcount_out);
/******************** 32 bit COUNTER with CE INPUT and LAST COUNT OUTPUT *********************/
// Counter with CE: is activated by sysclk but it increments only
// during one sysclk cycle when "CE_in" is HI.
// At "reset" countvalue is stored into final_count registry.
input sysclk;
input reset;
input CE_in; //counter enable signal (keep HI for only one cycle!)
output reg [31:0] finalcount_out = 0;
reg [31:0] internal_counter = 0;
always @(posedge sysclk )
if (reset) begin
internal_counter <= 0;
end
else if (CE_in) begin
if( internal_counter != 32'hffff_ffff) //prevent overflow
internal_counter <= internal_counter + 1;
end
//eliminate the problem when reset is more than one sysclock cycle long
// in which case in the previous version the finalcount_out was set 0
always @(posedge reset )
finalcount_out <= internal_counter;
/******************** END OF COUNTER ***************************/
endmodule
-- Main.KurtWick - 13 Dec 2012
Verilog code attached