Thursday, 19 December 2019

Adding a UART

The first part of the design for the SoC I want to implement on the IceBreaker is a UART.

Not only will this UART allow communication from within programs running on the CPU, it will also allow a monitor program implemented in hardware to load and dump data as well as start a program.

This is nothing new but I found that the UART I used in a previous design on the IceStick was not always stable at higher baudrates. So my plan is to build things up slowly and for instance add FIFO buffers to the design.

The first implementation is listed below. It is nothing more than a small echo application and when connected to a terminal it seems to perform quite reliably at a baudrate of 115200.


`include "../puck/cores/osdvu/uart.v"
`default_nettype none

`define ADDR_WIDTH 12


module top(
 input CLK,
 input RX,
 output TX,
 input BTN_N,
 output reg LED1,
 output reg LED2,
 output reg LED3,
 output reg LED4,
 output reg LED5,
 output reg LEDR_N,
 output reg LEDG_N);

 // uart wires
 wire u_reset = 0;
 reg [7:0] u_tx_byte;
 reg [7:0] u_rx_byte;
 reg u_transmit;
 wire u_received,u_is_transmitting;
 wire u_break,u_error;

 uart #(
  .baud_rate(115200),
  .sys_clk_freq(12000000)
 ) uart0 (
  .clk(CLK),     // The master clock for this module
  .rst(0),     // Synchronous reset
  .rx(RX),     // Incoming serial line
  .tx(TX),     // Outgoing serial line
  .transmit(u_transmit),    // Assert to begin transmission
  .tx_byte(u_tx_byte),    // Byte to transmit
  .received(u_received),    // Indicates that a byte has been received
  .rx_byte(u_rx_byte),    // Byte received
  .is_receiving(),    // Low when receive line is idle.
  .is_transmitting(u_is_transmitting),            // Low when transmit line is idle.
  .recv_error(u_error)         // Indicates error in receiving packet.
  // output reg [3:0] rx_samples,
  // output reg [3:0] rx_sample_countdown
        );

 always @(posedge CLK) begin
  u_transmit <= 0;
  LED1 <= 0;
  if(u_received) begin
   u_tx_byte <= u_rx_byte;
   LED1 <= 1;
   u_transmit <= 1;
  end
 end

endmodule



The uart cores are sourced from cyrozap.

The code as shown does nothing substantial between receiving and sending a byte so there is hardly any chance of clock skew or similar difficulties. However, this is not necessarily so when the CPU is also using this UART, so the next step will be to add FIFOs to the UART.

CPU design

The CPU design as currently implemented largely follows the diagram shown below. It features a 16 x 32bit register file and 16 bit instructi...