OpenCores
URL https://opencores.org/ocsvn/uart16550/uart16550/trunk

Subversion Repositories uart16550

[/] [uart16550/] [tags/] [initial/] [verilog/] [UART_regs.v] - Rev 106

Compare with Previous | Blame | View Log

//  UART core registers
//
// Includes transmission and reception tasks
//
// Author: Jacob Gorban   (jacob.gorban@flextronicssemi.com)
// Company: Flextronics Semiconductor
//
// Filename: UART_regs.v
//
// Releases:
//              1.1     First release
//
`include "timescale.v"
`include "UART_defines.v"
 
`define DL1 7:0
`define DL2 15:8
`define DL3 23:16
`define DL4 31:24
 
module UART_regs (clk,
	wb_rst_i, wb_addr_i, wb_dat_i, wb_dat_o, wb_we_i,
 
// registers
	ier, iir, fcr, mcr, lcr, lsr, msr, dl,
// additional signals
	modem_inputs,
	stx_o, srx_i,
	enable,
	rts_o, dtr_o
	);
 
input		clk;
input		wb_rst_i;
input	[`ADDR_WIDTH-1:0]	wb_addr_i;
input	[7:0]	wb_dat_i;
output	[7:0]	wb_dat_o;
input		wb_we_i;
 
output	[3:0]	ier;
output	[7:0]	iir;
output	[3:0]	fcr;  /// bits 7,6,2,1 of fcr. Other bits are ignored
output	[4:0]	mcr;
output	[7:0]	lcr;
output	[7:0]	lsr;
output	[7:0]	msr;
output	[31:0]	dl;  // 32-bit divisor latch
output		stx_o;
input		srx_i;
 
input	[3:0]	modem_inputs;
output		enable;
output		rts_o;
output		dtr_o;
 
wire	[3:0]	modem_inputs;
reg		enable;
reg		stx_o;
wire		srx_i;
 
reg	[7:0]	wb_dat_o;
 
wire	[`ADDR_WIDTH-1:0]	wb_addr_i;
wire	[7:0]	wb_dat_i;
 
 
reg	[3:0]	ier;
reg	[7:0]	iir;
reg	[3:0]	fcr;  /// bits 7,6,2,1 of fcr. Other bits are ignored
reg	[4:0]	mcr;
reg	[7:0]	lcr;
reg	[7:0]	lsr;
reg	[7:0]	msr;
reg	[31:0]	dl;  // 32-bit divisor latch
 
reg	[31:0]	dlc;  // 32-bit divisor latch counter
 
// Transmitter FIFO signals
wire	[`FIFO_WIDTH-1:0]	tf_data_in;
wire	[`FIFO_WIDTH-1:0]	tf_data_out;
reg				tf_push;
reg				tf_pop;
wire				tf_underrun;
wire				tf_overrun;
wire	[`FIFO_COUNTER_W-1:0]	tf_count;
 
// Receiver FIFO signals
reg	[`FIFO_REC_WIDTH-1:0]	rf_data_in;
wire	[`FIFO_REC_WIDTH-1:0]	rf_data_out;
reg				rf_push;
reg				rf_pop;
wire				rf_underrun;
wire				rf_overrun;
wire	[`FIFO_COUNTER_W-1:0]	rf_count;
wire				rf_error_bit; // an error (parity or framing) is inside the fifo
 
reg	[3:0]			trigger_level; // trigger level of the receiver FIFO
 
wire		dlab;			   // divisor latch access bit
wire		cts_i, dsr_i, ri_i, dcd_i; // modem status bits
wire		loopback;		   // loopback bit (MCR bit 4)
wire		cts, dsr, ri, dcd;	   // effective signals (considering loopback)
wire		rts_o, dtr_o;		   // modem control outputs
 
//
// ASSINGS
//
assign {cts_i, dsr_i, ri_i, dcd_i} = modem_inputs;
assign {cts, dsr, ri, dcd} = loopback ? {mcr[`MC_RTS],mcr[`MC_DTR],mcr[`MC_OUT1],mcr[`MC_OUT2]}
		 : ~{cts_i,dsr_i,ri_i,dcd_i};
 
assign dlab = lcr[`LC_DL];
assign tf_data_in = wb_dat_i;
assign loopback = mcr[4];
 
// assign modem outputs
assign	rts_o = mcr[`MC_RTS];
assign	dtr_o = mcr[`MC_DTR];
 
 
//
// FIFO INSTANCES
//
 
UART_TX_FIFO fifo_tx(clk, wb_rst_i, tf_data_in, tf_data_out,
	tf_push, tf_pop, tf_underrun, tf_overrun, tf_count);
 
UART_RX_FIFO fifo_rx(clk, wb_rst_i, rf_data_in, rf_data_out,
	rf_push, rf_pop, rf_underrun, rf_overrun, rf_count, rf_error_bit);
// Receiver FIFO parameters redefine
defparam fifo_rx.fifo_width = `FIFO_REC_WIDTH;
 
always @(posedge clk)   // synchrounous reading
//always @(wb_we_i or wb_addr_i or dlab or dl or rf_data_out or ier or iir or lcr or lsr or msr)
    if (~wb_we_i)   //if (we're not writing)
	case (wb_addr_i)
	`REG_RB : begin // Receiver FIFO or DL byte 1
			rf_pop <= #1 1;
			wb_dat_o <= #1 dlab ? dl[`DL1] : rf_data_out;
		  end
 
	`REG_IE	: wb_dat_o <= #1 dlab ? dl[`DL2] : ier;
	`REG_II	: wb_dat_o <= #1 iir;
	`REG_LC	: wb_dat_o <= #1 lcr;
	`REG_LS	: if (dlab)
			wb_dat_o <= #1 dl[`DL4];
		  else
		  begin
			wb_dat_o <= #1 lsr;
			// clear read bits
			lsr <= #1 lsr & 8'b00000001;
		  end
	`REG_MS	: wb_dat_o <= #1 msr;
	`REG_DL3: wb_dat_o <= #1 dlab ? dl[`DL3] : 8'b0;
 
	default:  wb_dat_o <= #1 8'b0; // ??
	endcase
    else
	wb_dat_o <= #1 8'b0;
 
 
//
//   WRITES AND RESETS   //
//
// Line Control Register
always @(posedge clk)
	if (wb_rst_i)
		lcr <= #1 8'b00000011; // 8n1 setting
	else
	if (wb_we_i && wb_addr_i==`REG_LC)
		lcr <= #1 wb_dat_i;
 
// Interrupt Enable Register or DL2
always @(posedge clk or posedge wb_rst_i)
	if (wb_rst_i)
		ier <= #1 4'b0000; // no interrupts after reset
	else
	if (wb_we_i && wb_addr_i==`REG_IE)
		if (dlab)
		begin
			dl[`DL2] <= #1 wb_dat_i;
			dlc <= #1 dl;  // reset the counter to dl value
		end
		else
			ier <= #1 wb_dat_i[3:0]; // ier uses only 4 lsb
 
 
// FIFO Control Register
always @(posedge clk or posedge wb_rst_i)
	if (wb_rst_i)
		fcr <= #1 4'b1100; // no interrupts after reset
	else
	if (wb_we_i && wb_addr_i==`REG_FC)
		fcr <= #1 {wb_dat_i[7:6],wb_dat_i[2:1]};
 
// Modem Control Register or DL3
always @(posedge clk or posedge wb_rst_i)
	if (wb_rst_i)
		mcr <= #1 5'b00000; // no interrupts after reset
	else
	if (wb_we_i && wb_addr_i==`REG_MC)
		if (dlab)
		begin
			dl[`DL3] <= #1 wb_dat_i;
			dlc <= #1 dl;
		end
		else
			mcr <= #1 wb_dat_i[4:0];
 
// TX_FIFO or DL1
always @(posedge clk or posedge wb_rst_i)
	if (!wb_rst_i && wb_we_i && wb_addr_i==`REG_TR)
		if (dlab)
		begin
			dl[`DL1] <= #1 wb_dat_i;
			dlc <= #1 dl;
		end
		else
			tf_push  <= #1 1;
 
// Receiver FIFO trigger level selection logic (asynchronous mux)
always @(fcr[`FC_TL])
	case (fcr[`FC_TL])
		2'b00 : trigger_level <= #1 1;
		2'b01 : trigger_level <= #1 4;
		2'b10 : trigger_level <= #1 8;
		2'b11 : trigger_level <= #1 14;
	endcase
 
// FIFO push and pop signals reset
always @(posedge clk or posedge wb_rst_i)
	if (wb_rst_i)
		tf_push <= #1 0;
	else
	if (tf_push == 1)
		tf_push <= #1 0;
 
always @(posedge clk or posedge wb_rst_i)
	if (wb_rst_i)
		tf_pop <= #1 0;
	else
	if (tf_pop == 1)
		tf_pop <= #1 0;
 
always @(posedge clk or posedge wb_rst_i)
	if (wb_rst_i)
		rf_push <= #1 0;
	else
	if (rf_push == 1)
		rf_push <= #1 0;
 
always @(posedge clk or posedge wb_rst_i)
	if (wb_rst_i)
		rf_pop <= #1 0;
	else
	if (rf_pop == 1)
		rf_pop <= #1 0;
 
 
// DL4 write
always @(posedge clk)
	if (!wb_rst_i && wb_we_i && wb_addr_i==`REG_DL4)
	begin
		dl[`DL4] <= #1 wb_dat_i;
		dlc <= #1 dl;
	end
 
//
//  STATUS REGISTERS  //
//
 
// Modem Status Register
always @(posedge clk)
begin
	msr[`MS_DDCD:`MS_DCTS] <= #1 {dcd, ri, dsr, cts} ^ msr[`MS_DDCD:`MS_DCTS];
	msr[`MS_CDCD:`MS_CCTS] <= #1 {dcd, ri, dsr, cts};
end
 
// Divisor Latches reset
always @(posedge wb_rst_i)
	dl <= #1 32'b0;
 
// Line Status Register is after the transmitter
 
// Enable signal generation logic
always @(posedge clk)
begin
	if (|dl) // if dl<>0
		if (enable)
			dlc <= #1 dl;
		else
			dlc <= #1 dlc - 1;  // decrease count
end
 
always @(dlc)
	if (~|dlc)  // dlc==0 ?
		enable = 1;
	else
		enable = 0;
 
//
//	INTERRUPT LOGIC
//
reg	rls_int;  // receiver line status interrupt
reg	rda_int;  // receiver data available interrupt
reg	ti_int;   // timeout indicator interrupt
reg	thre_int; // transmitter holding register empty interrupt
reg	ms_int;   // modem status interrupt
 
reg	[5:0]	counter_t;	// counts the timeout condition clocks
 
always @(posedge clk or posedge wb_rst_i)
begin
	if (wb_rst_i)
	begin
		rls_int  <= #1 0;
		rda_int  <= #1 0;
		ti_int   <= #1 0;
		thre_int <= #1 0;
		ms_int   <= #1 0;
	end
	else
	begin
		rls_int  <= #1 lsr[`LS_OE] | lsr[`LS_PE] | lsr['LS_FE] | lsr[`LS_BE];
		rda_int  <= #1 (rf_count >= trigger_level);
		thre_int <= #1 lsr[`LS_TFE];
		ms_int   <= #1 | msr[7:4]; // modem interrupt is pending when one of the modem inputs is asserted
		ti_int   <= #1 (counter_t == 0);
	end
end
 
always @(posedge clk or posedge wb_rst_i)
begin
	if (rls_int && ier[`IE_RLS])  // interrupt occured and is enabled  (not masked)
	begin
		iir[`II_II] <= #1 `II_RLS;	// set identification register to correct value
		iir				// and set the IIR bit 0 (interrupt pending)
	end
end
 
 
 
//
// TRANSMITTER LOGIC
//
 
`define S_IDLE        0
`define S_SEND_START  1
`define S_SEND_BYTE   2
`define S_SEND_PARITY 3
`define S_SEND_STOP   4
`define S_POP_BYTE    5
 
reg	[2:0]	state;
reg	[3:0]	counter16;
reg	[2:0]	bit_counter;   // counts the bits to be sent
reg	[6:0]	shift_out;	// output shift register
reg		bit_out;
reg		parity_xor;  // parity of the word
 
always @(posedge clk or posedge wb_rst_i)
begin
  if (wb_rst_i)
  begin
	state     <= #1 `S_IDLE;
	stx_o     <= #1 0;
	counter16 <= #1 0;
  end
  else
  if (enable)
  begin
	case (state)
	`S_IDLE	 :	if (~|tf_count) // if tf_count==0
			begin
				state <= #1 `S_IDLE;
				stx_o <= #1 0;
			end
			else
			begin
				tf_pop <= #1 1;
				stx_o  <= #1 0;
				state  <= #1 `S_POP_BYTE;
			end
	`S_POP_BYTE :	begin
				tf_pop <= #1 0;
				case (lcr[/*`LC_BITS*/1:0])  // number of bits in a word
				2'b00 : begin
					bit_counter <= #1 3'b100;
					parity_xor  <= #1 ^tf_data_out[4:0];
				     end
				2'b01 : begin
					bit_counter <= #1 3'b101;
					parity_xor  <= #1 ^tf_data_out[5:0];
				     end
				2'b10 : begin
					bit_counter <= #1 3'b110;
					parity_xor  <= #1 ^tf_data_out[6:0];
				     end
				2'b11 : begin
					bit_counter <= #1 3'b111;
					parity_xor <= #1 ^tf_data_out[7:0];
				     end
				endcase
				{shift_out[6:0], bit_out} <= #1 tf_data_out;
				state <= #1 `S_SEND_START;
			end
	`S_SEND_START :	begin
				if (~|counter16)
					counter16 <= #1 4'b1111;
				else
				if (counter16 == 1)
				begin
					counter16 <= #1 0;
					state <= #1 `S_SEND_BYTE;
				end
				else
					counter16 <= #1 counter16 - 1;
				stx_o <= #1 1;
			end
	`S_SEND_BYTE :	begin
				if (~|counter16)
					counter16 <= #1 4'b1111;
				else
				if (counter16 == 1)
				begin
					if (|bit_counter) // if bit_counter>0
					begin
						bit_counter <= #1 bit_counter - 1;
						{shift_out[5:0],bit_out  } <= #1 {shift_out[6:1], shift_out[0]};
						state <= #1 `S_SEND_BYTE;
					end
					else   // end of byte
					if (~lcr[`LC_PE])
					begin
						state <= #1 `S_SEND_STOP;
					end
					else
					begin
						case ({lcr[`LC_EP],lcr[`LC_SP]})
						2'b00:	bit_out <= #1 ~parity_xor;
						2'b01:	bit_out <= #1 1;
						2'b10:	bit_out <= #1 parity_xor;
						2'b11:	bit_out <= #1 0;
						endcase
						state <= #1 `S_SEND_PARITY;
					end
					counter16 <= #1 0;
				end
				else
					counter16 <= #1 counter16 - 1;
				stx_o <= #1 bit_out; // set output pin
			end
	`S_SEND_PARITY :	begin
				if (~|counter16)
					counter16 <= #1 4'b1111;
				else
				if (counter16 == 1)
				begin
					counter16 <= #1 0;
					state <= #1 `S_SEND_STOP;
				end
				else
					counter16 <= #1 counter16 - 1;
				stx_o <= #1 bit_out;
			end
	`S_SEND_STOP :  begin
				if (~|counter16)
					counter16 <= #1 4'b1111;
				else
				if (counter16 == 1)
				begin
					counter16 <= #1 0;
					state <= #1 `S_IDLE;
				end
				else
					counter16 <= #1 counter16 - 1;
				stx_o <= #1 0;
			end
 
		default : // should never get here
			state <= #1 `S_IDLE;
	endcase
  end // end if enable
end // transmitter logic
 
 
///
///  RECEIVER LOGIC
///
 
`define SR_IDLE		0
`define SR_REC_START	1
`define SR_REC_BIT	2
`define	SR_REC_PARITY	3
`define SR_REC_STOP	4
`define SR_CHECK_PARITY	5
`define SR_REC_PREPARE	6
`define SR_END_BIT	7
`define SR_CALC_PARITY	8
`define SR_WAIT1	9
`define SR_PUSH		10
`define SR_LAST		11
 
reg	[3:0]	rstate;
reg	[3:0]	rcounter16;
reg	[2:0]	rbit_counter;
reg	[7:0]	rshift;			// receiver shift register
reg		rparity;		// received parity
reg		rparity_error;
reg		rframing_error;		// framing error flag
reg		rbit_in;
reg		rparity_xor;
 
wire		rcounter16_eq_7 = (rcounter16 == 7);
wire		rcounter16_eq_0 = (rcounter16 == 0);
wire	[3:0]	rcounter16_minus_1 = rcounter16 - 1;
 
always @(posedge clk or posedge wb_rst_i)
begin
  if (wb_rst_i)
  begin
	rstate		<= #1 `SR_IDLE;
	rbit_in		<= #1 0;
	rcounter16	<= #1 0;
	rbit_counter	<= #1 0;
	rparity_xor	<= #1 0;
	rframing_error	<= #1 0;
	rparity_error	<= #1 0;
	rshift		<= #1 0;
  end
  else
  if (enable)
  begin
	case (rstate)
	`SR_IDLE :	if (srx_i==1)   // detected a pulse (start bit?)
			begin
				rstate <= #1 `SR_REC_START;
				rcounter16 <= #1 4'b1110;
			end
			else
				rstate <= #1 `SR_IDLE;
	`SR_REC_START :	begin
				if (rcounter16_eq_7)    // check the pulse
					if (srx_i==0)   // no start bit
						rstate <= #1 `SR_IDLE;
					else            // start bit detected
						rstate <= #1 `SR_REC_PREPARE;
				rcounter16 <= #1 rcounter16_minus_1;
			end
	`SR_REC_PREPARE:begin
				case (lcr[/*`LC_BITS*/1:0])  // number of bits in a word
				2'b00 : rbit_counter <= #1 3'b100;
				2'b01 : rbit_counter <= #1 3'b101;
				2'b10 : rbit_counter <= #1 3'b110;
				2'b11 : rbit_counter <= #1 3'b111;
				endcase
				if (rcounter16_eq_0)
				begin
					rstate		<= #1 `SR_REC_BIT;
					rcounter16	<= #1 4'b1110;
					rshift		<= #1 0;
				end
				else
					rstate <= #1 `SR_REC_PREPARE;
				rcounter16 <= #1 rcounter16_minus_1;
			end
	`SR_REC_BIT :	begin
				if (rcounter16_eq_0)
					rstate <= #1 `SR_END_BIT;
				if (rcounter16_eq_7) // read the bit
					case (lcr[/*`LC_BITS*/1:0])  // number of bits in a word
					2'b00 : rshift[4:0]  <= #1 {srx_i, rshift[4:1]};
					2'b01 : rshift[5:0]  <= #1 {srx_i, rshift[5:1]};
					2'b10 : rshift[6:0]  <= #1 {srx_i, rshift[6:1]};
					2'b11 : rshift[7:0]  <= #1 {srx_i, rshift[7:1]};
					endcase
				rcounter16 <= #1 rcounter16_minus_1;
			end
	`SR_END_BIT :   begin
				if (rbit_counter==0) // no more bits in word
					if (lcr[`LC_PE]) // choose state based on parity
						rstate <= #1 `SR_REC_PARITY;
					else
					begin
						rstate <= #1 `SR_REC_STOP;
						rparity_error <= #1 0;  // no parity - no error :)
					end
				else		// else we have more bits to read
				begin
					rstate <= #1 `SR_REC_BIT;
					rbit_counter <= #1 rbit_counter - 1;
				end
				rcounter16 <= #1 4'b1110;
			end
	`SR_REC_PARITY: begin
				if (rcounter16_eq_7)	// read the parity
				begin
					rparity <= #1 srx_i;
					rstate <= #1 `SR_CALC_PARITY;
				end
				rcounter16 <= #1 rcounter16_minus_1;
			end
	`SR_CALC_PARITY : begin    // rcounter equals 6
				rcounter16  <= #1 rcounter16_minus_1;
				rparity_xor <= #1 ^{rshift,rparity}; // calculate parity on all incoming data
				rstate      <= #1 `SR_CHECK_PARITY;
			  end
	`SR_CHECK_PARITY: begin	  // rcounter equals 5
				case ({lcr[`LC_EP],lcr[`LC_SP]})
				2'b00: rparity_error <= #1 ~rparity_xor;  // no error if parity 1
				2'b01: rparity_error <= #1 ~rparity;      // parity should sticked to 1
				2'b10: rparity_error <= #1 rparity_xor;   // error if parity is odd
				2'b11: rparity_error <= #1 rparity;	  // parity should be sticked to 0
				endcase
				rcounter16 <= #1 rcounter16_minus_1;
				rstate <= #1 `SR_WAIT1;
			  end
	`SR_WAIT1 :	if (rcounter16_eq_0)
			begin
				rstate <= #1 `SR_REC_STOP;
				rcounter16 <= #1 4'b1110;
			end
			else
			begin
				rcounter16 <= #1 rcounter16_minus_1;
//				rstate <= #1 `SR_WAIT1;
			end
	`SR_REC_STOP :	begin
				if (rcounter16_eq_7)	// read the parity
				begin
					rframing_error <= #1 srx_i; // no framing error if input is 0 (stop bit)
					rf_data_in <= #1 {rshift, rparity_error, rframing_error};
					rstate <= #1 `SR_PUSH;
				end
				rcounter16 <= #1 rcounter16_minus_1;
			end
	`SR_PUSH :	begin
///////////////////////////////////////
				$display($time, ": received: %b", rf_data_in);
				rf_push    <= #1 1;
				rstate     <= #1 `SR_LAST;
			end
	`SR_LAST :	begin
				if (rcounter16_eq_0)
					rstate <= #1 `SR_IDLE;
				rcounter16 <= #1 rcounter16_minus_1;
				rf_push <= #1 0;
			end
	default : rstate <= #1 `SR_IDLE;
	endcase
  end  // if (enable)
end // always of receiver
 
//
// Break condition detection.
// Works in conjuction with the receiver state machine
reg	[3:0]	counter_b;	// counts the 0 signals
 
always @(posedge clk or posedge wb_rst_i)
begin
	if (wb_rst_i)
		counter_b <= #1 4'd11;
	else
	if (enable)  // only work on enable times
		if (srx_i)
		begin
			counter_b <= #1 4'd11; // maximum character time length - 1
			lsr[`LS_BI] <= #1 0;   // break off
		end
		else
		if (counter_b == 0)            // break reached
			lsr[`LS_BI] <= #1 1;   // break detected flag set
		else
			counter_b <= #1 counter_b - 1;  // decrement break counter
end // always of break condition detection
 
///
/// Timeout condition detection
 
always @(posedge clk or posedge wb_rst_i)
begin
	if (wb_rst_i)
		counter_t <= #1 6'd44;
	else
	if (enable)
		if(rf_push | rf_pop | rda_int) // counter is reset when RX FIFO is accessed or above trigger level
			counter_t <= #1 6'd44;
		else
		if (counter_t != 0)  // we don't want to underflow
			counter_t <= #1 counter_t - 1;		
end
 
// Line Status Register
always @(posedge clk or wb_rst_i)
begin
	if (wb_rst_i)
		lsr <= #1 8'b01100000;
	else
	begin
		lsr[0] <= #1 (rf_count!=0);  // data in receiver fifo available
		lsr[1] <= #1 rf_overrun;     // Receiver overrun error
		lsr[2] <= #1 rf_data_out[1]; // parity error bit
		//lsr[4] (break interrupt is done in break detection, after the receiver FSM)
		lsr[3] <= #1 rf_data_out[0]; // framing error bit
		lsr[5] <= #1 (tf_count==0);  // transmitter fifo is empty
		lsr[6] <= #1 (tf_count==0 && state == `S_IDLE); // transmitter empty
		lsr[7] <= #1 rf_error_bit;
	end
end
 
endmodule
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.