Skip to content

Commit

Permalink
putc() for sifive-trace UART driver
Browse files Browse the repository at this point in the history
This will allow redirecting stdout via the dts file and sending
all stdout out as trace messages instead of serial uart messages.
  • Loading branch information
bradseevers authored and nategraff-sifive committed Aug 19, 2019
1 parent 2df07a2 commit fcfdf57
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 16 deletions.
2 changes: 1 addition & 1 deletion metal/drivers/sifive_trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
#ifndef METAL__DRIVERS__SIFIVE_TRACE_H
#define METAL__DRIVERS__SIFIVE_TRACE_H

#include <metal/compiler.h>
#include <metal/io.h>
#include <metal/uart.h>
#include <metal/compiler.h>

struct __metal_driver_vtable_sifive_trace {
const struct metal_uart_vtable uart;
Expand Down
81 changes: 66 additions & 15 deletions src/drivers/sifive_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,88 @@
#include <metal/drivers/sifive_trace.h>
#include <metal/machine.h>

#define TRACE_REG(base, offset) (((unsigned long)base + offset))
#define TRACE_REGB(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u8 *)TRACE_REG(base, offset)))
#define TRACE_REGW(base, offset) (__METAL_ACCESS_ONCE((__metal_io_u32 *)TRACE_REG(base, offset)))
#define TRACE_REG(offset) (((unsigned long)base + (offset)))
#define TRACE_REG8(offset) \
(__METAL_ACCESS_ONCE((__metal_io_u8 *)TRACE_REG(offset)))
#define TRACE_REG16(offset) \
(__METAL_ACCESS_ONCE((__metal_io_u16 *)TRACE_REG(offset)))
#define TRACE_REG32(offset) \
(__METAL_ACCESS_ONCE((__metal_io_u32 *)TRACE_REG(offset)))

int __metal_driver_sifive_trace_putc(struct metal_uart *trace, unsigned char c)
{
static void write_itc_uint32(struct metal_uart *trace, uint32_t data) {
long base = __metal_driver_sifive_trace_base(trace);
return 0;

TRACE_REG32(METAL_SIFIVE_TRACE_ITCSTIMULUS) = data;
}

static void write_itc_uint16(struct metal_uart *trace, uint16_t data) {
long base = __metal_driver_sifive_trace_base(trace);

TRACE_REG16(METAL_SIFIVE_TRACE_ITCSTIMULUS + 2) = data;
}

int __metal_driver_sifive_trace_getc(struct metal_uart *trace, unsigned char *c)
{
static void write_itc_uint8(struct metal_uart *trace, uint8_t data) {
long base = __metal_driver_sifive_trace_base(trace);
return 0;

TRACE_REG8(METAL_SIFIVE_TRACE_ITCSTIMULUS + 3) = data;
}

int __metal_driver_sifive_trace_putc(struct metal_uart *trace,
unsigned char c) {
static uint32_t buffer = 0;
static int bytes_in_buffer = 0;

buffer |= (((uint32_t)c) << (bytes_in_buffer * 8));

bytes_in_buffer += 1;

if (bytes_in_buffer >= 4) {
write_itc_uint32(trace, buffer);

buffer = 0;
bytes_in_buffer = 0;
} else if ((c == '\n') || (c == '\r')) { // partial write
switch (bytes_in_buffer) {
case 3: // do a full word write
write_itc_uint16(trace, (uint16_t)(buffer));
write_itc_uint8(trace, (uint8_t)(buffer >> 16));
break;
case 2: // do a 16 bit write
write_itc_uint16(trace, (uint16_t)buffer);
break;
case 1: // do a 1 byte write
write_itc_uint8(trace, (uint8_t)buffer);
break;
}

buffer = 0;
bytes_in_buffer = 0;
}

return (int)c;
}

void __metal_driver_sifive_trace_init(struct metal_uart *trace, int baud_rate)
{
void __metal_driver_sifive_trace_init(struct metal_uart *trace, int baud_rate) {
// The only init we do here is to make sure ITC 0 is enabled. It is up to
// Freedom Studio or other mechanisms to make sure tracing is enabled. If we
// try to enable tracing here, it will likely conflict with Freedom Studio,
// and they will just fight with each other.

long base = __metal_driver_sifive_trace_base(trace);

TRACE_REG32(METAL_SIFIVE_TRACE_ITCTRACEENABLE) |= 0x00000001;
}

__METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_trace) = {
.uart.init = __metal_driver_sifive_trace_init,
.uart.putc = __metal_driver_sifive_trace_putc,
.uart.getc = __metal_driver_sifive_trace_getc,
.uart.init = __metal_driver_sifive_trace_init,
.uart.putc = __metal_driver_sifive_trace_putc,
.uart.getc = NULL,

.uart.get_baud_rate = NULL,
.uart.set_baud_rate = NULL,

.uart.controller_interrupt = NULL,
.uart.get_interrupt_id = NULL,
.uart.get_interrupt_id = NULL,
};

#endif /* METAL_SIFIVE_TRACE */

0 comments on commit fcfdf57

Please sign in to comment.