mirror of
https://github.com/MPSU/APS.git
synced 2025-09-15 17:20:10 +00:00
243 lines
6.9 KiB
Systemverilog
243 lines
6.9 KiB
Systemverilog
// Copyright 2017 ETH Zurich and University of Bologna.
|
|
// Copyright and related rights are licensed under the Solderpad Hardware
|
|
// License, Version 0.51 (the “License”); you may not use this file except in
|
|
// compliance with the License. You may obtain a copy of the License at
|
|
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
|
|
// or agreed to in writing, software, hardware and materials distributed under
|
|
// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
|
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations under the License.
|
|
|
|
// This file has been taken from https://github.com/pulp-platform/apb_uart_sv
|
|
// and modified by Andrei Solodovnikov in order to be used in
|
|
// Architectures of Processor Systems (APS) lab work project
|
|
|
|
// Changelog:
|
|
// some of the input signals has been hardcoded to constant values
|
|
// cfg_div_i input has been replaced by baudrate_i input signal.
|
|
// The signal cfg_div_i is now controled by baudrate_i input, and this control
|
|
// logic is work from assumption that clk_i is 10 MHz.
|
|
|
|
module uart_tx (
|
|
input logic clk_i,
|
|
input logic rst_i,
|
|
output logic tx_o,
|
|
output logic busy_o,
|
|
input logic [16:0] baudrate_i,
|
|
input logic parity_en_i,
|
|
input logic stopbit_i,
|
|
input logic [7:0] tx_data_i,
|
|
input logic tx_valid_i
|
|
//, input logic cfg_en_i,
|
|
// input logic [15:0] cfg_div_i,
|
|
// input logic cfg_parity_en_i,
|
|
// input logic [1:0] cfg_bits_i,
|
|
// input logic stopbit_i,
|
|
// output logic tx_ready_o
|
|
);
|
|
logic rstn_i;
|
|
logic cfg_en_i;
|
|
logic [1:0] cfg_bits_i;
|
|
logic [15:0] cfg_div_i;
|
|
logic tx_ready_o;
|
|
assign rstn_i = !rst_i;
|
|
assign cfg_en_i = 1'b1;
|
|
assign cfg_bits_i = 2'd3;
|
|
always_comb begin
|
|
case(baudrate_i)
|
|
17'd9600 : cfg_div_i = 15'd1041;
|
|
17'd19200 : cfg_div_i = 15'd520;
|
|
17'd38400 : cfg_div_i = 15'd259;
|
|
17'd57600 : cfg_div_i = 15'd173;
|
|
17'd115200: cfg_div_i = 15'd86;
|
|
default : cfg_div_i = 15'd1041;
|
|
endcase
|
|
end
|
|
enum logic [2:0] {IDLE,START_BIT,DATA,PARITY,STOP_BIT_FIRST,STOP_BIT_LAST} CS,NS;
|
|
|
|
logic [7:0] reg_data;
|
|
logic [7:0] reg_data_next;
|
|
|
|
|
|
logic [2:0] reg_bit_count;
|
|
logic [2:0] reg_bit_count_next;
|
|
|
|
logic [2:0] s_target_bits;
|
|
|
|
logic parity_bit;
|
|
logic parity_bit_next;
|
|
|
|
logic sampleData;
|
|
|
|
logic [15:0] baud_cnt;
|
|
logic baudgen_en;
|
|
logic bit_done;
|
|
|
|
assign busy_o = (CS != IDLE);
|
|
|
|
always_comb
|
|
begin
|
|
case(cfg_bits_i)
|
|
2'b00:
|
|
s_target_bits = 3'h4;
|
|
2'b01:
|
|
s_target_bits = 3'h5;
|
|
2'b10:
|
|
s_target_bits = 3'h6;
|
|
2'b11:
|
|
s_target_bits = 3'h7;
|
|
endcase
|
|
end
|
|
|
|
always_comb
|
|
begin
|
|
NS = CS;
|
|
tx_o = 1'b1;
|
|
sampleData = 1'b0;
|
|
reg_bit_count_next = reg_bit_count;
|
|
reg_data_next = {1'b1,reg_data[7:1]};
|
|
tx_ready_o = 1'b0;
|
|
baudgen_en = 1'b0;
|
|
parity_bit_next = parity_bit;
|
|
case(CS)
|
|
IDLE:
|
|
begin
|
|
if (cfg_en_i)
|
|
tx_ready_o = 1'b1;
|
|
if (tx_valid_i)
|
|
begin
|
|
NS = START_BIT;
|
|
sampleData = 1'b1;
|
|
reg_data_next = tx_data_i;
|
|
end
|
|
end
|
|
|
|
START_BIT:
|
|
begin
|
|
tx_o = 1'b0;
|
|
parity_bit_next = 1'b0;
|
|
baudgen_en = 1'b1;
|
|
if (bit_done)
|
|
NS = DATA;
|
|
end
|
|
|
|
DATA:
|
|
begin
|
|
tx_o = reg_data[0];
|
|
baudgen_en = 1'b1;
|
|
parity_bit_next = parity_bit ^ reg_data[0];
|
|
if (bit_done)
|
|
begin
|
|
if (reg_bit_count == s_target_bits)
|
|
begin
|
|
reg_bit_count_next = 'h0;
|
|
if (parity_en_i)
|
|
begin
|
|
NS = PARITY;
|
|
end
|
|
else
|
|
begin
|
|
NS = STOP_BIT_FIRST;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
reg_bit_count_next = reg_bit_count + 1;
|
|
sampleData = 1'b1;
|
|
end
|
|
end
|
|
end
|
|
|
|
PARITY:
|
|
begin
|
|
tx_o = parity_bit;
|
|
baudgen_en = 1'b1;
|
|
if (bit_done)
|
|
NS = STOP_BIT_FIRST;
|
|
end
|
|
STOP_BIT_FIRST:
|
|
begin
|
|
tx_o = 1'b1;
|
|
baudgen_en = 1'b1;
|
|
if (bit_done)
|
|
begin
|
|
if (stopbit_i)
|
|
NS = STOP_BIT_LAST;
|
|
else
|
|
NS = IDLE;
|
|
end
|
|
end
|
|
STOP_BIT_LAST:
|
|
begin
|
|
tx_o = 1'b1;
|
|
baudgen_en = 1'b1;
|
|
if (bit_done)
|
|
begin
|
|
NS = IDLE;
|
|
end
|
|
end
|
|
default:
|
|
NS = IDLE;
|
|
endcase
|
|
end
|
|
|
|
always_ff @(posedge clk_i or negedge rstn_i)
|
|
begin
|
|
if (rstn_i == 1'b0)
|
|
begin
|
|
CS <= IDLE;
|
|
reg_data <= 8'hFF;
|
|
reg_bit_count <= 'h0;
|
|
parity_bit <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
if(bit_done)
|
|
begin
|
|
parity_bit <= parity_bit_next;
|
|
end
|
|
|
|
if(sampleData)
|
|
begin
|
|
reg_data <= reg_data_next;
|
|
end
|
|
|
|
reg_bit_count <= reg_bit_count_next;
|
|
if(cfg_en_i)
|
|
CS <= NS;
|
|
else
|
|
CS <= IDLE;
|
|
end
|
|
end
|
|
|
|
always_ff @(posedge clk_i or negedge rstn_i)
|
|
begin
|
|
if (rstn_i == 1'b0)
|
|
begin
|
|
baud_cnt <= 'h0;
|
|
bit_done <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
if(baudgen_en)
|
|
begin
|
|
if(baud_cnt == cfg_div_i)
|
|
begin
|
|
baud_cnt <= 'h0;
|
|
bit_done <= 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
baud_cnt <= baud_cnt + 1;
|
|
bit_done <= 1'b0;
|
|
end
|
|
end
|
|
else
|
|
begin
|
|
baud_cnt <= 'h0;
|
|
bit_done <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
endmodule |