HierarchyFilesModulesSignalsTasksFunctionsHelp
12
//-----------------------------------------------------------------------------
// customised top-level example Cortex-M0 controller
// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license.
//
// Contributors
//
// David Flynn (d.w.flynn@soton.ac.uk)
//
// Copyright © 2021-2, SoC Labs (www.soclabs.org)
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// The confidential and proprietary information contained in this file may
// only be used by a person authorised under and to the extent permitted
// by a subsisting licensing agreement from Arm Limited or its affiliates.
//
//            (C) COPYRIGHT 2010-2011 Arm Limited or its affiliates.
//                ALL RIGHTS RESERVED
//
// This entire notice must be reproduced on all copies of this file
// and copies of this file may only be made by a person if such person is
// permitted to do so under the terms of a subsisting license agreement
// from Arm Limited or its affiliates.
//
//      SVN Information
//
//      Checked In          : $Date: 2017-10-10 15:55:38 +0100 (Tue, 10 Oct 2017) $
//
//      Revision            : $Revision: 371321 $
//
//      Release Information : Cortex-M System Design Kit-r1p1-00rel0
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Abstract : Simple APB UART
//-----------------------------------------------------------------------------
//-------------------------------------
// Programmer's model
// 0x00 R     RXD[7:0]    Received Data
//      W     TXD[7:0]    Transmit data
// 0x04 RW    STAT[3:0]
//              [3] RX buffer overrun (write 1 to clear)
//              [2] TX buffer overrun (write 1 to clear)
//              [1] RX buffer full (Read only)
//              [0] TX buffer full (Read only)
// 0x08 RW    CTRL[3:0]   TxIntEn, RxIntEn, TxEn, RxEn
//              [6] High speed test mode Enable
//              [5] RX overrun interrupt enable
//              [4] TX overrun interrupt enable
//              [3] RX Interrupt Enable
//              [2] TX Interrupt Enable
//              [1] RX Enable
//              [0] TX Enable
// 0x0C R/Wc  intr_status/INTCLEAR
//              [3] RX overrun interrupt
//              [2] TX overrun interrupt
//              [1] RX interrupt
//              [0] TX interrupt
// 0x10 RW    BAUDDIV[19:0] Baud divider
//            (minimum value is 16)
// 0x3E0 - 0x3FC  ID registers
//-------------------------------------

[Up: cmsdk_mcu_chip u_apb_uart_com]
module cmsdk_apb_uart_streamioIndex (
// --------------------------------------------------------------------------
// Port Definitions
// --------------------------------------------------------------------------
  input  wire        PCLK,     // Clock
  input  wire        PCLKG,    // Gated Clock
  input  wire        PRESETn,  // Reset

  input  wire        PSEL,     // Device select
  input  wire [11:2] PADDR,    // Address
  input  wire        PENABLE,  // Transfer control
  input  wire        PWRITE,   // Write control
  input  wire [31:0] PWDATA,   // Write data

  input  wire [3:0]  ECOREVNUM,// Engineering-change-order revision bits

  output wire [31:0] PRDATA,   // Read data
  output wire        PREADY,   // Device ready
  output wire        PSLVERR,  // Device error response

  input  wire        RXD,      // Serial input
  output wire        TXD,      // Transmit data output
  output wire        TXEN,     // Transmit enabled
  output wire        BAUDTICK, // Baud rate (x16) Tick
  
  output wire        TX_VALID_o,
  output wire [7:0]  TX_DATA8_o,
  input  wire        TX_READY_i,

  input  wire        RX_VALID_i,
  input  wire [7:0]  RX_DATA8_i,
  output wire        RX_READY_o,

  output wire        TXINT,    // Transmit Interrupt
  output wire        RXINT,    // Receive Interrupt
  output wire        TXOVRINT, // Transmit overrun Interrupt
  output wire        RXOVRINT, // Receive overrun Interrupt
  output wire        UARTINT); // Combined interrupt

// Local ID parameters, APB UART part number is 0x821
localparam  ARM_CMSDK_APB_UART_PID4 = 8'h04;
localparam  ARM_CMSDK_APB_UART_PID5 = 8'h00;
localparam  ARM_CMSDK_APB_UART_PID6 = 8'h00;
localparam  ARM_CMSDK_APB_UART_PID7 = 8'h00;
localparam  ARM_CMSDK_APB_UART_PID0 = 8'h21;
localparam  ARM_CMSDK_APB_UART_PID1 = 8'hB8;
localparam  ARM_CMSDK_APB_UART_PID2 = 8'h1B;
localparam  ARM_CMSDK_APB_UART_PID3 = 4'h0;
localparam  ARM_CMSDK_APB_UART_CID0 = 8'h0D;
localparam  ARM_CMSDK_APB_UART_CID1 = 8'hF0;
localparam  ARM_CMSDK_APB_UART_CID2 = 8'h05;
localparam  ARM_CMSDK_APB_UART_CID3 = 8'hB1;

  // --------------------------------------------------------------------------
  // Internal wires
  // --------------------------------------------------------------------------
// Signals for read/write controls
wire          read_enable;
wire          write_enable;
wire          write_enable00; // Write enable for data register
wire          write_enable04; // Write enable for Status register
wire          write_enable08; // Write enable for control register
wire          write_enable0c; // Write enable for interrupt status register
wire          write_enable10; // Write enable for Baud rate divider
reg     [7:0] read_mux_byte0; // Read data multiplexer for lower 8-bit
reg     [7:0] read_mux_byte0_reg; // Register read data for lower 8-bit
wire   [31:0] read_mux_word;  // Read data multiplexer for whole 32-bit
wire    [3:0] pid3_value;     // constant value for lower 4-bit in perpherial ID3

// Signals for Control registers
reg     [6:0] reg_ctrl;       // Control register
reg     [7:0] reg_tx_buf;     // Transmit data buffer
reg     [7:0] reg_rx_buf;     // Receive data buffer
reg    [19:0] reg_baud_div;   // Baud rate setting

// Internal signals
  // Baud rate divider
reg    [15:0] reg_baud_cntr_i; // baud rate divider counter i (integer)
wire   [15:0] nxt_baud_cntr_i;
reg     [3:0] reg_baud_cntr_f; // baud rate divider counter f (fraction)
wire    [3:0] nxt_baud_cntr_f;
wire    [3:0] mapped_cntr_f;   // remapped counter f value
reg           reg_baud_tick;   // Register baud rate tick (16 times of baud rate)
reg           baud_updated;    // baud rate value has bee updated from APB
wire          reload_i;        // baud rate divider counter i reload
wire          reload_f;        // baud rate divider counter f reload
wire          baud_div_en;     // enable baud rate counter

  // Status
wire    [3:0] uart_status;     // UART status
reg           reg_rx_overrun;  // Receive overrun status register
wire          rx_overrun;      // Receive overrun detection
reg           reg_tx_overrun;  // Transmit overrun status register
wire          tx_overrun;      // Transmit overrun detection
wire          nxt_rx_overrun;  // next state for reg_rx_overrun
wire          nxt_tx_overrun;  // next state for reg_tx_overrun
  // Interrupts
reg           reg_txintr;      // Transmit interrupt register
reg           reg_rxintr;      // Receive interrupt register
wire          tx_overflow_intr;// Transmit overrun/overflow interrupt
wire          rx_overflow_intr;// Receive overrun/overflow interrupt
wire    [3:0] intr_state;      // UART interrupt status
wire    [1:0] intr_stat_set;   // Set TX/RX interrupt
wire    [1:0] intr_stat_clear; // Clear TX/RX interrupt

  // transmit
reg     [3:0] tx_state;    // Transmit FSM state
reg     [4:0] nxt_tx_state;
wire          tx_state_update;
wire          tx_state_inc; // Bit pulse
reg     [3:0] tx_tick_cnt;  // Transmit Tick counter
wire    [4:0] nxt_tx_tick_cnt;
reg     [7:0] tx_shift_buf;      // Transmit shift register
wire    [7:0] nxt_tx_shift_buf;  // next state    for tx_shift_buf
wire          tx_buf_ctrl_shift; // shift control for tx_shift_buf
wire          tx_buf_ctrl_load;  // load  control for tx_shift_buf
reg           tx_buf_full;  // TX Buffer full
reg           reg_txd;      // Tx Data
wire          nxt_txd;      // next state of reg_txd
wire          update_reg_txd; // update reg_txd
wire          tx_buf_clear; // Clear buffer full status when data is load into TX shift register

  // Receive data sync and filter
reg           rxd_sync_1;  // Double flip-flop syncrhoniser
reg           rxd_sync_2;  // Double flip-flop syncrhoniser
reg     [2:0] rxd_lpf;     // Averaging Low Pass Filter
wire    [2:0] nxt_rxd_lpf;
wire          rx_shift_in; // Shift Register Input

  // Receiver
reg     [3:0] rx_state;   // Receiver FSM state
reg     [4:0] nxt_rx_state;
wire          rx_state_update;
reg     [3:0] rx_tick_cnt; // Receiver Tick counter
wire    [4:0] nxt_rx_tick_cnt;
wire          update_rx_tick_cnt;
wire          rx_state_inc;// Bit pulse
reg     [6:0] rx_shift_buf;// Receiver shift data register
wire    [6:0] nxt_rx_shift_buf;
reg           rx_buf_full;  // Receive buffer full status
wire          nxt_rx_buf_full;
wire          rxbuf_sample; // Sample received data into receive data buffer
wire          rx_data_read; // Receive data buffer read by APB interface
wire    [7:0] nxt_rx_buf;

// Start of main code
// Read and write control signals
assign  read_enable  = PSEL & (~PWRITE); // assert for whole APB read transfer
assign  write_enable = PSEL & (~PENABLE) & PWRITE; // assert for 1st cycle of write transfer
assign  write_enable00 = write_enable & (PADDR[11:2] == 10'h000);
assign  write_enable04 = write_enable & (PADDR[11:2] == 10'h001);
assign  write_enable08 = write_enable & (PADDR[11:2] == 10'h002);
assign  write_enable0c = write_enable & (PADDR[11:2] == 10'h003);
assign  write_enable10 = write_enable & (PADDR[11:2] == 10'h004);

// Write operations
  // Transmit data register
  always @(posedge PCLKG or negedge PRESETn)
  begin
    if (~PRESETn)
        reg_tx_buf <= {8{1'b0}};
    else if (write_enable00)
      reg_tx_buf <= PWDATA[7:0];
  end

  assign TX_DATA8_o = reg_tx_buf[7:0];
  
  // Status register overrun registers
  assign nxt_rx_overrun = (reg_rx_overrun & (~((write_enable04|write_enable0c) & PWDATA[3]))) | rx_overrun;
  assign nxt_tx_overrun = (reg_tx_overrun & (~((write_enable04|write_enable0c) & PWDATA[2]))) | tx_overrun;

  // RX OverRun status
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      reg_rx_overrun <= 1'b0;
    else if (rx_overrun | write_enable04 | write_enable0c)
      reg_rx_overrun <= nxt_rx_overrun;
  end

  // TX OverRun status
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      reg_tx_overrun <= 1'b0;
    else if (tx_overrun | write_enable04 | write_enable0c)
      reg_tx_overrun <= nxt_tx_overrun;
  end

  // Control register
  always @(posedge PCLKG or negedge PRESETn)
  begin
    if (~PRESETn)
      reg_ctrl <= {7{1'b0}};
    else if (write_enable08)
      reg_ctrl <= PWDATA[6:0];
  end

  // Baud rate divider - integer
  always @(posedge PCLKG or negedge PRESETn)
  begin
    if (~PRESETn)
      reg_baud_div <= {20{1'b0}};
    else if (write_enable10)
      reg_baud_div <= PWDATA[19:0];
  end

// Read operation
  assign uart_status = {reg_rx_overrun, reg_tx_overrun, rx_buf_full, tx_buf_full};

  assign pid3_value  = ARM_CMSDK_APB_UART_PID3;

  // First level of read mux
 always @(PADDR or reg_rx_buf or uart_status or reg_ctrl or intr_state or reg_baud_div
   or ECOREVNUM or pid3_value)
  begin
   if (PADDR[11:5] == 7'h00) begin
     case (PADDR[4:2])
     3'h0: read_mux_byte0 =  reg_rx_buf;
     3'h1: read_mux_byte0 =  {{4{1'b0}},uart_status};
     3'h2: read_mux_byte0 =  {{1{1'b0}},reg_ctrl};
     3'h3: read_mux_byte0 =  {{4{1'b0}},intr_state};
     3'h4: read_mux_byte0 =  reg_baud_div[7:0];
     3'h5, 3'h6, 3'h7: read_mux_byte0 =   {8{1'b0}};     //default read out value
     default:  read_mux_byte0 =   {8{1'bx}};// x propogation
     endcase
   end
   else if (PADDR[11:6] == 6'h3F) begin
     case  (PADDR[5:2])
       4'h0, 4'h1,4'h2,4'h3: read_mux_byte0 =   {8{1'b0}}; //default read out value
   // ID register - constant values
       4'h4: read_mux_byte0 = ARM_CMSDK_APB_UART_PID4; // 0xFD0 : PID 4
       4'h5: read_mux_byte0 = ARM_CMSDK_APB_UART_PID5; // 0xFD4 : PID 5
       4'h6: read_mux_byte0 = ARM_CMSDK_APB_UART_PID6; // 0xFD8 : PID 6
       4'h7: read_mux_byte0 = ARM_CMSDK_APB_UART_PID7; // 0xFDC : PID 7
       4'h8: read_mux_byte0 = ARM_CMSDK_APB_UART_PID0; // 0xFE0 : PID 0  APB UART part number[7:0]
       4'h9: read_mux_byte0 = ARM_CMSDK_APB_UART_PID1; // 0xFE0 : PID 1 [7:4] jep106_id_3_0. [3:0] part number [11:8]
       4'hA: read_mux_byte0 = ARM_CMSDK_APB_UART_PID2; // 0xFE0 : PID 2 [7:4] revision, [3] jedec_used. [2:0] jep106_id_6_4
       4'hB: read_mux_byte0 = {ECOREVNUM[3:0],pid3_value[3:0]};
                                                       // 0xFE0 : PID 3 [7:4] ECO revision, [3:0] modification number
       4'hC: read_mux_byte0 = ARM_CMSDK_APB_UART_CID0; // 0xFF0 : CID 0
       4'hD: read_mux_byte0 = ARM_CMSDK_APB_UART_CID1; // 0xFF4 : CID 1 PrimeCell class
       4'hE: read_mux_byte0 = ARM_CMSDK_APB_UART_CID2; // 0xFF8 : CID 2
       4'hF: read_mux_byte0 = ARM_CMSDK_APB_UART_CID3; // 0xFFC : CID 3
       default : read_mux_byte0 = {8{1'bx}}; // x propogation
      endcase
    end
    else begin
       read_mux_byte0 =   {8{1'b0}};     //default read out value
    end
  end



  // Register read data
  always @(posedge PCLKG or negedge PRESETn)
  begin
    if (~PRESETn)
      read_mux_byte0_reg      <= {8{1'b0}};
    else if (read_enable)
      read_mux_byte0_reg      <= read_mux_byte0;
  end

  // Second level of read mux
  assign read_mux_word[ 7: 0] = read_mux_byte0_reg;
  assign read_mux_word[19: 8] = (PADDR[11:2]==10'h004) ? reg_baud_div[19:8] : {12{1'b0}};
  assign read_mux_word[31:20] = {12{1'b0}};


  // Output read data to APB
  assign PRDATA[31: 0] = (read_enable) ? read_mux_word : {32{1'b0}};
  assign PREADY  = 1'b1; // Always ready
  assign PSLVERR = 1'b0; // Always okay

// --------------------------------------------
// Baud rate generator
  // Baud rate generator enable
  assign baud_div_en    = (reg_ctrl[1:0] != 2'b00);
  assign mapped_cntr_f  = {reg_baud_cntr_f[0],reg_baud_cntr_f[1],
                           reg_baud_cntr_f[2],reg_baud_cntr_f[3]};
  // Reload Integer divider
  // when UART enabled and (reg_baud_cntr_f < reg_baud_div[3:0])
  // then count to 1, or
  // when UART enabled then count to 0
  assign reload_i      = (baud_div_en &
         (((mapped_cntr_f >= reg_baud_div[3:0]) &
         (reg_baud_cntr_i[15:1] == {15{1'b0}})) |
         (reg_baud_cntr_i[15:0] == {16{1'b0}})));

  // Next state for Baud rate divider
  assign nxt_baud_cntr_i = (baud_updated | reload_i) ? reg_baud_div[19:4] :
                           (reg_baud_cntr_i - 16'h0001);
  // Update at reload or decrement
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      reg_baud_cntr_i   <= {16{1'b0}};
    else if (baud_updated | baud_div_en)
      reg_baud_cntr_i   <= nxt_baud_cntr_i;
  end

  // Reload fraction divider
  assign reload_f      = baud_div_en & (reg_baud_cntr_f==4'h0) &
                        reload_i;
  // Next state for fraction part of Baud rate divider
  assign nxt_baud_cntr_f =
                        (reload_f|baud_updated) ? 4'hF :
                        (reg_baud_cntr_f - 4'h1);

  // Update at reload or decrement
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      reg_baud_cntr_f   <= {4{1'b0}};
    else if (baud_updated | reload_f | reload_i)
      reg_baud_cntr_f   <= nxt_baud_cntr_f;
  end

  // Generate control signal to update baud rate counters
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      baud_updated    <= 1'b0;
    else if (write_enable10 | baud_updated)
      // Baud rate updated - to load new value to counters
      baud_updated    <= write_enable10;
  end

  // Generate Tick signal for external logic
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      reg_baud_tick    <= 1'b0;
    else if (reload_i | reg_baud_tick)
      reg_baud_tick    <= reload_i;
  end

  // Connect to external
  assign BAUDTICK = reg_baud_tick;

// --------------------------------------------
// Transmit

  // Buffer full status
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      tx_buf_full     <= 1'b0;
    else if (write_enable00) // | tx_buf_clear)
      tx_buf_full     <= write_enable00;
    else if (tx_buf_full & TX_READY_i) // AXI stream ack
      tx_buf_full <= 0;
  end

  assign TX_VALID_o = tx_buf_full;

  // Increment TickCounter
  assign nxt_tx_tick_cnt = ((tx_state==4'h1) & reg_baud_tick) ? {5{1'b0}} :
                        tx_tick_cnt + {{3{1'b0}},reg_baud_tick};

  // Registering TickCounter
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      tx_tick_cnt     <= {4{1'b0}};
    else if (reg_baud_tick)
      tx_tick_cnt     <= nxt_tx_tick_cnt[3:0];
  end

  // Increment state (except Idle(0) and Wait for Tick(1))
  assign tx_state_inc   = (((&tx_tick_cnt)|(tx_state==4'h1)) & reg_baud_tick)|reg_ctrl[6];
          // state increment every cycle of high speed test mode is enabled
  // Clear buffer full status when data is load into shift register
  assign tx_buf_clear   = ((tx_state==4'h0) & tx_buf_full) |
                        ((tx_state==4'hB) & tx_buf_full & tx_state_inc);

  // tx_state machine
  // 0 = Idle, 1 =  Wait for Tick,
  // 2 = Start bit, 3 = D0 .... 10 = D7
  // 11 = Stop bit
  always @(tx_state or tx_buf_full or tx_state_inc or reg_ctrl)
  begin
  case (tx_state)
    0: begin
       nxt_tx_state = (tx_buf_full & reg_ctrl[0]) ? 5'h01 : 5'h00;  // New data is written to buffer
       end
    1,                         // State 1   : Wait for next Tick
    2,3,4,5,6,7,8,9,10: begin  // State 2-10: Start bit, D0 - D7
       nxt_tx_state = tx_state + {3'b000,tx_state_inc};
       end
    11: begin // Stop bit , goto next start bit or Idle
       nxt_tx_state = (tx_state_inc) ? ( tx_buf_full ? 5'h02:5'h00) : {1'b0, tx_state};
       end
    default:
       nxt_tx_state = {5{1'bx}};
  endcase
  end

  assign tx_state_update = tx_state_inc | ((tx_state==4'h0) & tx_buf_full & reg_ctrl[0]) | (tx_state>4'd11);

  // Registering outputs
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      tx_state        <= {4{1'b0}};
    else if (tx_state_update)
      tx_state        <= nxt_tx_state[3:0];
  end

  // Load/shift TX register
  assign tx_buf_ctrl_load  = (((tx_state==4'h0) & tx_buf_full) |
                              ((tx_state==4'hB) & tx_buf_full & tx_state_inc));
  assign tx_buf_ctrl_shift =  ((tx_state>4'h2) & tx_state_inc);

  assign nxt_tx_shift_buf = tx_buf_ctrl_load ? reg_tx_buf[7:0] : {1'b1,tx_shift_buf[7:1]};

  // Registering TX shift register
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      tx_shift_buf    <= {8{1'b0}};
    else if (tx_buf_ctrl_shift | tx_buf_ctrl_load)
      tx_shift_buf    <= nxt_tx_shift_buf;
  end

  // Data output
  assign nxt_txd = (tx_state==4'h2) ? 1'b0 :
                   (tx_state>4'h2) ? tx_shift_buf[0] : 1'b1;

  assign update_reg_txd = (nxt_txd != reg_txd);

  // Registering outputs
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      reg_txd         <= 1'b1;
    else if (update_reg_txd)
      reg_txd         <= nxt_txd;
  end

  // Generate TX overrun error status
  assign tx_overrun = tx_buf_full & (~tx_buf_clear) & write_enable00;

  // Connect to external
  assign TXD  = reg_txd;
  assign TXEN = reg_ctrl[0];

// --------------------------------------------
// Receive synchronizer and low pass filter

  // Doubling Flip-flop synxt_rx_tick_cntnchroniser
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      begin
      rxd_sync_1 <= 1'b1;
      rxd_sync_2 <= 1'b1;
      end
    else if (reg_ctrl[1]) // Turn off synchronizer if receive is not enabled
      begin
      rxd_sync_1 <= RXD;
      rxd_sync_2 <= rxd_sync_1;
      end
  end

  // Averaging low pass filter
  assign nxt_rxd_lpf = {rxd_lpf[1:0], rxd_sync_2};
  // Registering stage for low pass filter
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      rxd_lpf <= 3'b111;
    else if (reg_baud_tick)
      rxd_lpf <= nxt_rxd_lpf;
  end

  // Averaging values
  assign rx_shift_in = (rxd_lpf[1] & rxd_lpf[0]) |
                       (rxd_lpf[1] & rxd_lpf[2]) |
                       (rxd_lpf[0] & rxd_lpf[2]);

// --------------------------------------------
// Receive

  // Increment TickCounter
  assign nxt_rx_tick_cnt = ((rx_state==4'h0) & (~rx_shift_in)) ? 5'h08 :
                        rx_tick_cnt + {{3{1'b0}},reg_baud_tick};

  assign update_rx_tick_cnt = ((rx_state==4'h0) & (~rx_shift_in)) | reg_baud_tick;

  // Registering other register
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      rx_tick_cnt    <= {4{1'b0}};
    else if (update_rx_tick_cnt)
      rx_tick_cnt    <= nxt_rx_tick_cnt[3:0];
  end

  // Increment state
  assign rx_state_inc   = ((&rx_tick_cnt) & reg_baud_tick);
  // Buffer full status
  assign nxt_rx_buf_full = rxbuf_sample | (rx_buf_full & (~rx_data_read));

  // Sample shift register when D7 is sampled
///  assign rxbuf_sample  = ((rx_state==4'h9) & rx_state_inc);
  assign rxbuf_sample  = RX_VALID_i & !rx_buf_full;

  // Reading receive buffer (Set at 1st cycle of APB transfer
  // because read mux is registered before output)
  assign rx_data_read   = (PSEL & (~PENABLE) & (PADDR[11:2]==10'h000) & (~PWRITE));
  // Generate RX overrun error status
  assign rx_overrun = rx_buf_full & rxbuf_sample & (~rx_data_read);

  // rx_state machine
  // 0 = Idle, 1 =  Start of Start bit detected
  // 2 = Sample Start bit, 3 = D0 .... 10 = D7
  // 11 = Stop bit
  // 11, 12, 13, 14, 15: illegal/unused states
  always @(rx_state or rx_shift_in or rx_state_inc or reg_ctrl)
  begin
  case (rx_state)
    0: begin
       nxt_rx_state = ((~rx_shift_in) & reg_ctrl[1]) ? 5'h01 : 5'h00;  // Wait for Start bit
       end
    1,                      // State 1  : Wait for middle of start bit
    2,3,4,5,6,7,8,9: begin  // State 2-9: D0 - D7
       nxt_rx_state = rx_state + {3'b000,rx_state_inc};
       end
    10: begin // Stop bit , goto back to Idle
       nxt_rx_state = (rx_state_inc) ? 5'h00 : 5'h0A;
       end
    default:
       nxt_rx_state = {5{1'bx}};
  endcase
  end

  assign rx_state_update = rx_state_inc |  ((~rx_shift_in) & reg_ctrl[1]);

  // Registering rx_state
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      rx_state       <= {4{1'b0}};
    else if (rx_state_update)
      rx_state       <= nxt_rx_state[3:0];
  end

  // Buffer full status
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      rx_buf_full     <= 1'b0;
    else if (rxbuf_sample | rx_data_read)
      rx_buf_full     <= nxt_rx_buf_full;
  end

  // Sample receive buffer
///  assign nxt_rx_buf     = {rx_shift_in, rx_shift_buf};
  assign nxt_rx_buf     = RX_DATA8_i[7:0];
  
  // Registering receive data buffer
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      reg_rx_buf      <= {8{1'b0}};
    else if  (rxbuf_sample)
      reg_rx_buf      <= nxt_rx_buf;
  end

  // Shift register
  assign nxt_rx_shift_buf= {rx_shift_in, rx_shift_buf[6:1]};
  // Registering shift buffer
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      rx_shift_buf    <= {7{1'b0}};
    else if (rx_state_inc)
      rx_shift_buf    <= nxt_rx_shift_buf;
  end



// --------------------------------------------
// Interrupts
  // Set by event
  assign intr_stat_set[1] = reg_ctrl[3] & rxbuf_sample; // A new receive data is sampled
  assign intr_stat_set[0] = reg_ctrl[2] & reg_ctrl[0] & tx_buf_full & tx_buf_clear;
                            // Falling edge of buffer full
  // Clear by write to IntClear register
  assign intr_stat_clear[1:0] = {2{write_enable0c}} & PWDATA[1:0];

  // Registering outputs
  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      reg_txintr    <= 1'b0;
    else if (intr_stat_set[0] | intr_stat_clear[0])
      reg_txintr    <= intr_stat_set[0];
  end

  always @(posedge PCLK or negedge PRESETn)
  begin
    if (~PRESETn)
      reg_rxintr    <= 1'b0;
    else if (intr_stat_set[1] | intr_stat_clear[1])
      reg_rxintr    <= intr_stat_set[1];
  end

  assign rx_overflow_intr = reg_rx_overrun & reg_ctrl[5];
  assign tx_overflow_intr = reg_tx_overrun & reg_ctrl[4];

  // Interrupt status for read back
  assign intr_state = {rx_overflow_intr, tx_overflow_intr, reg_rxintr, reg_txintr};

  // Connect to external
  assign TXINT    = reg_txintr;
  assign RXINT    = reg_rxintr;
  assign TXOVRINT = tx_overflow_intr;
  assign RXOVRINT = rx_overflow_intr;
  assign UARTINT  = reg_txintr | reg_rxintr | tx_overflow_intr | rx_overflow_intr;


`ifdef ARM_APB_ASSERT_ON
   // ------------------------------------------------------------
   // Assertions
   // ------------------------------------------------------------
`include "std_ovl_defines.h"

   // Prepare signals for OVL checking
   reg [15:0] ovl_last_reg_baud_cntr_i;
   reg  [3:0] ovl_last_reg_baud_cntr_f;
   reg        ovl_last_baud_div_en;
   reg        ovl_last_baud_updated;
   always @(posedge PCLK or negedge PRESETn)
   begin
     if (~PRESETn)
       begin
       ovl_last_reg_baud_cntr_i <= {16{1'b0}};
       ovl_last_reg_baud_cntr_f <= {4{1'b0}};
       ovl_last_baud_div_en     <= 1'b0;
       ovl_last_baud_updated    <= 1'b0;
       end
     else
       begin
       ovl_last_reg_baud_cntr_i <= reg_baud_cntr_i;
       ovl_last_reg_baud_cntr_f <= reg_baud_cntr_f;
       ovl_last_baud_div_en     <= baud_div_en;
       ovl_last_baud_updated    <= baud_updated;
       end
   end

   reg        ovl_reg_hs_test_mode_triggered; // Indicate if HighSpeed testmode has been activated
   wire       ovl_nxt_hs_test_mode_triggered;
   reg  [7:0] ovl_reg_tx_tick_count;  // For measuring width of TX state
   wire [7:0] ovl_nxt_tx_tick_count;
   reg  [7:0] ovl_reg_rx_tick_count;  // For measuring width of RX state
   wire [7:0] ovl_nxt_rx_tick_count;
   reg  [3:0] ovl_reg_last_tx_state;  // last state
   reg  [3:0] ovl_reg_last_rx_state;
   reg  [6:0] ovl_last_reg_ctrl;

   // Clear test mode indicator each time state is changed, set to 1 if high speed test mode is
   // enabled
   assign ovl_nxt_hs_test_mode_triggered =
     (tx_state!=ovl_reg_last_tx_state) ? reg_ctrl[6]: (reg_ctrl[6] | ovl_reg_hs_test_mode_triggered);

   // Counter clear at each state change, increasement at each reg_baud_tick
   assign ovl_nxt_tx_tick_count = (tx_state!=ovl_reg_last_tx_state) ? (8'h00) :
     (ovl_reg_tx_tick_count + {{7{1'b0}}, reg_baud_tick});

   // Counter clear at each state change, increasement at each reg_baud_tick
   assign ovl_nxt_rx_tick_count = (rx_state!=ovl_reg_last_rx_state) ? (8'h00) :
     (ovl_reg_rx_tick_count + {{7{1'b0}}, reg_baud_tick});

   always@(posedge PCLK or negedge PRESETn)
     begin
     if (~PRESETn)
       begin
       ovl_reg_hs_test_mode_triggered <= 1'b0;
       ovl_reg_last_tx_state          <= 4'h0;
       ovl_reg_last_rx_state          <= 4'h0;
       ovl_reg_tx_tick_count          <= 8'h00;
       ovl_reg_rx_tick_count          <= 8'h00;
       ovl_last_reg_ctrl              <= 7'h00;
       end
     else
       begin
       ovl_reg_hs_test_mode_triggered <= ovl_nxt_hs_test_mode_triggered;
       ovl_reg_last_tx_state          <= tx_state;
       ovl_reg_last_rx_state          <= rx_state;
       ovl_reg_tx_tick_count          <= ovl_nxt_tx_tick_count;
       ovl_reg_rx_tick_count          <= ovl_nxt_rx_tick_count;
       ovl_last_reg_ctrl              <= reg_ctrl;
       end
     end

   // Signals for checking clearing of interrupts
   reg          ovl_last_txint;
   reg          ovl_last_rxint;
   reg          ovl_last_psel;
   reg          ovl_last_penable;
   reg          ovl_last_pwrite;
   reg  [31:0]  ovl_last_pwdata;
   reg  [11:2]  ovl_last_paddr;
   reg          ovl_last_rx_buf_full;
   reg          ovl_last_tx_shift_buf_0;


   always@(posedge PCLK or negedge PRESETn)
     begin
     if (~PRESETn)
       begin
       ovl_last_txint   <= 1'b0;
       ovl_last_rxint   <= 1'b0;
       ovl_last_psel    <= 1'b0;
       ovl_last_penable <= 1'b0;
       ovl_last_pwrite  <= 1'b0;
       ovl_last_paddr   <= {10{1'b0}};
       ovl_last_pwdata  <= {32{1'b0}};
       ovl_last_rx_buf_full  <= 1'b0;
       ovl_last_tx_shift_buf_0 <= 1'b0;
       end
     else
       begin
       ovl_last_txint   <= TXINT;
       ovl_last_rxint   <= RXINT;
       ovl_last_psel    <= PSEL;
       ovl_last_penable <= PENABLE;
       ovl_last_pwrite  <= PWRITE;
       ovl_last_paddr   <= PADDR;
       ovl_last_pwdata  <= PWDATA;
       ovl_last_rx_buf_full  <= rx_buf_full;
       ovl_last_tx_shift_buf_0 <= tx_shift_buf[0];
       end
     end

   // Ensure rx_state must not be 11, 12, 13, 14, 15
   assert_never
     #(`OVL_ERROR,`OVL_ASSERT,
       "rx_state in illegal state")
   u_ovl_rx_state_illegal
     (.clk(PCLK), .reset_n(PRESETn),
      .test_expr((rx_state==4'hB)|(rx_state==4'hC)|(rx_state==4'hD)|
      (rx_state==4'hE)|(rx_state==4'hF)));

   // Ensure tx_state must not be 12, 13, 14, 15
   assert_never
     #(`OVL_ERROR,`OVL_ASSERT,
       "tx_state in illegal state")
   u_ovl_tx_state_illegal
     (.clk(PCLK), .reset_n(PRESETn),
      .test_expr((tx_state==4'hC)|(tx_state==4'hD)|
      (tx_state==4'hE)|(tx_state==4'hF)));

   // Ensure reg_baud_cntr_i change only if UART is enabled
   // or if write to baud rate divider
   assert_implication
     #(`OVL_ERROR,`OVL_ASSERT,
       "Unexpected baud rate divider change")
   u_ovl_reg_baud_cntr_i_change
     (.clk(PCLK), .reset_n(PRESETn),
      .antecedent_expr(ovl_last_reg_baud_cntr_i!=reg_baud_cntr_i),
      .consequent_expr(ovl_last_baud_div_en | ovl_last_baud_updated )
      );

   // Ensure reg_baud_div[19:4] >= reg_baud_cntr_i unless reg_baud_div just been programmed
   assert_implication
     #(`OVL_ERROR,`OVL_ASSERT,
       "Unexpected baud rate divided change")
   u_ovl_reg_baud_cntr_i_range
     (.clk(PCLK), .reset_n(PRESETn),
      .antecedent_expr(reg_baud_cntr_i>reg_baud_div[19:4]),
      .consequent_expr(baud_updated)
      );

   // Ensure reg_baud_cntr_f change only if UART is enabled
   // or if write to baud rate divider
   assert_implication
     #(`OVL_ERROR,`OVL_ASSERT,
       "Unexpected baud rate divider change")
   u_ovl_reg_baud_cntr_f_change
     (.clk(PCLK), .reset_n(PRESETn),
      .antecedent_expr(ovl_last_reg_baud_cntr_f!=reg_baud_cntr_f),
      .consequent_expr(ovl_last_baud_div_en | ovl_last_baud_updated )
      );

   // Ensure tx_buf_full is set to 1 after write to TX buffer (PADDR[11:2]==0)
   assert_next
     #(`OVL_ERROR, 1,1,0, `OVL_ASSERT,
      "tx_buf_full should be asserted after write to TX buffer")
   u_ovl_tx_buf_full
    (.clk(PCLK),  .reset_n(PRESETn),
     .start_event (PSEL & (~PENABLE) & PWRITE & (PADDR[11:2] == 10'h000)),
     .test_expr   (tx_buf_full)
     );

   // If last tx_state=0 (idle) or 1 (wait for tick), TXD = 1.
   assert_next
     #(`OVL_ERROR, 1,1,0, `OVL_ASSERT,
      "TXD should be 1 when idle or just before data transmission")
   u_ovl_txd_state_0_1
    (.clk(PCLK),  .reset_n(PRESETn),
     .start_event ((tx_state==4'd0)|(tx_state==4'd1)),
     .test_expr   (TXD==1'b1)
     );

   // If last tx_state=2 (start bit), TXD = 0.
   assert_next
     #(`OVL_ERROR, 1,1,0, `OVL_ASSERT,
      "TXD should be 0 when output start bit")
   u_ovl_txd_state_2
    (.clk(PCLK),  .reset_n(PRESETn),
     .start_event (tx_state==4'd2),
     .test_expr   (TXD==1'b0)
     );

   // If last tx_state=3-10 (D0 to D7), TXD = anything (tx_shift_buf[0]).
   assert_next
     #(`OVL_ERROR, 1,1,0, `OVL_ASSERT,
      "TXD should be same as first bit of shift register during transfer")
   u_ovl_txd_state_3_to_10
    (.clk(PCLK),  .reset_n(PRESETn),
     .start_event ((tx_state>4'd2) & (tx_state<4'd11)),
     .test_expr   (TXD==ovl_last_tx_shift_buf_0)
     );

   // If last tx_state=11 (stop bit), TXD = 1.
   assert_next
     #(`OVL_ERROR, 1,1,0, `OVL_ASSERT,
      "TXD should be 1 when output stop bit")
   u_ovl_txd_state_11
    (.clk(PCLK),  .reset_n(PRESETn),
     .start_event (tx_state==4'd11),
     .test_expr   (TXD==1'b1)
     );

   // Duration of tx_state in 2 to 11 must have 16 reg_baud_tick
   // (unless high speed test mode has been active)
   assert_implication
     #(`OVL_ERROR,`OVL_ASSERT,
     "Duration of tx_state when in state 2 to state 11 should have 16 ticks")
   u_ovl_width_of_tx_state
     (.clk(PCLK), .reset_n(PRESETn),
      .antecedent_expr((tx_state!=ovl_reg_last_tx_state) &      // at state change
       (ovl_reg_last_tx_state>4'd1)&(ovl_reg_last_tx_state<4'd12) & // from state 2 to 11
       (ovl_reg_hs_test_mode_triggered==1'b0)), // high speed test mode not triggered
      .consequent_expr((ovl_reg_tx_tick_count==8'd15) | (ovl_reg_tx_tick_count==8'd16))
        // count from 0 to 15 (16 ticks)
     );


   // In high speed test mode, tx_state must change if it is in range of 2 to 11
   assert_next
     #(`OVL_ERROR, 1,1,0, `OVL_ASSERT,
       "Duration of tx_state should be 1 cycle if high speed test mode is enabled")
   u_ovl_width_of_tx_state_in_high_speed_test_mode
     (.clk(PCLK), .reset_n(PRESETn),
      .start_event((tx_state>4'd1)&(tx_state<4'd12) & reg_ctrl[6]),
      .test_expr  (tx_state != ovl_reg_last_tx_state)
      );

   // Duration of rx_state in 1 must have 8 reg_baud_tick
   assert_implication
     #(`OVL_ERROR,`OVL_ASSERT,
     "Duration of rx_state when state 1 should have 8 ticks")
   u_ovl_width_of_rx_state_1
     (.clk(PCLK), .reset_n(PRESETn),
      .antecedent_expr((rx_state!=ovl_reg_last_rx_state) & // at state change
       (ovl_reg_last_rx_state==4'd1)), // last state was state 1
      .consequent_expr((ovl_reg_rx_tick_count==8'd7)|(ovl_reg_rx_tick_count==8'd8))
        // count from 0 to 7 (8 ticks)
     );

   // Duration of rx_state in 2 to 10 must have 16 reg_baud_tick
   assert_implication
     #(`OVL_ERROR,`OVL_ASSERT,
     "Duration of rx_state when in state 2 to state 10 should have 16 ticks")
   u_ovl_width_of_rx_state_data
     (.clk(PCLK), .reset_n(PRESETn),
      .antecedent_expr((rx_state!=ovl_reg_last_rx_state) &    // at state change
       (ovl_reg_last_rx_state>4'd1)&(ovl_reg_last_rx_state<4'd11)),  // from state 2 to 9
      .consequent_expr((ovl_reg_rx_tick_count==8'd15)|(ovl_reg_rx_tick_count==8'd16))
         // count from 0 to 15 (16 ticks)
     );

   // UARTINT must be 0 if TXINT, RXINT, TXOVRINT and RXOVRINT are all 0
   assert_implication
     #(`OVL_ERROR,`OVL_ASSERT,
     "UARTINT must be 0 if TXINT, RXINT, TXOVRINT and RXOVRINT are all 0")
   u_ovl_uartint_mismatch
     (.clk(PCLK), .reset_n(PRESETn),
      .antecedent_expr((TXINT | RXINT | TXOVRINT | RXOVRINT) == 1'b0), // No interrupt
      .consequent_expr(UARTINT==1'b0) // Combined interrupt = 0
     );

    // TXINT should be asserted when TX interrupt enabled and transmit buffer is available
    assert_next
    #(`OVL_ERROR, 1,1,0, `OVL_ASSERT,
    "TXINT should be triggered when enabled")
    u_ovl_txint_enable
      (.clk(PCLK ), .reset_n (PRESETn),
     .start_event (reg_ctrl[0] & reg_ctrl[2] & tx_buf_full & tx_buf_clear),
     .test_expr   (TXINT == 1'b1)
     );

   // There should be no rising edge of TXINT if transmit is disabled or transmit interrupt is disabled
    assert_next
    #(`OVL_ERROR, 1,1,0, `OVL_ASSERT,
    "TXINT should not be triggered when disabled")
    u_ovl_txint_disable
      (.clk(PCLK ), .reset_n (PRESETn),
     .start_event (((reg_ctrl[0]==1'b0) | (reg_ctrl[2]==1'b0)) & (TXINT == 1'b0)),
     .test_expr   (TXINT == 1'b0)
     );

   // if TXINT falling edge, there must has been a write to INTCLEAR register with bit[0]=1
   assert_implication
     #(`OVL_ERROR,`OVL_ASSERT,
     "When there is a falling edge of TXINT, there must has been a write to INTCLEAR")
   u_ovl_txint_clear
     (.clk(PCLK), .reset_n(PRESETn),
      .antecedent_expr(ovl_last_txint & (~TXINT)), // Falling edge of TXINT
      .consequent_expr(ovl_last_psel & ovl_last_pwrite &
      (ovl_last_paddr==10'h003) & (ovl_last_pwdata[0]) ) // There must has been a write to INTCLEAR
     );

    // RXINT should be asserted when RX interrupt enabled and a new data is received
    assert_next
    #(`OVL_ERROR, 1,1,0, `OVL_ASSERT,
    "RXINT should be triggered when enabled")
    u_ovl_rxint_enable
      (.clk(PCLK ), .reset_n (PRESETn),
     .start_event (reg_ctrl[3] & (rx_state==9) & (nxt_rx_state==10)),
     .test_expr   (RXINT == 1'b1)
     );

Next12
HierarchyFilesModulesSignalsTasksFunctionsHelp

This page: Created:Wed Apr 6 17:30:52 2022
From: ../verilog/cmsdk_apb_uart_streamio.v

Verilog converted to html by v2html 7.30.1.3 (written by Costas Calamvokis).Help