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

Subversion Repositories attiny_atmega_xmega_core

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /attiny_atmega_xmega_core
    from Rev 5 to Rev 6
    Reverse comparison

Rev 5 → Rev 6

/trunk/io/uart_s.v
0,0 → 1,476
/*
* This IP is a simple paralel IO adapter implementation.
*
* Copyright (C) 2018 Iulian Gheorghiu
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
 
`timescale 1ns / 1ps
 
`include "io_s_h.v"
 
module uart_s #(
parameter BAUDRATE_COUNTER_LENGTH = 12,
parameter DINAMIC_BAUDRATE = "TRUE",
parameter BAUDRATE_DIVIDER = 19200,
parameter ADDRESS = 0,
parameter BUS_ADDR_DATA_LEN = 16
)(
input rst,
input clk,
input [BUS_ADDR_DATA_LEN-1:0]addr,
input wr,
input rd,
input [7:0]bus_in,
output reg[7:0]bus_out,
output int_rx_rcv,
output int_tx_compl,
output int_tx_buff_empty,
inout int_rst,
inout rtx_clk,
output reg tx,
input rx
);
 
localparam [6:0]MAX_WORD_LEN = 9;
 
localparam state_idle = 1'b0;
localparam state_busy = 1'b1;
 
reg [7:0]DATA_in;
reg [7:0]DATA_out;
reg [7:0]STATUS;
reg [7:0]CTRLA;
reg [7:0]CTRLB;
reg [7:0]CTRLC;
reg [7:0]BAUDCTRLA;
reg [7:0]BAUDCTRLB;
reg [7:0]BAUDCTRLB_tmp_read;
reg [7:0]BAUDCTRLB_tmp_write;
 
wire cs_int = addr >= ADDRESS && addr < (ADDRESS + 16);
wire rd_int = cs_int && rd;
wire wr_int = cs_int && wr;
 
reg [BAUDRATE_COUNTER_LENGTH == 0 ? 0 : BAUDRATE_COUNTER_LENGTH - 1:0]baud_cnt;
 
reg receiveoverrunp;
reg receiveoverrunn;
wire receiveoverrunpn;
 
reg [2:0]rxbitcntstate;
 
reg charreceivedp;
reg charreceivedn;
 
reg state_rx;
reg state_tx;
reg [(MAX_WORD_LEN - 1) + 4:0]shift_reg_in;
reg [(MAX_WORD_LEN - 1) + 4:0]shift_reg_out;
//reg [MAX_WORD_LEN - 1:0]temp_output_buffer;
reg [7:0]sckint_rx;
//reg [3:0]bitcount_rx;
reg [3:0]total_word_len_rx;
 
wire _chk_int;
wire chk_int;
reg [(MAX_WORD_LEN - 1) + 4:0]parity_mask;
wire [(MAX_WORD_LEN - 1) + 4:0]valid_data;
wire parity_bit;
reg [3:0]wordlen;
 
reg inbufffullp;
reg inbufffulln;
 
reg last_state_rxp;
reg last_state_rxn;
wire rx_start_detected;
 
reg [3:0]sckint_tx;
reg [3:0]bitcount_tx;
reg [3:0]total_word_len_tx;
 
wire buffempty = ~(inbufffullp ^ inbufffulln);
reg [11:0]prescallerbuff;
 
reg int_tx_compl_int;
reg int_tx_buff_empty_int;
assign int_tx_compl = CTRLB[`USART_TXEN_bp] ? int_tx_compl_int : 1'b0;
assign int_tx_buff_empty = CTRLB[`USART_TXEN_bp] ? int_tx_buff_empty_int : 1'b0;
reg int_rx_rcv_int;
assign int_rx_rcv = CTRLB[`USART_RXEN_bp] ? int_rx_rcv_int : 1'b0;
 
wire [15:0]static_baudrate = {BAUDCTRLB, BAUDCTRLA};
 
always @ (posedge rd_int or posedge rst)
begin
if(rst)
begin
charreceivedn <= 1'b0;
receiveoverrunp <= 1'b0;
end
else if(rd_int)
begin
case(addr[3:0])
`USART_DATA:
begin
if(charreceivedp != charreceivedn)
charreceivedn <= ~charreceivedn;
if(receiveoverrunn != receiveoverrunp)
receiveoverrunp <= ~receiveoverrunp;
end
endcase
end
end
 
always @ (*)
begin
if(rst)
begin
BAUDCTRLB_tmp_read <= 'h0;
end
else if(rd_int)
begin
case(addr[3:0])
`USART_DATA: bus_out <= DATA_out;
`USART_STATUS: bus_out <= STATUS;
`USART_CTRLA: bus_out <= CTRLA;
`USART_CTRLB: bus_out <= CTRLB;
`USART_CTRLC: bus_out <= CTRLC;
`USART_BAUDCTRLA:
begin
if(DINAMIC_BAUDRATE == "TRUE")
begin
bus_out <= BAUDCTRLA;
BAUDCTRLB_tmp_read <= BAUDCTRLB;
end
else
begin
bus_out <= static_baudrate[7:0];
end
end
`USART_BAUDCTRLB:
begin
if(DINAMIC_BAUDRATE == "TRUE")
bus_out <= BAUDCTRLB_tmp_read;
else
bus_out <= static_baudrate[15:8];
end
default: bus_out <= 8'bz;
endcase
end
else
begin
bus_out <= 8'bz;
end
end
 
 
always @ (*)
begin
case(CTRLC[`USART_CHSIZE_gp + 2:`USART_CHSIZE_gp])
3'h00: wordlen <= 12'd5;
3'h01: wordlen <= 12'd6;
3'h02: wordlen <= 12'd7;
3'h03: wordlen <= 12'd8;
3'h07: wordlen <= 12'd9;
default: wordlen <= 12'd8;
endcase
end
 
always @ (*)
begin
case(wordlen)
4'h05: parity_mask <= 12'b000000111110;
4'h06: parity_mask <= 12'b000001111110;
4'h07: parity_mask <= 12'b000011111110;
4'h09: parity_mask <= 12'b001111111110;
default: parity_mask <= 12'b000111111110;
endcase
end
assign valid_data = shift_reg_in & parity_mask;
assign _chk_int = ^valid_data;
assign chk_int = (CTRLC[`USART_CMODE_gp + 1:`USART_CMODE_gp] == 2'b10) ? ~_chk_int:_chk_int;
assign parity_bit = (shift_reg_in & (1 << wordlen + 1)) ? 1:0;
 
always @ (negedge rx or posedge rst)
begin
if(rst)
last_state_rxn <= 0;
else
begin
if(last_state_rxn == last_state_rxp)
begin
last_state_rxn <= ~last_state_rxp;
end
end
end
 
assign rx_start_detected = (last_state_rxn ^ last_state_rxp);
 
always @ (posedge clk or posedge rst)
begin
if(rst)
begin
baud_cnt = 'h00;
charreceivedn <= 1'b0;
inbufffullp <= 1'b0;
inbufffulln <= 1'b0;
DATA_in <= 'h0;
STATUS <= 'h0;
CTRLA <= 'h0;
CTRLB <= 'h0;
CTRLC <= `USART_CHSIZE_8BIT_gc;
BAUDCTRLA <= 'h0;
BAUDCTRLB <= 'h0;
BAUDCTRLB_tmp_write <= 'h0;
last_state_rxp <= 'h0;
state_rx <= state_idle;
state_tx <= state_idle;
shift_reg_in <= 'h0;
sckint_rx <= 'h0;
charreceivedp <= 'h0;
receiveoverrunn <= 'h0;
rxbitcntstate <= 'h0;
total_word_len_rx <= 'h0;
int_rx_rcv_int <= 'h0;
int_tx_compl_int <= 'h0;
int_tx_buff_empty_int <= 'h0;
tx <= 1'b1;
end
else
begin
STATUS[`USART_DREIF_bp] <= buffempty;
/*
* Read from IO logic
*/
if(wr_int)
begin
case(addr[3:0])
`USART_STATUS: STATUS <= STATUS ^ bus_in;
`USART_CTRLA: CTRLA <= bus_in;
`USART_CTRLB: CTRLB <= bus_in;
`USART_CTRLC: CTRLC <= bus_in;
`USART_BAUDCTRLA:
begin
if(DINAMIC_BAUDRATE == "TRUE")
begin
BAUDCTRLA <= bus_in;
BAUDCTRLB <= BAUDCTRLB_tmp_write;
end
end
`USART_BAUDCTRLB:
begin
if(DINAMIC_BAUDRATE == "TRUE")
begin
BAUDCTRLB_tmp_write <= bus_in;
end
end
`USART_DATA:
begin
if(inbufffullp == inbufffulln && buffempty && CTRLB[`USART_TXEN_bp])
begin
inbufffullp <= ~inbufffullp;
prescallerbuff <= {BAUDCTRLB[3:0], BAUDCTRLA};
DATA_in <= bus_in;
int_tx_compl_int <= 1'b0;
int_tx_buff_empty_int <= 'h0;
end
end
endcase
end
if(rd_int)
begin
case(addr[3:0])
`USART_DATA: int_rx_rcv_int <= 1'b0;
endcase
end
if(DINAMIC_BAUDRATE == "TRUE" ? baud_cnt == prescallerbuff : baud_cnt == {BAUDRATE_DIVIDER})
begin
baud_cnt <= 'h00;
if(CTRLB[`USART_RXEN_bp])
begin
/*
* Rx logic
*/
if(state_rx == state_idle)
begin
// Wait for a transition from hi to low that indicate a start condition.
if(rx_start_detected)
begin
shift_reg_in <= 0;
sckint_rx <= 0;
rxbitcntstate <= 7;
// Calculate the total number of bits to receive including end.
total_word_len_rx <= CTRLC[`USART_CMODE_gp + 1:`USART_CMODE_gp] ? 1 : 0 + 1 + CTRLC[`USART_SBMODE_bp] + wordlen;
state_rx <= state_busy;
end
end
else
begin
case(sckint_rx[3:0])
7,8,9:
begin
rxbitcntstate <= rxbitcntstate + (rx ? 3'd7 : 3'd1);
sckint_rx <= sckint_rx + 1;
end
10:
begin
if(sckint_rx[7:4] == total_word_len_rx)// If is stop bit check-it and out the received data.
begin
// Verify stop bit to be valid, else report a frame error.
STATUS[`USART_FERR_bp] <= ~rxbitcntstate[2];
// Verify the parity bit
if(CTRLC[`USART_CMODE_gp + 1:`USART_CMODE_gp])
STATUS[`USART_PERR_bp] <= parity_bit ^ chk_int;
else
STATUS[`USART_PERR_bp] <= 'h0;
// Put data from shift register to output data register.
{STATUS[`USART_RXB8_bp], DATA_out} <= valid_data[9:1];
// Check if the previous received data has been read from output register, if not report a overrun situation..
if(charreceivedn == charreceivedp)
charreceivedp <= ~charreceivedp;
else
begin
if(receiveoverrunn == receiveoverrunp)
receiveoverrunn <= ~receiveoverrunn;
end
if(CTRLA[`USART_RXCINTLVL_gp + 1 : `USART_RXCINTLVL_gp])
begin
int_rx_rcv_int <= 1'b1;
end
state_rx <= state_idle;
sckint_rx <= 0;
last_state_rxp <= last_state_rxn;
end
else
begin
shift_reg_in[sckint_rx[7:4]] <= rxbitcntstate[2];
sckint_rx <= sckint_rx + 1;
end
end
15:
begin
rxbitcntstate <= 7;
sckint_rx <= sckint_rx + 1;
end
default:
begin
sckint_rx <= sckint_rx + 1;
end
endcase
end
end
else
begin
int_rx_rcv_int <= 'h0;
end
/*
* Tx logic
*/
if(CTRLB[`USART_TXEN_bp])
begin
case(state_tx)
state_idle:
begin
if(inbufffullp != inbufffulln)
begin
inbufffulln <= ~inbufffulln;
sckint_tx <= 5'h01;
int_tx_compl_int <= 1'b0;
if(CTRLA[`USART_DREINTLVL_gc + 1 : `USART_DREINTLVL_gc])
begin
int_tx_buff_empty_int <= 'h1;
end
case({CTRLC[`USART_PMODE_gp + 1 : `USART_PMODE_gp], CTRLC[`USART_SBMODE_bp], wordlen})
{2'b00, 4'h05}: shift_reg_out <= {1'b1, DATA_in[4:0], 1'h0};
{2'b00, 4'h06}: shift_reg_out <= {1'b1, DATA_in[5:0], 1'h0};
{2'b00, 4'h07}: shift_reg_out <= {1'b1, DATA_in[6:0], 1'h0};
{2'b00, 4'h08}: shift_reg_out <= {1'b1, DATA_in, 1'h0};
{2'b00, 4'h09}: shift_reg_out <= {1'b1, CTRLB[`USART_TXB8_bp], DATA_in, 1'h0};
{2'b01, 4'h05}: shift_reg_out <= {2'b11, DATA_in[4:0], 1'h0};
{2'b01, 4'h06}: shift_reg_out <= {2'b11, DATA_in[5:0], 1'h0};
{2'b01, 4'h07}: shift_reg_out <= {2'b11, DATA_in[6:0], 1'h0};
{2'b01, 4'h08}: shift_reg_out <= {2'b11, DATA_in, 1'h0};
{2'b01, 4'h09}: shift_reg_out <= {2'b11, CTRLB[`USART_TXB8_bp], DATA_in, 1'h0};
{2'b10, 4'h05}: shift_reg_out <= {1'b1, chk_int, DATA_in[4:0], 1'h0};
{2'b10, 4'h06}: shift_reg_out <= {1'b1, chk_int, DATA_in[5:0], 1'h0};
{2'b10, 4'h07}: shift_reg_out <= {1'b1, chk_int, DATA_in[6:0], 1'h0};
{2'b10, 4'h08}: shift_reg_out <= {1'b1, chk_int, DATA_in, 1'h0};
{2'b10, 4'h09}: shift_reg_out <= {1'b1, chk_int, CTRLB[`USART_TXB8_bp], DATA_in, 1'h0};
{2'b11, 4'h05}:shift_reg_out <= {2'b11, chk_int, DATA_in[4:0], 1'h0};
{2'b11, 4'h06}:shift_reg_out <= {2'b11, chk_int, DATA_in[5:0], 1'h0};
{2'b11, 4'h07}:shift_reg_out <= {2'b11, chk_int, DATA_in[6:0], 1'h0};
{2'b11, 4'h08}:shift_reg_out <= {2'b11, chk_int, DATA_in, 1'h0};
{2'b11, 4'h09}:shift_reg_out <= {2'b11, chk_int, CTRLB[`USART_TXB8_bp], DATA_in, 1'h0};
default: shift_reg_out <= {1'b1, DATA_in[7:0], 1'h0};
endcase
bitcount_tx <= 4'b0000;
total_word_len_tx <= CTRLC[`USART_PMODE_gp + 1:`USART_PMODE_gp] ? 1 : 0 + 1 + CTRLC[`USART_SBMODE_bp] + wordlen + 1;
state_tx <= state_busy;
/*Put start, first bit from shift_reg_out*/
tx <= 1'b0;
end
end
state_busy:
begin
case(sckint_tx)
4'h0D:
begin
sckint_tx <= sckint_tx + 1;
bitcount_tx <= bitcount_tx + 'b0001;
end
4'h0E:
begin
if(bitcount_tx == total_word_len_tx)
begin
state_tx <= state_idle;
if(CTRLA[`USART_TXCINTLVL_gp + 1 : `USART_TXCINTLVL_gp])
begin
int_tx_compl_int <= 1'b1;
end
end
sckint_tx <= sckint_tx + 1;
end
4'h0F:
begin
sckint_tx <= sckint_tx + 1;
tx <= shift_reg_out[bitcount_tx];
end
default:
begin
sckint_tx <= sckint_tx + 1;
end
endcase
end
endcase
end
else
begin
int_tx_compl_int <= 'h0;
int_tx_buff_empty_int <= 'h0;
end
end
else
begin
baud_cnt <= baud_cnt + 1;
end
end
end
 
 
endmodule

powered by: WebSVN 2.1.0

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