From cb47213025cb38a11ee2bbc3e2617b53ff762f84 Mon Sep 17 00:00:00 2001 From: agamemnon Date: Tue, 18 Jul 2023 18:06:14 +0300 Subject: [PATCH 1/7] [rtl] removed original uart.sv file and added my uart implementation for customizable parameters --- rtl/system/async_fifo.v | 97 +++++++++++ rtl/system/sync_fifo.v | 56 +++++++ rtl/system/synchronizer.v | 26 +++ rtl/system/uart.sv | 321 ------------------------------------ rtl/system/uart.vh | 14 ++ rtl/system/uart_rx.v | 125 ++++++++++++++ rtl/system/uart_top.v | 336 ++++++++++++++++++++++++++++++++++++++ rtl/system/uart_tx.v | 73 +++++++++ 8 files changed, 727 insertions(+), 321 deletions(-) create mode 100644 rtl/system/async_fifo.v create mode 100644 rtl/system/sync_fifo.v create mode 100644 rtl/system/synchronizer.v delete mode 100644 rtl/system/uart.sv create mode 100644 rtl/system/uart.vh create mode 100644 rtl/system/uart_rx.v create mode 100644 rtl/system/uart_top.v create mode 100644 rtl/system/uart_tx.v diff --git a/rtl/system/async_fifo.v b/rtl/system/async_fifo.v new file mode 100644 index 00000000..867073e2 --- /dev/null +++ b/rtl/system/async_fifo.v @@ -0,0 +1,97 @@ +`include "synchronizer.v" +`timescale 1ns/1ps + +module async_fifo #( + parameter WIDTH = 32, // width of data bus + parameter DEPTH = 16 // depth of FIFO buffer +) ( + input wire [WIDTH-1:0] wdata_i, + input wire wclk_i, + input wire rclk_i, + input wire rst_ni, + input wire we_i, + input wire re_i, + output wire [WIDTH-1:0] rdata_o, + output wire full_o, + output wire empty_o +); + +localparam ADDR_BITS = $clog2(DEPTH); // address width for buffer + +reg [ADDR_BITS:0] w_ptr, r_ptr; +wire [ADDR_BITS:0] w_ptr_gray, r_ptr_gray; + +wire [ADDR_BITS:0] w_ptr_next, r_ptr_next; +wire [ADDR_BITS:0] w_ptr_next_gray, r_ptr_next_gray; + +wire [ADDR_BITS-1:0] w_addr, r_addr; + +wire [ADDR_BITS:0] w_ptr_sync_gray, r_ptr_sync_gray; +reg [ADDR_BITS:0] w_ptr_sync_bin, r_ptr_sync_bin; + +reg [WIDTH-1:0] mem [0:DEPTH-1]; + +assign w_ptr_next = (we_i & ~full_o)? w_ptr + 1'b1 : w_ptr; +assign r_ptr_next = (re_i & ~empty_o)? r_ptr + 1'b1 : r_ptr; + +assign w_addr = w_ptr[ADDR_BITS-1:0]; +assign r_addr = r_ptr[ADDR_BITS-1:0]; + +assign w_ptr_gray = w_ptr ^ (w_ptr >> 1); +assign r_ptr_gray = r_ptr ^ (r_ptr >> 1); + +assign w_ptr_next_gray = w_ptr_next ^ (w_ptr_next >> 1); +assign r_ptr_next_gray = r_ptr_next ^ (r_ptr_next >> 1); + +ff2_sync #( + .WIDTH(ADDR_BITS+1) +) sync_w2r_w_ptr ( + .clk_i(rclk_i), + .rst_ni(rst_ni), + .wdata_i(w_ptr_gray), + .rdata_o(w_ptr_sync_gray) +); + +ff2_sync #( + .WIDTH(ADDR_BITS+1) +) sync_r2w_r_ptr ( + .clk_i(wclk_i), + .rst_ni(rst_ni), + .wdata_i(r_ptr_gray), + .rdata_o(r_ptr_sync_gray) +); + +integer i; +always @(*) begin : gray_to_bin_w_ptr + for(i=0; i> i); +end + +always @(*) begin : gray_to_bin_r_ptr + for(i=0; i> i); +end + +always @(posedge wclk_i, negedge rst_ni) + if(~rst_ni) + w_ptr <= 0; + else + w_ptr <= w_ptr_next; + +always @(posedge wclk_i) begin : write + if(we_i & ~full_o) + mem[w_addr] <= wdata_i; +end + +always @(posedge rclk_i, negedge rst_ni) begin : read + if(~rst_ni) + r_ptr <= 0; + else + r_ptr <= r_ptr_next; +end + +assign full_o = w_ptr == {~r_ptr_sync_bin[ADDR_BITS], r_ptr_sync_bin[ADDR_BITS-1:0]}; +assign empty_o = r_ptr == w_ptr_sync_bin; +assign rdata_o = mem[r_addr]; + +endmodule \ No newline at end of file diff --git a/rtl/system/sync_fifo.v b/rtl/system/sync_fifo.v new file mode 100644 index 00000000..8fd5f973 --- /dev/null +++ b/rtl/system/sync_fifo.v @@ -0,0 +1,56 @@ +`timescale 1ns/1ps + +module sync_fifo #( + parameter WIDTH = 32, + parameter DEPTH = 128 +) ( + input wire clk_i, + input wire rst_ni, + input wire [WIDTH-1:0] wdata_i, + input wire we_i, + input wire re_i, + output wire [WIDTH-1:0] rdata_o, + output wire full_o, + output wire empty_o +); + +localparam ADDR_BITS = $clog2(DEPTH); // address width for buffer + +reg [ADDR_BITS:0] w_ptr, r_ptr; +wire [ADDR_BITS:0] w_ptr_next, r_ptr_next; + +wire [ADDR_BITS-1:0] w_addr, r_addr; + +wire full_next, empty_next; + +reg [WIDTH-1:0] mem [0:DEPTH-1]; + +assign w_ptr_next = (~full_o & we_i)? w_ptr + 1'b1 : w_ptr; +assign r_ptr_next = (~empty_o & re_i)? r_ptr + 1'b1 : r_ptr; + +assign full_o = r_ptr == {~w_ptr[ADDR_BITS], w_ptr[ADDR_BITS-1:0]}; +assign empty_o = r_ptr == w_ptr; + +assign rdata_o = mem[r_addr]; + +assign w_addr = w_ptr[ADDR_BITS-1:0]; +assign r_addr = r_ptr[ADDR_BITS-1:0]; + +always @(posedge clk_i, negedge rst_ni) begin + if(~rst_ni) begin + w_ptr <= 0; + r_ptr <= 0; + end + else begin + w_ptr <= w_ptr_next; + r_ptr <= r_ptr_next; + end +end + +always @(posedge clk_i) begin + if(we_i & ~full_o) begin + mem[w_addr] <= wdata_i; + end +end + +endmodule \ No newline at end of file diff --git a/rtl/system/synchronizer.v b/rtl/system/synchronizer.v new file mode 100644 index 00000000..09e85fe1 --- /dev/null +++ b/rtl/system/synchronizer.v @@ -0,0 +1,26 @@ +/* +* 2 DFF sync clock domain crossing +* for async fifo queue +*/ +`timescale 1ns/1ps + +module ff2_sync #( + parameter WIDTH = 32 +) ( + input wire clk_i, + input wire rst_ni, + input wire [WIDTH-1:0] wdata_i, + output reg [WIDTH-1:0] rdata_o +); + +reg [WIDTH-1:0] p0; + +always @(posedge clk_i, negedge rst_ni) + if(~rst_ni) begin + p0 <= 0; + rdata_o <= 0; + end + else + {rdata_o, p0} <= {p0, wdata_i}; + +endmodule \ No newline at end of file diff --git a/rtl/system/uart.sv b/rtl/system/uart.sv deleted file mode 100644 index 4c99e1b7..00000000 --- a/rtl/system/uart.sv +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - -module uart #( - parameter int unsigned ClockFrequency = 50_000_000, - parameter int unsigned BaudRate = 115_200, - parameter int unsigned RxFifoDepth = 128, - parameter int unsigned TxFifoDepth = 128 -) ( - input logic clk_i, - input logic rst_ni, - - input logic device_req_i, - /* verilator lint_off UNUSED */ - input logic [31:0] device_addr_i, - input logic device_we_i, - input logic [3:0] device_be_i, - input logic [31:0] device_wdata_i, - output logic device_rvalid_o, - output logic [31:0] device_rdata_o, - - input logic uart_rx_i, - output logic uart_irq_o, - output logic uart_tx_o -); - - localparam int unsigned ClocksPerBaud = ClockFrequency / BaudRate; - /* verilator lint_off WIDTH */ - localparam int unsigned UART_RX_REG = 32'h0; - /* verilator lint_off WIDTH */ - localparam int unsigned UART_TX_REG = 32'h4; - /* verilator lint_off WIDTH */ - localparam int unsigned UART_STATUS_REG = 32'h8; - - typedef enum logic[1:0] { - IDLE, - START, - PROC, - STOP - } uart_state_t; - - logic [31:0] device_rdata_d, device_rdata_q; - logic device_rvalid_d, device_rvalid_q; - - logic [11:0] reg_addr; - - logic [$clog2(ClocksPerBaud)-1:0] rx_baud_counter_q, rx_baud_counter_d; - logic rx_baud_tick; - - uart_state_t rx_state_q, rx_state_d; - logic [2:0] rx_bit_counter_q, rx_bit_counter_d; - logic [7:0] rx_current_byte_q, rx_current_byte_d; - logic [2:0] rx_q; - logic rx_start, rx_valid; - - logic rx_fifo_wvalid; - logic rx_fifo_rready; - logic [7:0] rx_fifo_rdata; - logic rx_fifo_rvalid; - logic rx_fifo_empty; - - logic [$clog2(ClocksPerBaud)-1:0] tx_baud_counter_q, tx_baud_counter_d; - logic tx_baud_tick; - - logic write_req; - - uart_state_t tx_state_q, tx_state_d; - logic [2:0] tx_bit_counter_q, tx_bit_counter_d; - logic [7:0] tx_current_byte_q, tx_current_byte_d; - logic tx_next_byte; - - logic tx_fifo_wvalid; - logic tx_fifo_rvalid, tx_fifo_rready; - logic [7:0] tx_fifo_rdata; - logic tx_fifo_full; - - assign reg_addr = device_addr_i[11:0]; - - always_comb begin - device_rdata_d = '0; - device_rvalid_d = 1'b0; - rx_fifo_rready = 1'b0; - - if (device_req_i) begin - device_rvalid_d = 1'b1; - - if (device_be_i[0] & ~device_we_i) begin - case (reg_addr) - UART_RX_REG: begin - device_rdata_d = {24'b0, rx_fifo_rdata}; - rx_fifo_rready = 1'b1; - end - UART_TX_REG: begin - device_rdata_d = '0; - end - UART_STATUS_REG: begin - device_rdata_d = {30'b0, tx_fifo_full, rx_fifo_empty}; - end - default: begin - device_rdata_d = '0; - end - endcase - end - end - end - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - device_rdata_q <= '0; - device_rvalid_q <= 1'b0; - end else begin - device_rdata_q <= device_rdata_d; - device_rvalid_q <= device_rvalid_d; - end - end - - assign device_rdata_o = device_rdata_q; - assign device_rvalid_o = device_rvalid_q; - - assign rx_fifo_wvalid = rx_baud_tick & rx_valid; - assign rx_fifo_empty = ~rx_fifo_rvalid; - - // Set the rx_baud_counter half-way on rx_start to ensure sampling the bits 'in the middle' - assign rx_baud_counter_d = rx_baud_tick ? '0 : - rx_start ? $bits(rx_baud_counter_q)'(ClocksPerBaud >> 1) : - rx_baud_counter_q + 1'b1; - - assign rx_baud_tick = rx_baud_counter_q == $bits(rx_baud_counter_q)'(ClocksPerBaud - 1); - - prim_fifo_sync #( - .Width(8), - .Pass (1'b0), - .Depth(RxFifoDepth) - ) u_rx_fifo ( - .clk_i, - .rst_ni, - .clr_i (1'b0), - - .wvalid_i(rx_fifo_wvalid), - .wready_o(), - .wdata_i (rx_current_byte_q), - - .rvalid_o(rx_fifo_rvalid), - .rready_i(rx_fifo_rready), - .rdata_o (rx_fifo_rdata), - - .full_o (), - .depth_o(), - .err_o () - ); - - assign uart_irq_o = !rx_fifo_empty; - - // Synchronize RX and derive rx_start signal - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - rx_q <= '0; - end else begin - rx_q <= {rx_q[1:0], uart_rx_i}; - end - end - - assign rx_start = !rx_q[1] & rx_q[2] & (rx_state_q == IDLE); - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - rx_baud_counter_q <= '0; - end else begin - rx_baud_counter_q <= rx_baud_counter_d; - end - end - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - rx_state_q <= IDLE; - rx_bit_counter_q <= '0; - rx_current_byte_q <= '0; - // Transition the rx state on both rx_start and an rx_baud_tick - end else if (rx_start || rx_baud_tick) begin - rx_state_q <= rx_state_d; - rx_bit_counter_q <= rx_bit_counter_d; - rx_current_byte_q <= rx_current_byte_d; - end - end - - always_comb begin - rx_valid = 0; - rx_bit_counter_d = rx_bit_counter_q; - rx_current_byte_d = rx_current_byte_q; - rx_state_d = rx_state_q; - - case (rx_state_q) - IDLE: begin - - if (rx_start) begin - rx_state_d = START; - end - end - START: begin - rx_current_byte_d = '0; - rx_bit_counter_d = '0; - - if (!rx_q[2]) begin - rx_state_d = PROC; - end else begin - rx_state_d = IDLE; - end - end - PROC: begin - rx_current_byte_d = {rx_q[2], rx_current_byte_q[7:1]}; - - if (rx_bit_counter_q == 3'd7) begin - rx_state_d = STOP; - end else begin - rx_bit_counter_d = rx_bit_counter_q + 3'd1; - end - end - STOP: begin - if (rx_q[2]) begin - rx_valid = 1; - end - rx_state_d = IDLE; - end - endcase - end - - assign write_req = (device_req_i & device_be_i[0] & device_we_i); - - assign tx_fifo_wvalid = (reg_addr == UART_TX_REG) & write_req; - assign tx_fifo_rready = tx_baud_tick & tx_next_byte; - - assign tx_baud_counter_d = tx_baud_tick ? '0 : tx_baud_counter_q + 1'b1; - assign tx_baud_tick = tx_baud_counter_q == $bits(tx_baud_counter_q)'(ClocksPerBaud - 1); - - prim_fifo_sync #( - .Width(8), - .Pass (1'b0), - .Depth(TxFifoDepth) - ) u_tx_fifo ( - .clk_i, - .rst_ni, - .clr_i (1'b0), - - .wvalid_i(tx_fifo_wvalid), - .wready_o(), - .wdata_i (device_wdata_i[7:0]), - - .rvalid_o(tx_fifo_rvalid), - .rready_i(tx_fifo_rready), - .rdata_o (tx_fifo_rdata), - - .full_o (tx_fifo_full), - .depth_o(), - .err_o () - ); - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - tx_baud_counter_q <= '0; - end else begin - tx_baud_counter_q <= tx_baud_counter_d; - end - end - - always_ff @(posedge clk_i or negedge rst_ni) begin - if (!rst_ni) begin - tx_state_q <= IDLE; - tx_bit_counter_q <= '0; - tx_current_byte_q <= '0; - end else if (tx_baud_tick) begin - tx_state_q <= tx_state_d; - tx_bit_counter_q <= tx_bit_counter_d; - tx_current_byte_q <= tx_current_byte_d; - end - end - - always_comb begin - uart_tx_o = 1'b0; - tx_bit_counter_d = tx_bit_counter_q; - tx_current_byte_d = tx_current_byte_q; - tx_next_byte = 1'b0; - tx_state_d = tx_state_q; - - case (tx_state_q) - IDLE: begin - uart_tx_o = 1'b1; - - if (tx_fifo_rvalid) begin - tx_state_d = START; - end - end - START: begin - uart_tx_o = 1'b0; - tx_state_d = PROC; - tx_bit_counter_d = 3'd0; - tx_current_byte_d = tx_fifo_rdata; - tx_next_byte = 1'b1; - end - PROC: begin - uart_tx_o = tx_current_byte_q[0]; - - tx_current_byte_d = {1'b0, tx_current_byte_q[7:1]}; - if (tx_bit_counter_q == 3'd7) begin - tx_state_d = STOP; - end else begin - tx_bit_counter_d = tx_bit_counter_q + 3'd1; - end - end - STOP: begin - uart_tx_o = 1'b1; - if (tx_fifo_rvalid) begin - tx_state_d = START; - end else begin - tx_state_d = IDLE; - end - end - endcase - end - -endmodule diff --git a/rtl/system/uart.vh b/rtl/system/uart.vh new file mode 100644 index 00000000..6104969f --- /dev/null +++ b/rtl/system/uart.vh @@ -0,0 +1,14 @@ +`ifndef UART +`define UART + +`timescale 1ns/1ps + +`include "sync_fifo.v" +`include "async_fifo.v" +`include "uart_rx.v" +`include "uart_tx.v" + +// If need be to use asynchronous FIFOs, uncomment. +//`define ASYNC + +`endif \ No newline at end of file diff --git a/rtl/system/uart_rx.v b/rtl/system/uart_rx.v new file mode 100644 index 00000000..67b67fba --- /dev/null +++ b/rtl/system/uart_rx.v @@ -0,0 +1,125 @@ +`timescale 1ns/1ps + +module uart_rx ( + input wire clk_i, + input wire clk_en_i, + input wire rst_ni, + input wire en, + input wire rx_i, + input wire [3:0] data_size_i, + input wire parity_size_i, + input wire parity_type_i, + input wire [1:0] stop_size_i, + output wire [8:0] data_o, + output wire rx_rdy_o, + output wire rx_err_o, + output wire [1:0] rx_state_o +); + +localparam IDLE = 0; +localparam DATA = 1; +localparam PARITY = 2; +localparam STOP = 3; + +reg [3:0] data_counter; +reg [3:0] data_size; +reg parity_counter; +reg parity_size; +reg [1:0] stop_counter; +reg [1:0] stop_size; +reg [8:0] data_buf; +reg parity_buf; +reg parity_type; +reg [1:0] stop_buf; +reg [1:0] state; +reg [1:0] next_state; + +reg [8:0] data_d; +reg rx_rdy_d; +reg rx_err_d; + +always @(*) begin + case(data_size) + 6 : data_d <= {3'b0, data_buf[8:3]}; + 7 : data_d <= {2'b0, data_buf[8:2]}; + 8 : data_d <= {1'b0, data_buf[8:1]}; + 9 : data_d <= data_buf; + default : data_d <= data_buf; + endcase +end + +always @(*) begin + case(state) + IDLE : begin + rx_rdy_d <= 1'b0; + rx_err_d <= 1'b0; + end + DATA : begin + rx_rdy_d <= rx_rdy_d; + rx_err_d <= rx_err_d; + end + PARITY : begin + rx_rdy_d <= rx_rdy_d; + rx_err_d <= rx_err_d; + end + STOP : begin + rx_rdy_d <= ~|stop_counter; + rx_err_d <= (|parity_size) & ((^{data_buf, parity_buf} & ~parity_type) | + (~^{data_buf, parity_buf} & parity_type)); + end + endcase +end + +always @(posedge clk_i, negedge rst_ni) begin + if(~rst_ni) begin + state <= IDLE; + end + else if(clk_en_i) begin + state <= next_state; + case(state) + IDLE : begin + data_counter <= data_size_i - 1; + parity_counter <= parity_size_i - 1; + stop_counter <= stop_size_i - 1; + + data_size <= data_size_i; + parity_size <= parity_size_i; + parity_type <= parity_type_i; + stop_size <= stop_size_i; + + data_buf <= 0; + parity_buf <= 0; + stop_buf <= 0; + end + DATA : begin + data_counter <= data_counter - 1; + data_buf <= {rx_i, data_buf[8:1]}; + end + PARITY : begin + parity_counter <= parity_counter - 1; + parity_buf <= rx_i; + end + STOP : begin + stop_counter <= stop_counter - 1; + stop_buf <= {rx_i, stop_buf[1]}; + end + endcase + end +end + +always @ (*) begin + case(state) + IDLE : next_state <= (~rx_i & en)? DATA : IDLE; + DATA : next_state <= (|data_counter)? DATA : (|(parity_size))? PARITY : STOP; + PARITY : next_state <= (|parity_counter)? PARITY : STOP; + STOP : next_state <= (|stop_counter)? STOP : IDLE; + default : next_state <= IDLE; + endcase +end + +assign data_o = data_d; +assign rx_rdy_o = rx_rdy_d; +assign rx_err_o = rx_err_d; +assign rx_state_o = state; + +endmodule \ No newline at end of file diff --git a/rtl/system/uart_top.v b/rtl/system/uart_top.v new file mode 100644 index 00000000..0970cc20 --- /dev/null +++ b/rtl/system/uart_top.v @@ -0,0 +1,336 @@ +`include "uart.vh" +module uart_top #( + parameter CLOCK_FREQUENCY = 50_000_000, + parameter RX_FIFO_DEPTH = 128, + parameter TX_FIFO_DEPTH = 128 +) ( + input wire clk_i, // core clock +`ifdef ASYNC + input wire clk_M_i, // master clock +`endif + input wire rst_ni, // reset not + input wire we, // write enable + input wire [3:0] be, // byte enable + input wire [31:0] uart_wdata_i, // data bus + input wire [31:0] addr_i, // addr bus + input wire uart_req_i, // request from core (IBEX LSU) + input wire uart_rx_i, // rx line + output wire uart_tx_o, // tx line + output wire [31:0] uart_rdata_o,// data bus + output wire uart_req_gnt_o, // request granted to core (IBEX LSU) + output wire uart_rvalid_o, // request valid to core (IBEX LSU) + output wire uart_irq_o, // interrupt request (CSR) + output wire uart_err_o // error to core (IBEX LSU) +); + +reg [31:0] uart_rdata_q, uart_rdata_d; +reg uart_rvalid_q, uart_rvalid_d; +reg uart_err_q, uart_err_d; + +localparam [31:0] INSTRUCTION_SIZE = 5; // size of instruction in bits +localparam [INSTRUCTION_SIZE-1:0] OP_WRITE_UART_PARAMETERS = 5'b10000; // set protocol parameters +localparam [INSTRUCTION_SIZE-1:0] OP_WRITE_UART_EN = 5'b01000; // write data from bus to enable or diable rx/tx sub-modules +localparam [INSTRUCTION_SIZE-1:0] OP_READ_UART_STATE = 5'b00100; // read uart module state +localparam [INSTRUCTION_SIZE-1:0] OP_WRITE_UART_DATA = 5'b00010; // write data from bus to FIFO tx queue +localparam [INSTRUCTION_SIZE-1:0] OP_READ_UART_DATA = 5'b00001; // read data from FIFO rx queue +localparam [INSTRUCTION_SIZE-1:0] OP_DO_NOTHING = 5'b00000; // do nothing +reg [INSTRUCTION_SIZE-1:0] opcode; // instruction to execute + +reg [3:0] data_size; // data size in bits of protocol +reg parity_size; // parity of protocol (0 or 1 parity bits) +reg parity_type; // parity type of protocol (ODD (1) or EVEN (0)) +reg [1:0] stop_size; // stop size in bits of protocol (1 or 2) +reg [31:0] baud_rate; // baud rate of protocol (default 9600) + +wire [8:0] rx_data; // data received from serial +wire rx_rdy; // ready flag +wire rx_err; // error flag +reg rx_en; // enable register of rx module +wire [1:0] rx_state; // rx state machine status +wire rx_start; // rx start signal (stability improvment) +reg [2:0] rx_buf; // rx buffer + +wire rx_fq_re; // rx FIFO read enable +wire rx_fq_we; // rx FIFO write enable +wire [8:0] rx_fq_data_out; // rx FIFO data output +wire rx_fq_full; // rx FIFO is full flag +wire rx_fq_empty; // rx FIFO is empty flag + +wire tx_rdy; // ready flag +reg tx_en; // enable register of tx module +wire tx_state; // tx state machine status +wire tx_start; + +wire tx_fq_re; // tx FIFO queue read enable +wire tx_fq_we; // tx FIFO queue write enable +wire [8:0] tx_fq_data_out; // tx FIFO data output (to transmit) +wire tx_fq_full; // tx FIFO is full flag +wire tx_fq_empty; // tx FIFO is empty flag + +reg [31:0] rx_tick_counter; +reg rx_clk_en; +reg [31:0] tx_tick_counter; +reg tx_clk_en; + +uart_rx rx0 ( +`ifndef ASYNC + .clk_i(clk_i), // clock +`else + .clk_i(clk_M_i), // clock +`endif + .clk_en_i(rx_clk_en), // clock enable + .rst_ni(rst_ni), // negative reset signal + .en(rx_en), // rx enable + .rx_i(rx_buf[0]), // rx pin + .data_size_i(data_size), // data size (payload) + .parity_size_i(parity_size), // parity bit + .parity_type_i(parity_type), // parity type + .stop_size_i(stop_size), // stop bits size + .data_o(rx_data), // data out (received data) + .rx_rdy_o(rx_rdy), // received new data flag + .rx_err_o(rx_err), // parity mismatch flag + .rx_state_o(rx_state) +); + +`ifndef ASYNC +// Synchronous FIFO queue for rx module +sync_fifo #( + .WIDTH(9), // width of data bus + .DEPTH(RX_FIFO_DEPTH) // depth of FIFO buffer +) rx_sync_fifo ( + .clk_i(clk_i), // input clock + .rst_ni(rst_ni), // reset signal + .wdata_i(rx_data), // input data + .we_i(rx_fq_we), // write enable signal + .re_i(rx_fq_re), // read enable signal + .rdata_o(rx_fq_data_out), // output data + .full_o(rx_fq_full), // full flag + .empty_o(rx_fq_empty) // empty flag +); +`else +// Asynchronous FIFO queue for rx module +async_fifo #( + .WIDTH(9), + .DEPTH(RX_FIFO_DEPTH) +) rx_async_fifo ( + .wclk_i(clk_M_i), + .rst_ni(rst_ni), + .wdata_i(rx_data), + .rclk_i(clk_i), + .we_i(rx_fq_we), + .re_i(rx_fq_re), + .rdata_o(rx_fq_data_out), + .full_o(rx_fq_full), + .empty_o(rx_fq_empty) +); +`endif + + +uart_tx tx0 ( +`ifndef ASYNC + .clk_i(clk_i), // clock +`else + .clk_i(clk_M_i), // clock +`endif + .clk_en_i(tx_clk_en), // clock enable + .rst_ni(rst_ni), // negative reset signal + .en(tx_en), // tx enable + .tx_start_i(tx_start), // start transmission flag + .data_size_i(data_size), // payload size + .parity_size_i(parity_size), // parity bit size + .parity_type_i(parity_type), // type of parity + .stop_size_i(stop_size), // stop bits size + .data_i(tx_fq_data_out), // data to transmit + .tx_o(uart_tx_o), // tx wire + .tx_rdy_o(tx_rdy), // module is ready flag + .tx_state_o(tx_state) +); + +`ifndef ASYNC +// Synchronous FIFO queue for tx module +sync_fifo #( + .WIDTH(9), // width of data bus + .DEPTH(TX_FIFO_DEPTH) // depth of FIFO buffer +) tx_sync_fifo ( + .clk_i(clk_i), // input clock + .rst_ni(rst_ni), // reset signal + .wdata_i(uart_wdata_i[8:0]), // input data + .we_i(tx_fq_we), // write enable signal + .re_i(tx_fq_re), // read enable signal + .rdata_o(tx_fq_data_out), // output data + .full_o(tx_fq_full), // full flag + .empty_o(tx_fq_empty) // empty flag +); +`else +// Asynchronous FIFO queue for tx module +async_fifo #( + .WIDTH(9), + .DEPTH(TX_FIFO_DEPTH) +) tx_async_fifo ( + .wclk_i(clk_i), + .rst_ni(rst_ni), + .wdata_i(uart_wdata_i[8:0]), + .rclk_i(clk_M_i), + .we_i(tx_fq_we), + .re_i(tx_fq_re), + .rdata_o(tx_fq_data_out), + .full_o(tx_fq_full), + .empty_o(tx_fq_empty) +); +`endif + +assign rx_start = rx_buf[2] & ~rx_buf[1] & ~rx_buf[0] & rx_state == rx0.IDLE; + +assign tx_start = ~tx_fq_empty; +assign tx_fq_we = (opcode == OP_WRITE_UART_DATA) & tx_en ; +assign tx_fq_re = tx_rdy & tx_en & tx_clk_en; +assign rx_fq_we = rx_rdy & ~rx_err & rx_clk_en; +assign rx_fq_re = (opcode == OP_READ_UART_DATA) & rx_en; + +assign uart_irq_o = ~rx_fq_empty; + +always +`ifndef ASYNC + @(posedge clk_i, negedge rst_ni) +`else + @(posedge clk_M_i, negedge rst_ni) +`endif +begin + if(~rst_ni) begin + rx_buf <= 3'b111; + end + else begin + rx_buf <= {rx_buf[1:0], uart_rx_i}; + end +end + +always +`ifndef ASYNC + @(posedge clk_i, negedge rst_ni) +`else + @(posedge clk_M_i, negedge rst_ni) +`endif begin + if(~rst_ni) begin + rx_tick_counter <= 32'b0; + rx_clk_en <= 1'b0; + end + else begin + rx_tick_counter <= (rx_clk_en)? 32'b0 : (rx_start)? baud_rate >> 1 : rx_tick_counter + 1'b1; + rx_clk_en <= (rx_tick_counter == (baud_rate - 1'b1)); + end +end + + +always +`ifndef ASYNC + @(posedge clk_i, negedge rst_ni) +`else + @(posedge clk_M_i, negedge rst_ni) +`endif +begin + if(~rst_ni) begin + tx_tick_counter <= 32'b0; + tx_clk_en <= 1'b0; + end + else begin + tx_tick_counter <= (tx_clk_en)? 32'b0 : tx_tick_counter + 1'b1; + tx_clk_en <= (tx_tick_counter == (baud_rate - 1'b1)); + end +end + + +always @(*) begin + if(uart_req_i) + case(addr_i[7:0]) + 8'h00 : opcode <= (~we)? OP_READ_UART_DATA : OP_DO_NOTHING; + 8'h04 : opcode <= (we)? OP_WRITE_UART_DATA : OP_DO_NOTHING; + 8'h08 : opcode <= (~we)? OP_READ_UART_STATE : OP_DO_NOTHING; + 8'h0c : opcode <= (we)? OP_WRITE_UART_EN : OP_DO_NOTHING; + 8'h10 : opcode <= (we)? OP_WRITE_UART_PARAMETERS : OP_DO_NOTHING; + default : opcode <= OP_DO_NOTHING; + endcase + else + opcode <= OP_DO_NOTHING; +end + +always @(*) begin + uart_err_d = 1'b0; + uart_rvalid_d = 1'b1; + case(opcode) + OP_WRITE_UART_PARAMETERS : begin + uart_rdata_d <= 32'b0; + end + OP_READ_UART_DATA : begin + uart_rdata_d <= {23'b0, rx_fq_data_out}; + end + OP_WRITE_UART_DATA : begin + uart_rdata_d <= 32'b0; + end + OP_READ_UART_STATE : begin + uart_rdata_d <= {30'b0, tx_fq_full, rx_fq_empty}; + end + OP_WRITE_UART_EN : begin + uart_rdata_d <= 32'b0; + end + default : begin + uart_rdata_d <= 32'b0; + end + endcase +end + +always @(posedge clk_i, negedge rst_ni) begin + if(~rst_ni) begin + uart_rdata_q <= 32'b0; + uart_rvalid_q <= 1'b0; + uart_err_q <= 1'b0; + end + else begin + uart_rdata_q <= uart_rdata_d; + uart_rvalid_q <= uart_rvalid_d; + uart_err_q <= uart_err_d; + end +end + +always @(posedge clk_i, negedge rst_ni) begin + if(~rst_ni) begin + baud_rate <= CLOCK_FREQUENCY / 9600; + data_size <= 4'h8; + parity_size <= 1'b0; + parity_type <= 1'b0; + stop_size <= 2'b01; + rx_en <= 1'b0; + tx_en <= 1'b0; + end + else begin + case(opcode) + OP_WRITE_UART_PARAMETERS : begin + case(uart_wdata_i[1:0]) + 2'b00 : data_size <= 4'h6; + 2'b01 : data_size <= 4'h7; + 2'b10 : data_size <= 4'h8; + 2'b11 : data_size <= 4'h9; + endcase + parity_size <= uart_wdata_i[2]; + parity_type <= uart_wdata_i[3]; + stop_size <= (uart_wdata_i[4])? 2'b10 : 2'b01; + case(uart_wdata_i[6:5]) + 2'b00 : baud_rate <= CLOCK_FREQUENCY / 4800; + 2'b01 : baud_rate <= CLOCK_FREQUENCY / 9600; + 2'b10 : baud_rate <= CLOCK_FREQUENCY / 57600; + 2'b11 : baud_rate <= CLOCK_FREQUENCY / 115200; + endcase + end + OP_WRITE_UART_EN : begin + {tx_en, rx_en} <= uart_wdata_i[1:0]; + end + default : begin + end + endcase + end +end + +assign uart_rdata_o = uart_rdata_q; +assign uart_rvalid_o = uart_rvalid_q; +assign uart_err_o = uart_err_q; + +endmodule \ No newline at end of file diff --git a/rtl/system/uart_tx.v b/rtl/system/uart_tx.v new file mode 100644 index 00000000..a37a6b6a --- /dev/null +++ b/rtl/system/uart_tx.v @@ -0,0 +1,73 @@ +`timescale 1ns/1ps + +module uart_tx ( + input wire clk_i, + input wire clk_en_i, + input wire rst_ni, + input wire en, + input wire tx_start_i, + input wire [3:0] data_size_i, + input wire parity_size_i, + input wire parity_type_i, + input wire [1:0] stop_size_i, + input wire [8:0] data_i, + output wire tx_o, + output wire tx_rdy_o, + output wire tx_state_o +); + +localparam IDLE = 0; // Waiting to send data +localparam WRITE = 1; // Transmitting frame + +reg [3:0] frame_counter; +reg [12:0] frame_buffer; +reg state; +reg next_state; + +always @ (posedge clk_i, negedge rst_ni) begin + if(~rst_ni) begin + state <= IDLE; + end + else if(clk_en_i) begin + state <= next_state; + case(state) + IDLE : begin + // Size of frame in bits + frame_counter <= stop_size_i + parity_size_i + data_size_i + 1 + 1; + // if none parity just fill with logic 1 + // else calculate appropriate parity + case(data_size_i) + 6 : begin + frame_buffer <= {4'b1111, (~|parity_size_i)? 1'b1 : (parity_type_i)? ^data_i : ~^data_i, data_i[5:0], 2'b01}; + end + 7 : begin + frame_buffer <= {3'b111, (~|parity_size_i)? 1'b1 : (parity_type_i)? ^data_i : ~^data_i, data_i[6:0], 2'b01}; + end + 8 : begin + frame_buffer <= {2'b11, (~|parity_size_i)? 1'b1 : (parity_type_i)? ^data_i : ~^data_i, data_i[7:0], 2'b01}; + end + default : begin + frame_buffer <= {1'b1, (~|parity_size_i)? 1'b1 : (parity_type_i)? ^data_i : ~^data_i, data_i, 2'b01}; + end + endcase + end + WRITE : begin + frame_counter <= frame_counter - 1; + frame_buffer <= {1'b1, frame_buffer[12:1]}; + end + endcase + end +end + +always @(*) + case(state) + IDLE : next_state <= (tx_start_i & en)? WRITE : IDLE; + WRITE : next_state <= (~|frame_counter)? IDLE : WRITE; + default : next_state <= IDLE; + endcase + +assign tx_rdy_o = (state == IDLE); +assign tx_o = (state == WRITE)? frame_buffer[0] : 1'b1; +assign tx_state_o = state; + +endmodule From 66d920ba7b233ac081b403f3f9a489572141d0bb Mon Sep 17 00:00:00 2001 From: agamemnon Date: Tue, 18 Jul 2023 18:07:29 +0300 Subject: [PATCH 2/7] [core] edited the .core files to include my verilog file to compile process --- ibex_demo_system.core | 3 +-- ibex_demo_system_core.core | 8 +++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ibex_demo_system.core b/ibex_demo_system.core index dc54e386..e5e29c8d 100644 --- a/ibex_demo_system.core +++ b/ibex_demo_system.core @@ -107,8 +107,7 @@ targets: toplevel: top_cw305 tools: vivado: - part: "xc7a100tftg256-2" # default to a100 part - #part: "xc7a35tftg256-2" # a35 option + part: "xc7a35tftg256-2" # a35 option parameters: - SRAMInitFile - PRIM_DEFAULT_IMPL=prim_pkg::ImplXilinx diff --git a/ibex_demo_system_core.core b/ibex_demo_system_core.core index bca488ee..da14cc6f 100644 --- a/ibex_demo_system_core.core +++ b/ibex_demo_system_core.core @@ -16,7 +16,13 @@ filesets: - rtl/system/gpio.sv - rtl/system/pwm.sv - rtl/system/pwm_wrapper.sv - - rtl/system/uart.sv + - rtl/system/uart_top.v + - rtl/system/uart_rx.v + - rtl/system/uart_tx.v + - rtl/system/sync_fifo.v + - rtl/system/async_fifo.v + - rtl/system/uart.vh + - rtl/system/synchronizer.v - rtl/system/spi_host.sv - rtl/system/spi_top.sv file_type: systemVerilogSource From 7d9ad0995fd95b41eff673aadbfd554e67932d66 Mon Sep 17 00:00:00 2001 From: agamemnon Date: Tue, 18 Jul 2023 18:11:52 +0300 Subject: [PATCH 3/7] [sw] edited common header files to support configurable uart parameters and updated the hello world program to demonstrate it --- sw/c/common/demo_system.c | 1 - sw/c/common/demo_system.h | 2 +- sw/c/common/link.ld | 76 ++++++++++++++++++++++++++++++++++++ sw/c/common/uart.c | 19 +++++++-- sw/c/common/uart.h | 39 ++++++++++++++---- sw/c/demo/hello_world/main.c | 50 ++++++++---------------- 6 files changed, 140 insertions(+), 47 deletions(-) create mode 100644 sw/c/common/link.ld diff --git a/sw/c/common/demo_system.c b/sw/c/common/demo_system.c index ab7c4ff4..784ed70a 100644 --- a/sw/c/common/demo_system.c +++ b/sw/c/common/demo_system.c @@ -138,4 +138,3 @@ void simple_exc_handler(void) { while(1); } - diff --git a/sw/c/common/demo_system.h b/sw/c/common/demo_system.h index d2518b4a..e88ffab7 100644 --- a/sw/c/common/demo_system.h +++ b/sw/c/common/demo_system.h @@ -112,4 +112,4 @@ uint32_t get_mcycle(void); void reset_mcycle(void); -#endif +#endif \ No newline at end of file diff --git a/sw/c/common/link.ld b/sw/c/common/link.ld new file mode 100644 index 00000000..1260f249 --- /dev/null +++ b/sw/c/common/link.ld @@ -0,0 +1,76 @@ +/* Copyright lowRISC contributors. + Licensed under the Apache License, Version 2.0, see LICENSE for details. + SPDX-License-Identifier: Apache-2.0 */ + +OUTPUT_ARCH(riscv) + +MEMORY +{ + /* 60 KiB should be enough for anybody... */ + ram : ORIGIN = 0x00100000, LENGTH = 0xE000 /* 56 KiB */ + stack : ORIGIN = 0x0010E000, LENGTH = 0x2000 /* 4 KiB */ +} + +/* Stack information variables */ +_min_stack = 0x1000; /* 4K - minimum stack space to reserve */ +_stack_len = LENGTH(stack); +_stack_start = ORIGIN(stack) + LENGTH(stack); + +_entry_point = _vectors_start + 0x80; +ENTRY(_entry_point) + +SECTIONS +{ + .text : { + . = ALIGN(4); + _vectors_start = .; + KEEP(*(.vectors)) + _vectors_end = .; + *(.text) + *(.text.*) + . = ALIGN(4); + } > ram + + .rodata : { + . = ALIGN(4); + /* Small RO data before large RO data */ + *(.srodata) + *(.srodata.*) + *(.rodata); + *(.rodata.*) + . = ALIGN(4); + } > ram + + .data : { + . = ALIGN(4); + /* Small data before large data */ + *(.sdata) + *(.sdata.*) + *(.data); + *(.data.*) + . = ALIGN(4); + } > ram + + .bss : + { + . = ALIGN(4); + _bss_start = .; + /* Small BSS before large BSS */ + *(.sbss) + *(.sbss.*) + *(.bss) + *(.bss.*) + *(COMMON) + _bss_end = .; + . = ALIGN(4); + } > ram + + /* ensure there is enough room for stack */ + .stack (NOLOAD): { + . = ALIGN(4); + . = . + _min_stack ; + . = ALIGN(4); + stack = . ; + _stack = . ; + } > stack +} diff --git a/sw/c/common/uart.c b/sw/c/common/uart.c index 19edf7ef..b387bc46 100644 --- a/sw/c/common/uart.c +++ b/sw/c/common/uart.c @@ -1,7 +1,3 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - #include "uart.h" #include "dev_access.h" #include "demo_system.h" @@ -26,3 +22,18 @@ void uart_out(uart_t uart, char c) { DEV_WRITE(uart + UART_TX_REG, c); } + +void uart_enable(uart_t uart, char en) { + + DEV_WRITE(uart + UART_ENABLE_REG, en); +} + +void uart_disable(uart_t uart) { + + DEV_WRITE(uart + UART_ENABLE_REG, 0x00); +} + +void uart_setup(uart_t uart, char parameters) { + + DEV_WRITE(uart + UART_PARAMETERS_REG, parameters); +} \ No newline at end of file diff --git a/sw/c/common/uart.h b/sw/c/common/uart.h index ac2578f6..6197275d 100644 --- a/sw/c/common/uart.h +++ b/sw/c/common/uart.h @@ -1,13 +1,13 @@ -// Copyright lowRISC contributors. -// Licensed under the Apache License, Version 2.0, see LICENSE for details. -// SPDX-License-Identifier: Apache-2.0 - #ifndef UART_H__ #define UART_H__ -#define UART_RX_REG 0 -#define UART_TX_REG 4 -#define UART_STATUS_REG 8 +#include + +#define UART_RX_REG 0x00 +#define UART_TX_REG 0x04 +#define UART_STATUS_REG 0x08 +#define UART_ENABLE_REG 0x0C +#define UART_PARAMETERS_REG 0x10 #define UART_STATUS_RX_EMPTY 1 #define UART_STATUS_TX_FULL 2 @@ -18,9 +18,32 @@ typedef void* uart_t; #define UART_FROM_BASE_ADDR(addr)((uart_t)(addr)) +#define DATA_SIZE_6 0x00 +#define DATA_SIZE_7 0x01 +#define DATA_SIZE_8 0x02 +#define DATA_SIZE_9 0x03 + +#define PARITY_NONE 0x00 +#define PARITY_EVEN 0x04 +#define PARITY_ODD 0x0C + +#define STOP_BITS_ONE 0x00 +#define STOP_BITS_TWO 0x10 + +#define BAUD_RATE_4800 0x00 +#define BAUD_RATE_9600 0x20 +#define BAUD_RATE_57600 0x40 +#define BAUD_RATE_115200 0x60 + +#define UART_RX_EN 0x01 +#define UART_TX_EN 0x02 + void uart_enable_rx_int(void); int uart_in(uart_t uart); void uart_out(uart_t uart, char c); -#endif // UART_H__ +void uart_enable(uart_t uart, char en); +void uart_disable(uart_t uart); +void uart_setup(uart_t uart, char parameters); +#endif diff --git a/sw/c/demo/hello_world/main.c b/sw/c/demo/hello_world/main.c index 4e612410..87ec2d49 100644 --- a/sw/c/demo/hello_world/main.c +++ b/sw/c/demo/hello_world/main.c @@ -1,30 +1,30 @@ // Copyright lowRISC contributors. // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 - +#include "uart.h" #include "demo_system.h" #include "timer.h" #include "gpio.h" #include "pwm.h" #include +#include #define USE_GPIO_SHIFT_REG 0 void test_uart_irq_handler(void) __attribute__((interrupt)); void test_uart_irq_handler(void) { - int uart_in_char; - - while ((uart_in_char = uart_in(DEFAULT_UART)) != -1) { - uart_out(DEFAULT_UART, uart_in_char); - uart_out(DEFAULT_UART, '\r'); - uart_out(DEFAULT_UART, '\n'); - } + unsigned char u; + u = getchar(); + putchar(u); } int main(void) { install_exception_handler(UART_IRQ_NUM, &test_uart_irq_handler); uart_enable_rx_int(); + + uart_enable(DEFAULT_UART, UART_RX_EN | UART_TX_EN); + uart_setup(DEFAULT_UART, DATA_SIZE_8 | PARITY_NONE | STOP_BITS_ONE | BAUD_RATE_115200); // This indicates how often the timer gets updated. timer_init(); @@ -41,37 +41,21 @@ int main(void) { bool ascending = true; // The three least significant bits correspond to RGB, where B is the leas significant. uint8_t color = 7; - + + const char str[] = " Hello World "; + uint32_t c = 0; while(1) { uint64_t cur_time = get_elapsed_time(); if (cur_time != last_elapsed_time) { last_elapsed_time = cur_time; - - // Disable interrupts whilst outputting to prevent output for RX IRQ - // happening in the middle + set_global_interrupt_enable(0); - - // Print this to UART (use the screen command to see it). - puts("Hello World! "); - puthex(last_elapsed_time); - puts(" Input Value: "); - uint32_t in_val = read_gpio(GPIO_IN_DBNC); - puthex(in_val); - putchar('\n'); - - // Re-enable interrupts with output complete + puts(str); + puthex(c++); + puts("\r\n"); set_global_interrupt_enable(1); - - // Cycling through green LEDs when BTN0 is pressed - if (USE_GPIO_SHIFT_REG) { - set_outputs(GPIO_OUT_SHIFT, in_val); - } else { - uint32_t out_val = read_gpio(GPIO_OUT); - out_val = ((out_val << 1) & GPIO_OUT_MASK) | (in_val & 0x1); - set_outputs(GPIO_OUT, out_val); - } - + // Going from bright to dim on PWM for(int i = 0; i < NUM_PWM_MODULES; i++) { set_pwm(PWM_FROM_ADDR_AND_INDEX(PWM_BASE, i), @@ -94,8 +78,8 @@ int main(void) { } } } + } - asm volatile ("wfi"); } } From b6ee85366216f36d93cf84767b64e220a0d8d2fa Mon Sep 17 00:00:00 2001 From: agamemnon Date: Tue, 18 Jul 2023 20:25:49 +0300 Subject: [PATCH 4/7] [sw c]Deleted link.ld, it was a copy mistake and it shouldn't be there,[core] Restored original ibex_demo_system.core the change was a mistake because of the board I used to load the bitstream --- ibex_demo_system.core | 3 +- sw/c/common/link.ld | 76 ------------------------------------------- 2 files changed, 2 insertions(+), 77 deletions(-) delete mode 100644 sw/c/common/link.ld diff --git a/ibex_demo_system.core b/ibex_demo_system.core index e5e29c8d..dc54e386 100644 --- a/ibex_demo_system.core +++ b/ibex_demo_system.core @@ -107,7 +107,8 @@ targets: toplevel: top_cw305 tools: vivado: - part: "xc7a35tftg256-2" # a35 option + part: "xc7a100tftg256-2" # default to a100 part + #part: "xc7a35tftg256-2" # a35 option parameters: - SRAMInitFile - PRIM_DEFAULT_IMPL=prim_pkg::ImplXilinx diff --git a/sw/c/common/link.ld b/sw/c/common/link.ld deleted file mode 100644 index 1260f249..00000000 --- a/sw/c/common/link.ld +++ /dev/null @@ -1,76 +0,0 @@ -/* Copyright lowRISC contributors. - Licensed under the Apache License, Version 2.0, see LICENSE for details. - SPDX-License-Identifier: Apache-2.0 */ - -OUTPUT_ARCH(riscv) - -MEMORY -{ - /* 60 KiB should be enough for anybody... */ - ram : ORIGIN = 0x00100000, LENGTH = 0xE000 /* 56 KiB */ - stack : ORIGIN = 0x0010E000, LENGTH = 0x2000 /* 4 KiB */ -} - -/* Stack information variables */ -_min_stack = 0x1000; /* 4K - minimum stack space to reserve */ -_stack_len = LENGTH(stack); -_stack_start = ORIGIN(stack) + LENGTH(stack); - -_entry_point = _vectors_start + 0x80; -ENTRY(_entry_point) - -SECTIONS -{ - .text : { - . = ALIGN(4); - _vectors_start = .; - KEEP(*(.vectors)) - _vectors_end = .; - *(.text) - *(.text.*) - . = ALIGN(4); - } > ram - - .rodata : { - . = ALIGN(4); - /* Small RO data before large RO data */ - *(.srodata) - *(.srodata.*) - *(.rodata); - *(.rodata.*) - . = ALIGN(4); - } > ram - - .data : { - . = ALIGN(4); - /* Small data before large data */ - *(.sdata) - *(.sdata.*) - *(.data); - *(.data.*) - . = ALIGN(4); - } > ram - - .bss : - { - . = ALIGN(4); - _bss_start = .; - /* Small BSS before large BSS */ - *(.sbss) - *(.sbss.*) - *(.bss) - *(.bss.*) - *(COMMON) - _bss_end = .; - . = ALIGN(4); - } > ram - - /* ensure there is enough room for stack */ - .stack (NOLOAD): { - . = ALIGN(4); - . = . + _min_stack ; - . = ALIGN(4); - stack = . ; - _stack = . ; - } > stack -} From 0850f841d2280d8805f37631b5e54bb6588ef1c4 Mon Sep 17 00:00:00 2001 From: AgamemnonasKyriazis Date: Sat, 30 Sep 2023 16:20:26 +0300 Subject: [PATCH 5/7] almost full and almost empty condition flags + Almost full flag for rx/tx sync FIFO + Almost empty flag for rx/tx sync FIFO + Almost full interrupt for tx in C + Almost full / empty flag added to read instruction --- rtl/system/async_fifo.v | 20 ++++++---- rtl/system/ibex_demo_system.sv | 38 ++++++++++--------- rtl/system/sync_fifo.v | 23 ++++++++---- rtl/system/synchronizer.v | 3 +- rtl/system/uart.vh | 2 - rtl/system/uart_rx.v | 2 - rtl/system/uart_top.v | 68 +++++++++++++++++++++------------- rtl/system/uart_tx.v | 2 - sw/c/common/demo_system.h | 8 +++- sw/c/common/uart.c | 11 +++++- sw/c/common/uart.h | 8 +++- sw/c/demo/hello_world/main.c | 21 +++++++++-- 12 files changed, 131 insertions(+), 75 deletions(-) diff --git a/rtl/system/async_fifo.v b/rtl/system/async_fifo.v index 867073e2..5f393bb7 100644 --- a/rtl/system/async_fifo.v +++ b/rtl/system/async_fifo.v @@ -1,6 +1,5 @@ `include "synchronizer.v" `timescale 1ns/1ps - module async_fifo #( parameter WIDTH = 32, // width of data bus parameter DEPTH = 16 // depth of FIFO buffer @@ -13,7 +12,9 @@ module async_fifo #( input wire re_i, output wire [WIDTH-1:0] rdata_o, output wire full_o, - output wire empty_o + output wire empty_o, + output wire near_full_o, + output wire near_empty_o ); localparam ADDR_BITS = $clog2(DEPTH); // address width for buffer @@ -43,7 +44,7 @@ assign r_ptr_gray = r_ptr ^ (r_ptr >> 1); assign w_ptr_next_gray = w_ptr_next ^ (w_ptr_next >> 1); assign r_ptr_next_gray = r_ptr_next ^ (r_ptr_next >> 1); -ff2_sync #( +sync_reg #( .WIDTH(ADDR_BITS+1) ) sync_w2r_w_ptr ( .clk_i(rclk_i), @@ -52,7 +53,7 @@ ff2_sync #( .rdata_o(w_ptr_sync_gray) ); -ff2_sync #( +sync_reg #( .WIDTH(ADDR_BITS+1) ) sync_r2w_r_ptr ( .clk_i(wclk_i), @@ -74,24 +75,27 @@ end always @(posedge wclk_i, negedge rst_ni) if(~rst_ni) - w_ptr <= 0; + w_ptr <= {ADDR_BITS+1{1'b0}}; else w_ptr <= w_ptr_next; -always @(posedge wclk_i) begin : write +always @(posedge wclk_i, negedge rst_ni) begin : write if(we_i & ~full_o) mem[w_addr] <= wdata_i; end always @(posedge rclk_i, negedge rst_ni) begin : read if(~rst_ni) - r_ptr <= 0; + r_ptr <= {ADDR_BITS+1{1'b0}}; else r_ptr <= r_ptr_next; end assign full_o = w_ptr == {~r_ptr_sync_bin[ADDR_BITS], r_ptr_sync_bin[ADDR_BITS-1:0]}; assign empty_o = r_ptr == w_ptr_sync_bin; -assign rdata_o = mem[r_addr]; +assign rdata_o = (empty_o)? {WIDTH{1'b0}} : mem[r_addr]; + +assign near_full_o = 1'b0; +assign near_empty_o = 1'b0; endmodule \ No newline at end of file diff --git a/rtl/system/ibex_demo_system.sv b/rtl/system/ibex_demo_system.sv index 167bbf57..82291453 100644 --- a/rtl/system/ibex_demo_system.sv +++ b/rtl/system/ibex_demo_system.sv @@ -88,7 +88,7 @@ module ibex_demo_system #( // interrupts logic timer_irq; - logic uart_irq; + logic [1:0] uart_irq; // host and device signals logic host_req [NrHosts]; @@ -268,7 +268,7 @@ module ibex_demo_system #( .irq_software_i(1'b0), .irq_timer_i (timer_irq), .irq_external_i(1'b0), - .irq_fast_i ({14'b0, uart_irq}), + .irq_fast_i ({13'b0, uart_irq}), .irq_nm_i (1'b0), .scramble_key_valid_i('0), @@ -349,23 +349,25 @@ module ibex_demo_system #( .pwm_o ); - uart #( - .ClockFrequency ( 50_000_000 ) + uart_top #( + .CLOCK_FREQUENCY (50_000_000), + .RX_FIFO_DEPTH (16), + .TX_FIFO_DEPTH (16) ) u_uart ( - .clk_i (clk_sys_i), - .rst_ni (rst_sys_ni), - - .device_req_i (device_req[Uart]), - .device_addr_i (device_addr[Uart]), - .device_we_i (device_we[Uart]), - .device_be_i (device_be[Uart]), - .device_wdata_i (device_wdata[Uart]), - .device_rvalid_o(device_rvalid[Uart]), - .device_rdata_o (device_rdata[Uart]), - - .uart_rx_i, - .uart_irq_o (uart_irq), - .uart_tx_o + .clk_i(clk_sys_i), // clock + .rst_ni(rst_sys_ni), // reset not + .we(device_we[Uart]), // write enable + .be(device_be[Uart]), // byte enable + .uart_wdata_i(device_wdata[Uart]), // data bus + .addr_i(device_addr[Uart]), // addr bus + .uart_req_i(device_req[Uart]), // request from core (IBEX LSU) + .uart_rx_i(uart_rx_i), // rx line + .uart_tx_o(uart_tx_o), // tx line + .uart_rdata_o(device_rdata[Uart]), // data bus + .uart_req_gnt_o(), // request granted to core (IBEX LSU) + .uart_rvalid_o(device_rvalid[Uart]), // request valid to core (IBEX LSU) + .uart_irq_o(uart_irq), // interrupt request (CSR) + .uart_err_o() // error to core (IBEX LSU) ); spi_top #( diff --git a/rtl/system/sync_fifo.v b/rtl/system/sync_fifo.v index 8fd5f973..2e55890e 100644 --- a/rtl/system/sync_fifo.v +++ b/rtl/system/sync_fifo.v @@ -1,5 +1,3 @@ -`timescale 1ns/1ps - module sync_fifo #( parameter WIDTH = 32, parameter DEPTH = 128 @@ -11,12 +9,15 @@ module sync_fifo #( input wire re_i, output wire [WIDTH-1:0] rdata_o, output wire full_o, - output wire empty_o + output wire empty_o, + output wire near_full_o, + output wire near_empty_o ); localparam ADDR_BITS = $clog2(DEPTH); // address width for buffer reg [ADDR_BITS:0] w_ptr, r_ptr; +wire [ADDR_BITS:0] w_ptr_incr, r_ptr_incr; wire [ADDR_BITS:0] w_ptr_next, r_ptr_next; wire [ADDR_BITS-1:0] w_addr, r_addr; @@ -25,21 +26,27 @@ wire full_next, empty_next; reg [WIDTH-1:0] mem [0:DEPTH-1]; -assign w_ptr_next = (~full_o & we_i)? w_ptr + 1'b1 : w_ptr; -assign r_ptr_next = (~empty_o & re_i)? r_ptr + 1'b1 : r_ptr; +assign w_ptr_incr = w_ptr + 1'b1; +assign r_ptr_incr = r_ptr + 1'b1; + +assign w_ptr_next = (~full_o & we_i)? w_ptr_incr : w_ptr; +assign r_ptr_next = (~empty_o & re_i)? r_ptr_incr : r_ptr; assign full_o = r_ptr == {~w_ptr[ADDR_BITS], w_ptr[ADDR_BITS-1:0]}; assign empty_o = r_ptr == w_ptr; -assign rdata_o = mem[r_addr]; +assign near_full_o = r_ptr == {~w_ptr_incr[ADDR_BITS], w_ptr_incr[ADDR_BITS-1:0]+1'b1}; +assign near_empty_o = r_ptr_incr == w_ptr; + +assign rdata_o = (empty_o)? {WIDTH{1'b0}} : mem[r_addr]; assign w_addr = w_ptr[ADDR_BITS-1:0]; assign r_addr = r_ptr[ADDR_BITS-1:0]; always @(posedge clk_i, negedge rst_ni) begin if(~rst_ni) begin - w_ptr <= 0; - r_ptr <= 0; + w_ptr <= {ADDR_BITS+1{1'b0}}; + r_ptr <= {ADDR_BITS+1{1'b0}}; end else begin w_ptr <= w_ptr_next; diff --git a/rtl/system/synchronizer.v b/rtl/system/synchronizer.v index 09e85fe1..a95f289b 100644 --- a/rtl/system/synchronizer.v +++ b/rtl/system/synchronizer.v @@ -3,8 +3,7 @@ * for async fifo queue */ `timescale 1ns/1ps - -module ff2_sync #( +module sync_reg #( parameter WIDTH = 32 ) ( input wire clk_i, diff --git a/rtl/system/uart.vh b/rtl/system/uart.vh index 6104969f..bf28e11c 100644 --- a/rtl/system/uart.vh +++ b/rtl/system/uart.vh @@ -1,8 +1,6 @@ `ifndef UART `define UART -`timescale 1ns/1ps - `include "sync_fifo.v" `include "async_fifo.v" `include "uart_rx.v" diff --git a/rtl/system/uart_rx.v b/rtl/system/uart_rx.v index 67b67fba..9254acdd 100644 --- a/rtl/system/uart_rx.v +++ b/rtl/system/uart_rx.v @@ -1,5 +1,3 @@ -`timescale 1ns/1ps - module uart_rx ( input wire clk_i, input wire clk_en_i, diff --git a/rtl/system/uart_top.v b/rtl/system/uart_top.v index 0970cc20..2ef9690b 100644 --- a/rtl/system/uart_top.v +++ b/rtl/system/uart_top.v @@ -1,4 +1,5 @@ `include "uart.vh" + module uart_top #( parameter CLOCK_FREQUENCY = 50_000_000, parameter RX_FIFO_DEPTH = 128, @@ -19,7 +20,7 @@ module uart_top #( output wire [31:0] uart_rdata_o,// data bus output wire uart_req_gnt_o, // request granted to core (IBEX LSU) output wire uart_rvalid_o, // request valid to core (IBEX LSU) - output wire uart_irq_o, // interrupt request (CSR) + output wire [1:0] uart_irq_o, // interrupt request (CSR) output wire uart_err_o // error to core (IBEX LSU) ); @@ -55,6 +56,8 @@ wire rx_fq_we; // rx FIFO write enable wire [8:0] rx_fq_data_out; // rx FIFO data output wire rx_fq_full; // rx FIFO is full flag wire rx_fq_empty; // rx FIFO is empty flag +wire rx_fq_near_full; // rx FIFO is almost full +wire rx_fq_near_empty; // rx FIFO is almost empty wire tx_rdy; // ready flag reg tx_en; // enable register of tx module @@ -66,6 +69,8 @@ wire tx_fq_we; // tx FIFO queue write enable wire [8:0] tx_fq_data_out; // tx FIFO data output (to transmit) wire tx_fq_full; // tx FIFO is full flag wire tx_fq_empty; // tx FIFO is empty flag +wire tx_fq_near_full; // tx FIFO is almost full +wire tx_fq_near_empty; // tx FIFO is almost empty reg [31:0] rx_tick_counter; reg rx_clk_en; @@ -98,14 +103,16 @@ sync_fifo #( .WIDTH(9), // width of data bus .DEPTH(RX_FIFO_DEPTH) // depth of FIFO buffer ) rx_sync_fifo ( - .clk_i(clk_i), // input clock - .rst_ni(rst_ni), // reset signal - .wdata_i(rx_data), // input data - .we_i(rx_fq_we), // write enable signal - .re_i(rx_fq_re), // read enable signal - .rdata_o(rx_fq_data_out), // output data - .full_o(rx_fq_full), // full flag - .empty_o(rx_fq_empty) // empty flag + .clk_i(clk_i), // input clock + .rst_ni(rst_ni), // reset signal + .wdata_i(rx_data), // input data + .we_i(rx_fq_we), // write enable signal + .re_i(rx_fq_re), // read enable signal + .rdata_o(rx_fq_data_out), // output data + .full_o(rx_fq_full), // full flag + .empty_o(rx_fq_empty), // empty flag + .near_full_o(rx_fq_near_full), // near full flag + .near_empty_o(rx_fq_near_empty) // near empty flag ); `else // Asynchronous FIFO queue for rx module @@ -121,7 +128,9 @@ async_fifo #( .re_i(rx_fq_re), .rdata_o(rx_fq_data_out), .full_o(rx_fq_full), - .empty_o(rx_fq_empty) + .empty_o(rx_fq_empty), + .near_full_o(rx_fq_near_full), + .near_empty_o(rx_fq_near_empty) ); `endif @@ -149,17 +158,19 @@ uart_tx tx0 ( `ifndef ASYNC // Synchronous FIFO queue for tx module sync_fifo #( - .WIDTH(9), // width of data bus - .DEPTH(TX_FIFO_DEPTH) // depth of FIFO buffer + .WIDTH(9), // width of data bus + .DEPTH(TX_FIFO_DEPTH) // depth of FIFO buffer ) tx_sync_fifo ( - .clk_i(clk_i), // input clock - .rst_ni(rst_ni), // reset signal - .wdata_i(uart_wdata_i[8:0]), // input data - .we_i(tx_fq_we), // write enable signal - .re_i(tx_fq_re), // read enable signal - .rdata_o(tx_fq_data_out), // output data - .full_o(tx_fq_full), // full flag - .empty_o(tx_fq_empty) // empty flag + .clk_i(clk_i), // input clock + .rst_ni(rst_ni), // reset signal + .wdata_i(uart_wdata_i[8:0]), // input data + .we_i(tx_fq_we), // write enable signal + .re_i(tx_fq_re), // read enable signal + .rdata_o(tx_fq_data_out), // output data + .full_o(tx_fq_full), // full flag + .empty_o(tx_fq_empty), // empty flag + .near_full_o(tx_fq_near_full), // near full flag + .near_empty_o(tx_fq_near_empty) // near emtpy flag ); `else // Asynchronous FIFO queue for tx module @@ -175,7 +186,9 @@ async_fifo #( .re_i(tx_fq_re), .rdata_o(tx_fq_data_out), .full_o(tx_fq_full), - .empty_o(tx_fq_empty) + .empty_o(tx_fq_empty), + .near_full_o(rx_fq_near_full), + .near_empty_o(rx_fq_near_empty) ); `endif @@ -187,7 +200,7 @@ assign tx_fq_re = tx_rdy & tx_en & tx_clk_en; assign rx_fq_we = rx_rdy & ~rx_err & rx_clk_en; assign rx_fq_re = (opcode == OP_READ_UART_DATA) & rx_en; -assign uart_irq_o = ~rx_fq_empty; +assign uart_irq_o = {tx_fq_near_full, ~rx_fq_empty}; always `ifndef ASYNC @@ -254,26 +267,30 @@ always @(*) begin end always @(*) begin - uart_err_d = 1'b0; uart_rvalid_d = 1'b1; case(opcode) OP_WRITE_UART_PARAMETERS : begin uart_rdata_d <= 32'b0; + uart_err_d = 1'b0; end OP_READ_UART_DATA : begin uart_rdata_d <= {23'b0, rx_fq_data_out}; + uart_err_d = rx_fq_empty; end OP_WRITE_UART_DATA : begin uart_rdata_d <= 32'b0; + uart_err_d <= tx_fq_full; end OP_READ_UART_STATE : begin - uart_rdata_d <= {30'b0, tx_fq_full, rx_fq_empty}; + uart_rdata_d <= {28'b0, tx_fq_near_full, rx_fq_near_empty, tx_fq_full, rx_fq_empty}; + uart_err_d = 1'b0; end OP_WRITE_UART_EN : begin - uart_rdata_d <= 32'b0; + uart_rdata_d <= 32'b0; end default : begin uart_rdata_d <= 32'b0; + uart_err_d = 1'b0; end endcase end @@ -332,5 +349,6 @@ end assign uart_rdata_o = uart_rdata_q; assign uart_rvalid_o = uart_rvalid_q; assign uart_err_o = uart_err_q; +assign uart_req_gnt_o = 1'b1; endmodule \ No newline at end of file diff --git a/rtl/system/uart_tx.v b/rtl/system/uart_tx.v index a37a6b6a..9215a566 100644 --- a/rtl/system/uart_tx.v +++ b/rtl/system/uart_tx.v @@ -1,5 +1,3 @@ -`timescale 1ns/1ps - module uart_tx ( input wire clk_i, input wire clk_en_i, diff --git a/sw/c/common/demo_system.h b/sw/c/common/demo_system.h index e88ffab7..517c6961 100644 --- a/sw/c/common/demo_system.h +++ b/sw/c/common/demo_system.h @@ -11,8 +11,12 @@ #include "uart.h" #include "gpio.h" -#define UART_IRQ_NUM 16 -#define UART_IRQ (1 << UART_IRQ_NUM) +#define UART_RX_IRQ_NUM 16 +#define UART_RX_IRQ (1 << UART_RX_IRQ_NUM) + +#define UART_TX_IRQ_NUM 17 +#define UART_TX_IRQ (1 << UART_TX_IRQ_NUM) + #define DEFAULT_UART UART_FROM_BASE_ADDR(UART0_BASE) #define GPIO_OUT GPIO_FROM_BASE_ADDR(GPIO_BASE + GPIO_OUT_REG) diff --git a/sw/c/common/uart.c b/sw/c/common/uart.c index b387bc46..97a8051d 100644 --- a/sw/c/common/uart.c +++ b/sw/c/common/uart.c @@ -3,7 +3,12 @@ #include "demo_system.h" void uart_enable_rx_int(void) { - enable_interrupts(UART_IRQ); + enable_interrupts(UART_RX_IRQ); + set_global_interrupt_enable(1); +} + +void uart_enable_tx_int(void) { + enable_interrupts(UART_TX_IRQ); set_global_interrupt_enable(1); } @@ -36,4 +41,8 @@ void uart_disable(uart_t uart) { void uart_setup(uart_t uart, char parameters) { DEV_WRITE(uart + UART_PARAMETERS_REG, parameters); +} + +int uart_status(uart_t uart) { + return DEV_READ(DEFAULT_UART + UART_STATUS_REG); } \ No newline at end of file diff --git a/sw/c/common/uart.h b/sw/c/common/uart.h index 6197275d..2e8a8717 100644 --- a/sw/c/common/uart.h +++ b/sw/c/common/uart.h @@ -9,8 +9,10 @@ #define UART_ENABLE_REG 0x0C #define UART_PARAMETERS_REG 0x10 -#define UART_STATUS_RX_EMPTY 1 -#define UART_STATUS_TX_FULL 2 +#define UART_STATUS_RX_EMPTY 0x01 +#define UART_STATUS_TX_FULL 0x02 +#define UART_STATUS_RX_NEAR_EMPTY 0x04 +#define UART_STATUS_TX_NEAR_FULL 0x08 #define UART_EOF -1 @@ -46,4 +48,6 @@ void uart_enable(uart_t uart, char en); void uart_disable(uart_t uart); void uart_setup(uart_t uart, char parameters); +int uart_status(uart_t uart); + #endif diff --git a/sw/c/demo/hello_world/main.c b/sw/c/demo/hello_world/main.c index 87ec2d49..f30e5eff 100644 --- a/sw/c/demo/hello_world/main.c +++ b/sw/c/demo/hello_world/main.c @@ -11,17 +11,32 @@ #define USE_GPIO_SHIFT_REG 0 -void test_uart_irq_handler(void) __attribute__((interrupt)); +void test_uart_rx_irq_handler(void) __attribute__((interrupt)); +void test_uart_tx_irq_handler(void) __attribute__((interrupt)); -void test_uart_irq_handler(void) { + +void test_uart_rx_irq_handler(void) { unsigned char u; u = getchar(); putchar(u); } +void test_uart_tx_irq_handler(void) { + int i; + /* + do + { + for(i=0; i < 100; i++){}; + } while (uart_status(DEFAULT_UART)); + */ +} + int main(void) { - install_exception_handler(UART_IRQ_NUM, &test_uart_irq_handler); + install_exception_handler(UART_RX_IRQ_NUM, &test_uart_rx_irq_handler); + install_exception_handler(UART_TX_IRQ_NUM, &test_uart_tx_irq_handler); uart_enable_rx_int(); + uart_enable_tx_int(); + uart_enable(DEFAULT_UART, UART_RX_EN | UART_TX_EN); uart_setup(DEFAULT_UART, DATA_SIZE_8 | PARITY_NONE | STOP_BITS_ONE | BAUD_RATE_115200); From 7807f35fd59cb7e01caffa2f9d78766bc10188c2 Mon Sep 17 00:00:00 2001 From: AgamemnonasKyriazis Date: Sat, 30 Sep 2023 17:03:10 +0300 Subject: [PATCH 6/7] bugfix missed to declare the enable_tx_int routine, also pushed a version where the interrupt is commented out... --- sw/c/common/uart.h | 3 +++ sw/c/demo/hello_world/main.c | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sw/c/common/uart.h b/sw/c/common/uart.h index 2e8a8717..40c195bf 100644 --- a/sw/c/common/uart.h +++ b/sw/c/common/uart.h @@ -41,6 +41,9 @@ typedef void* uart_t; #define UART_TX_EN 0x02 void uart_enable_rx_int(void); + +void uart_enable_tx_int(void); + int uart_in(uart_t uart); void uart_out(uart_t uart, char c); diff --git a/sw/c/demo/hello_world/main.c b/sw/c/demo/hello_world/main.c index f30e5eff..2417f5a9 100644 --- a/sw/c/demo/hello_world/main.c +++ b/sw/c/demo/hello_world/main.c @@ -23,12 +23,10 @@ void test_uart_rx_irq_handler(void) { void test_uart_tx_irq_handler(void) { int i; - /* do { for(i=0; i < 100; i++){}; - } while (uart_status(DEFAULT_UART)); - */ + } while (uart_status(DEFAULT_UART) & UART_STATUS_TX_NEAR_FULL); } int main(void) { From 9eca9d004e462a9743139957f89fe5c221643e95 Mon Sep 17 00:00:00 2001 From: AgamemnonasKyriazis Date: Fri, 6 Oct 2023 02:59:39 +0300 Subject: [PATCH 7/7] Update main.c [sw] added the volatile qualifier to avoid optimization of empty for block --- sw/c/demo/hello_world/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sw/c/demo/hello_world/main.c b/sw/c/demo/hello_world/main.c index 2417f5a9..3d67492a 100644 --- a/sw/c/demo/hello_world/main.c +++ b/sw/c/demo/hello_world/main.c @@ -22,7 +22,7 @@ void test_uart_rx_irq_handler(void) { } void test_uart_tx_irq_handler(void) { - int i; + volatile int i; do { for(i=0; i < 100; i++){};