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

Subversion Repositories rtfsimpleuart

[/] [rtfsimpleuart/] [trunk/] [rtl/] [verilog/] [rtfSimpleUart.v] - Rev 7

Go to most recent revision | Compare with Previous | Blame | View Log

/* ============================================================================
	2007,2011  Robert Finch
	robfinch@<remove>sympatico.ca
 
	rtfSimpleUart.v
		Basic uart with	baud rate generator based on a harmonic
	frequency synthesizer.
 
    This source code is available for evaluation and validation purposes
    only. This copyright statement and disclaimer must remain present in
    the file.
 
 
	NO WARRANTY.
    THIS Work, IS PROVIDEDED "AS IS" WITH NO WARRANTIES OF ANY KIND, WHETHER
    EXPRESS OR IMPLIED. The user must assume the entire risk of using the
    Work.
 
    IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
    INCIDENTAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES WHATSOEVER RELATING TO
    THE USE OF THIS WORK, OR YOUR RELATIONSHIP WITH THE AUTHOR.
 
    IN ADDITION, IN NO EVENT DOES THE AUTHOR AUTHORIZE YOU TO USE THE WORK
    IN APPLICATIONS OR SYSTEMS WHERE THE WORK'S FAILURE TO PERFORM CAN
    REASONABLY BE EXPECTED TO RESULT IN A SIGNIFICANT PHYSICAL INJURY, OR IN
    LOSS OF LIFE. ANY SUCH USE BY YOU IS ENTIRELY AT YOUR OWN RISK, AND YOU
    AGREE TO HOLD THE AUTHOR AND CONTRIBUTORS HARMLESS FROM ANY CLAIMS OR
    LOSSES RELATING TO SUCH UNAUTHORIZED USE.
 
 
  	To use:
 
  	Set the pClkFreq parameter to the frequency of the system
  	clock (clk_i). This can be done when the core is instanced.
 
    1) set the baud rate value in the clock multiplier
    registers (CM1,2,3). A default multiplier value may
    be specified using the pClkMul parameter, so it
    doesn't have to be programmed at run time. (Note the
    pBaud parameter may also be set, but it doesn't work
    in all cases due to arithmetic limitations).
    2) enable communication by activating the rts, and
    dtr signals in the modem control register. These
    signals are defaulted to be active on reset, so they
    may not need to be set. The pRts and pDtr parameters
    may be used to change the default setting.
    3) use interrupts or poll the status register to
    determine when to transmit or receive a byte of data
    4) read / write the transmit / recieve data buffer
    for communication.
 
    Notes:
    	This core only supports a single transmission /
    reception format: 1 start, 8 data, and 1 stop bit (no
    parity).	
    	The baud rate generator uses a 24 bit harmonic
    frequency synthesizer. Compute the multiplier value
    as if a 32 bit value was needed, then take the upper
    24 bits of the value. (The number of significant bits
    in the value determine the minimum frequency
    resolution or the precision of the value).
 
    				baud rate * 16
    	value = -----------------------
    			(clock frequency / 2^32)
 
  		eg			38400 * 16
  		value = -----------------------
				(28.63636MHz / 2^32)
 
				= 92149557.65
				= 057E1736 (hex)
 
 
		taking the upper 24 bits
				top 24 = 057E17
						= 359959
 
		so the value needed to be programmed into the register
	for 38.4k baud is 57E17 (hex)
		eg 	CM0 = 0 (not used)
			CM1 = 17 hex
			CM2 = 7E hex
			CM3 = 05 hex
 
 
	Register Description
 
	reg
	0	read / write (RW)
		TRB - transmit / receive buffer
		transmit / receive buffer
		write 	- write to transmit buffer
		read	- read from receive buffer
 
	1	read only (RO)
		LS	- line status register
		bit 0 = receiver not empty, this bit is set if there is
				any data available in the receiver fifo
		bit 1 = overrun, this bit is set if receiver overrun occurs
		bit 3 = framing error, this bit is set if there was a
				framing error with the current byte in the receiver
				buffer.
		bit 5 = transmitter not full, this bit is set if the transmitter
				can accept more data
		bit 6 = transmitter empty, this bit is set if the transmitter is
				completely empty
 
	2	MS	- modem status register (RO)
		writing to the modem status register clears the change
		indicators, which should clear a modem status interrupt
		bit 3 = change on dcd signal
		bit 4 = cts signal level
		bit 5 = dsr signal level
		bit 6 = ri signal level
		bit 7 = dcd signal level
 
	3	IS	- interrupt status register (RO)
		bit 0-4 = mailbox number
		bit 0,1	= 00
		bit 2-4	= encoded interrupt value
		bit 5-6 = not used, reserved
		bit 7 = 1 = interrupt pending, 0 = no interrupt
 
	4	IE	- interrupt enable register (RW)
		bit 0 = receive interrupt (data present)
		bit 1 = transmit interrupt (data empty)
		bit 3 = modem status (dcd) register change
		bit 5-7 = unused, reserved
 
	5	FF	- frame format register		(RW)
		this register doesn't do anything in the simpleUart
		but is reserved for compatiblity with the more
		advanced uart
 
	6	MC	- modem control register (RW)
		bit 0 = dtr signal level output
		bit 1 = rts signal level output
 
	7	- control register
		bit 0 = hardware flow control,
			when this bit is set, the transmitter output is
			controlled by the cts signal line automatically
 
 
		* Clock multiplier steps the 16xbaud clock frequency
		in increments of 1/2^32 of the clk_i input using a
		harmonic frequency synthesizer
		eg. to get a 9600 baud 16x clock (153.6 kHz) with a
		27.175 MHz clock input,
		value  = upper24(9600 * 16  / (27.175MHz / 2^32))
		Higher frequency baud rates will exhibit more jitter
		on the 16x clock, but this will mostly be masked by the 
		16x clock factor.
 
	8	CM0	- Clock Multiplier byte 0 (RW)
		this is the least significant byte
		of the clock multiplier value
		this register is not used unless the clock
		multiplier is set to contain 32 bit values
 
	9	CM1 - Clock Multiplier byte 1	(RW)
		this is the third most significant byte
		of the clock multiplier value
		this register is not used unless the clock
		multiplier is set to contain 24 or 32 bit values
 
	10	CM2 - Clock Multiplier byte 2	(RW)
		this is the second most significant byte of the clock
		multiplier value
 
	11	CM3	- Clock Multiplier byte 3 	(RW)
		this is the most significant byte of the multiplier value
 
	12	FC	- Fifo control register		(RW)
		this register doesnt' do anything in the simpleUart
		but is reserved for compatibility with the more
		advanced uart
 
	13-14	reserved registers
 
	15	SPR	- scratch pad register (RW)
 
 
   	+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	|WISHBONE Datasheet
	|WISHBONE SoC Architecture Specification, Revision B.3
	|
	|Description:						Specifications:
	+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	|General Description:				simple UART core
	+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	|Supported Cycles:					SLAVE,READ/WRITE
	|									SLAVE,BLOCK READ/WRITE
	|									SLAVE,RMW
	+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	|Data port, size:					8 bit
	|Data port, granularity:			8 bit
	|Data port, maximum operand size:	8 bit
	|Data transfer ordering:			Undefined
	|Data transfer sequencing:			Undefined
	+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	|Clock frequency constraints:		none
	+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	|Supported signal list and			Signal Name		WISHBONE equiv.
	|cross reference to equivalent		ack_o			ACK_O
	|WISHBONE signals					adr_i[3:0]		ADR_I()
	|									clk_i			CLK_I
	|                                   rst_i           RST_I()
	|									dat_i(7:0)		DAT_I()
	|									dat_o(7:0)		DAT_O()
	|									cyc_i			CYC_I
	|									stb_i			STB_I
	|									we_i			WE_I
	|
	+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	|Special requirements:
	+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
 
	Ref. Spartan3 -4
	117 LUTs / 87 slices / 133 MHz
============================================================================ */
 
`define UART_TRB    4'd0    // transmit/receive buffer
`define UART_LS     4'd1    // line status register
`define UART_MS     4'd2    // modem status register
`define UART_IS		4'd3	// interrupt status register
`define UART_IER    4'd4    // interrupt enable
`define UART_FF     4'd5    // frame format register
`define UART_MC     4'd6    // modem control register
`define UART_CTRL	4'd7	// control register
`define UART_CLKM0	4'd8	// clock multiplier byte 0
`define UART_CLKM1	4'd9	// clock multiplier byte 1
`define UART_CLKM2	4'd10	// clock multiplier byte 2
`define UART_CLKM3	4'd11	// clock multiplier byte 3
`define UART_FC     4'd12   // fifo control register
 
module rtfSimpleUart(
	// WISHBONE Slave interface
	input rst_i,		// reset
	input clk_i,		// eg 100.7MHz
	input cyc_i,		// cycle valid
	input stb_i,		// strobe
	input we_i,			// 1 = write
	input [31:0] adr_i,		// register address
	input [7:0] dat_i,		// data input bus
	output reg [7:0] dat_o,	// data output bus
	output ack_o,		// transfer acknowledge
	output vol_o,		// volatile register selected
	output irq_o,		// interrupt request
	//----------------
	input cts_ni,		// clear to send - active low - (flow control)
	output reg rts_no,	// request to send - active low - (flow control)
	input dsr_ni,		// data set ready - active low
	input dcd_ni,		// data carrier detect - active low
	output reg dtr_no,	// data terminal ready - active low
	input rxd_i,			// serial data in
	output txd_o,			// serial data out
	output data_present_o
);
parameter pClkFreq = 20000000;	// clock frequency in MHz
parameter pBaud = 19200;
parameter pClkMul = (4096 * pBaud) / (pClkFreq / 65536);
parameter pRts = 1;		// default to active
parameter pDtr = 1;
 
wire cs = cyc_i && stb_i && (adr_i[31:4]==28'hFFDC_0A0);
assign ack_o = cs;
assign vol_o = cs && adr_i[3:2]==2'b00;
 
//-------------------------------------------
// variables
reg [23:0] c;	// current count
reg [23:0] ck_mul;	// baud rate clock multiplier
wire tx_empty;
wire baud16;	// edge detector (active one cycle only!)
reg rx_present_ie;
reg tx_empty_ie;
reg dcd_ie;
reg hwfc;			// hardware flow control enable
wire clear = cyc_i && stb_i && we_i && adr_i==4'd13;
wire frame_err;		// receiver char framing error
wire over_run;		// receiver over run
reg [1:0] ctsx;		// cts_ni sampling
reg [1:0] dcdx;
reg [1:0] dsrx;
wire dcd_chg = dcdx[1]^dcdx[0];
 
 
wire rxIRQ = data_present_o & rx_present_ie;
wire txIRQ = tx_empty & tx_empty_ie;
wire msIRQ = dcd_chg & dcd_ie;
 
assign irq_o = 
	  rxIRQ
	| txIRQ
	| msIRQ
	;
 
wire [2:0] irqenc =
	rxIRQ ? 1 :
	txIRQ ? 3 :
	msIRQ ? 4 :
	0;
 
wire [7:0] rx_do;
wire txrx = cs && adr_i[3:0]==4'd0;
 
rtfSimpleUartRx uart_rx0(
	.rst_i(rst_i),
	.clk_i(clk_i),
	.cyc_i(cyc_i),
	.stb_i(stb_i),
	.cs_i(txrx),
	.we_i(we_i),
	.dat_o(rx_do),
	.baud16x_ce(baud16),
	.clear(clear),
	.rxd(rxd_i),
	.data_present(data_present_o),
	.frame_err(frame_err),
	.overrun(over_run)
);
 
rtfSimpleUartTx uart_tx0(
	.rst_i(rst_i),
	.clk_i(clk_i),
	.cyc_i(cyc_i),
	.stb_i(stb_i),
	.cs_i(txrx),
	.we_i(we_i),
	.dat_i(dat_i),
	.baud16x_ce(baud16),
	.cts(ctsx[1]|~hwfc),
	.txd(txd_o),
	.empty(tx_empty)
);
 
// mux the reg outputs
always @*
	if (cs) begin
		case(adr_i[3:0])	// synopsys full_case parallel_case
		`UART_MS:	dat_o <= {dcdx[1],1'b0,dsrx[1],ctsx[1],dcd_chg,3'b0};
		`UART_IS:	dat_o <= {irq_o, 2'b0, irqenc, 2'b0};
		`UART_LS:	dat_o <= {1'b0, tx_empty, tx_empty, 1'b0, frame_err, 1'b0, over_run, data_present_o};
		default:	dat_o <= rx_do;
		endcase
	end
	else
		dat_o <= 8'b0;
 
// Note: baud clock should pulse high for only a single
// cycle!
always @(posedge clk_i)
	if (rst_i)
		c <= 0;
	else
		c <= c + ck_mul;
 
// for detecting an edge on the msb
edge_det ed0(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(c[23]), .pe(baud16), .ne(), .ee() );
 
// register updates
always @(posedge clk_i) begin
	if (rst_i) begin
		rts_no <= ~pRts;
		rx_present_ie <= 1'b0;
		tx_empty_ie <= 1'b0;
		dcd_ie <= 1'b0;
		hwfc <= 1'b1;
		dtr_no <= ~pDtr;
		ck_mul <= pClkMul;
	end
	else if (cs & we_i) begin
		case (adr_i)
		`UART_IER:
				begin
				rx_present_ie <= dat_i[0];
				tx_empty_ie <= dat_i[1];
				dcd_ie <= dat_i[3];
				end
		`UART_MC:
				begin
				dtr_no <= ~dat_i[0];
				rts_no <= ~dat_i[1];
				end
		`UART_CTRL:		hwfc <= dat_i[0];
		`UART_CLKM1:	ck_mul[7:0] <= dat_i;
		`UART_CLKM2:	ck_mul[15:8] <= dat_i;
		`UART_CLKM3:	ck_mul[23:16] <= dat_i;
		default:
			;
		endcase
	end
end
 
 
// synchronize external signals
always @(posedge clk_i)
	ctsx <= {ctsx[0],~cts_ni};
 
always @(posedge clk_i)
	dcdx <= {dcdx[0],~dcd_ni};
 
always @(posedge clk_i)
	dsrx <= {dsrx[0],~dsr_ni};
 
endmodule
 
 

Go to most recent revision | 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.