mirror of
				https://github.com/openhwgroup/cvw
				synced 2025-02-11 06:05:49 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			194 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
///////////////////////////////////////////////////////////////////////
 | 
						|
// uart.c
 | 
						|
//
 | 
						|
// Written: Jaocb Pease jacob.pease@okstate.edu 7/22/2024
 | 
						|
//
 | 
						|
// Purpose: Uart printing functions, as well as functions for printing
 | 
						|
//          hex, decimal, and floating point numbers.
 | 
						|
//
 | 
						|
// 
 | 
						|
//
 | 
						|
// A component of the Wally configurable RISC-V project.
 | 
						|
// 
 | 
						|
// Copyright (C) 2021-23 Harvey Mudd College & Oklahoma State University
 | 
						|
//
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
 | 
						|
//
 | 
						|
// Licensed under the Solderpad Hardware License v 2.1 (the
 | 
						|
// “License”); you may not use this file except in compliance with the
 | 
						|
// License, or, at your option, the Apache License version 2.0. You
 | 
						|
// may obtain a copy of the License at
 | 
						|
//
 | 
						|
// https://solderpad.org/licenses/SHL-2.1/
 | 
						|
//
 | 
						|
// Unless required by applicable law or agreed to in writing, any work
 | 
						|
// distributed under the License is distributed on an “AS IS” BASIS,
 | 
						|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
						|
// implied. See the License for the specific language governing
 | 
						|
// permissions and limitations under the License.
 | 
						|
///////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
#include "uart.h"
 | 
						|
 | 
						|
void write_reg_u8(uintptr_t addr, uint8_t value)
 | 
						|
{
 | 
						|
  volatile uint8_t *loc_addr = (volatile uint8_t *)addr;
 | 
						|
  *loc_addr = value;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t read_reg_u8(uintptr_t addr)
 | 
						|
{
 | 
						|
  return *(volatile uint8_t *)addr;
 | 
						|
}
 | 
						|
 | 
						|
int is_transmit_empty()
 | 
						|
{
 | 
						|
  return read_reg_u8(UART_LSR) & 0x20;
 | 
						|
}
 | 
						|
 | 
						|
int is_receive_empty()
 | 
						|
{
 | 
						|
  return !(read_reg_u8(UART_LSR) & 0x1);
 | 
						|
}
 | 
						|
 | 
						|
void write_serial(char a)
 | 
						|
{
 | 
						|
  while (is_transmit_empty() == 0) {};
 | 
						|
 | 
						|
  write_reg_u8(UART_THR, a);
 | 
						|
}
 | 
						|
 | 
						|
void init_uart(uint32_t freq, uint32_t baud)
 | 
						|
{
 | 
						|
  // Alternative divisor calculation. From OpenSBI code.
 | 
						|
  // Reduces error for every possible frequency.
 | 
						|
  uint32_t divisor = (freq + 8 * baud) /(baud << 4);
 | 
						|
 | 
						|
  write_reg_u8(UART_IER, 0x00);                   // Disable all interrupts
 | 
						|
  write_reg_u8(UART_LCR, 0x80);                   // Enable DLAB (set baud rate divisor)
 | 
						|
  write_reg_u8(UART_DLL, divisor & 0xFF);         // divisor (lo byte)
 | 
						|
  write_reg_u8(UART_DLM, (divisor >> 8) & 0xFF);  // divisor (hi byte)
 | 
						|
  write_reg_u8(UART_LCR, 0x03);                   // 8 bits, no parity, one stop bit
 | 
						|
  write_reg_u8(UART_FCR, 0xC7);                   // Enable FIFO, clear them, with 14-byte threshold
 | 
						|
}
 | 
						|
 | 
						|
void print_uart(const char *str)
 | 
						|
{
 | 
						|
  const char *cur = &str[0];
 | 
						|
  while (*cur != '\0') {
 | 
						|
    write_serial((uint8_t)*cur);
 | 
						|
    ++cur;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
uint8_t bin_to_hex_table[16] = {
 | 
						|
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
 | 
						|
 | 
						|
void bin_to_hex(uint8_t inp, uint8_t res[2])
 | 
						|
{
 | 
						|
  res[1] = bin_to_hex_table[inp & 0xf];
 | 
						|
  res[0] = bin_to_hex_table[(inp >> 4) & 0xf];
 | 
						|
  return;
 | 
						|
}
 | 
						|
 | 
						|
void print_uart_hex(uint64_t addr, int n)
 | 
						|
{
 | 
						|
  int i;
 | 
						|
  for (i = n - 1; i > -1; i--) {
 | 
						|
    uint8_t cur = (addr >> (i * 8)) & 0xff;
 | 
						|
    uint8_t hex[2];
 | 
						|
    bin_to_hex(cur, hex);
 | 
						|
    write_serial(hex[0]);
 | 
						|
    write_serial(hex[1]);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void print_uart_dec(uint64_t addr) {
 | 
						|
 | 
						|
  // floor(log(2^64)) = 19
 | 
						|
  char str[19] = {'\0'};
 | 
						|
  uint8_t length = 1;
 | 
						|
  
 | 
						|
  uint64_t cur = addr;
 | 
						|
  while (cur != 0) {
 | 
						|
    char digit = bin_to_hex_table[cur % 10];
 | 
						|
    // write_serial(digit);
 | 
						|
    str[length] = digit;
 | 
						|
    cur = cur/10;
 | 
						|
    length++;
 | 
						|
  }
 | 
						|
 | 
						|
  for (int i = length; i > -1; i--) {
 | 
						|
    write_serial(str[i]);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Print a floating point number on the UART 
 | 
						|
void print_uart_float(float num, int precision) {
 | 
						|
  char str[32] = {'\0'};
 | 
						|
  char digit;
 | 
						|
  uint8_t length = precision + 1;
 | 
						|
  int i;
 | 
						|
  uint64_t cur;
 | 
						|
  
 | 
						|
  str[precision] = '.';
 | 
						|
 | 
						|
  int pow = 1;
 | 
						|
 | 
						|
  // Calculate power for precision
 | 
						|
  for (i = 0; i < precision; i++) {
 | 
						|
    pow = pow * 10;
 | 
						|
  }
 | 
						|
  
 | 
						|
  cur = (uint64_t)(num * pow);
 | 
						|
  for (i = 0; i < precision; i++) {
 | 
						|
    digit = bin_to_hex_table[cur % 10];
 | 
						|
    str[i] = digit;
 | 
						|
    cur = cur / 10;
 | 
						|
  }
 | 
						|
 | 
						|
  cur = (uint64_t)num;
 | 
						|
  do {
 | 
						|
    digit = bin_to_hex_table[cur % 10];
 | 
						|
    str[length] = digit;
 | 
						|
    cur = cur/10;
 | 
						|
    length++;
 | 
						|
  } while (cur != 0);
 | 
						|
  
 | 
						|
  for (i = length; i > -1; i--) {
 | 
						|
    write_serial(str[i]);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* void print_uart_int(uint32_t addr) */
 | 
						|
/* { */
 | 
						|
/*   int i; */
 | 
						|
/*   for (i = 3; i > -1; i--)  { */
 | 
						|
/*     uint8_t cur = (addr >> (i * 8)) & 0xff; */
 | 
						|
/*     uint8_t hex[2]; */
 | 
						|
/*     bin_to_hex(cur, hex); */
 | 
						|
/*     write_serial(hex[0]); */
 | 
						|
/*     write_serial(hex[1]); */
 | 
						|
/*   } */
 | 
						|
/* } */
 | 
						|
 | 
						|
/* void print_uart_addr(uint64_t addr) */
 | 
						|
/* { */
 | 
						|
/*   int i; */
 | 
						|
/*   for (i = 7; i > -1; i--) { */
 | 
						|
/*     uint8_t cur = (addr >> (i * 8)) & 0xff; */
 | 
						|
/*     uint8_t hex[2]; */
 | 
						|
/*     bin_to_hex(cur, hex); */
 | 
						|
/*     write_serial(hex[0]); */
 | 
						|
/*     write_serial(hex[1]); */
 | 
						|
/*   } */
 | 
						|
/* } */
 | 
						|
 | 
						|
/* void print_uart_byte(uint8_t byte) */
 | 
						|
/* { */
 | 
						|
/*   uint8_t hex[2]; */
 | 
						|
/*   bin_to_hex(byte, hex); */
 | 
						|
/*   write_serial(hex[0]); */
 | 
						|
/*   write_serial(hex[1]); */
 | 
						|
/* } */
 |