diff options
author | Zachary Yedidia <zyedidia@gmail.com> | 2022-05-13 15:17:55 -0700 |
---|---|---|
committer | Zachary Yedidia <zyedidia@gmail.com> | 2022-05-13 15:17:55 -0700 |
commit | 4d16c701e4e498a5d2979cbc194b4e32f2b620b2 (patch) | |
tree | 7eb5c46bd53871fdb7f44be6bb984912b3fcb0fd | |
parent | 5adca42ff4e8a2a6352408158e062d6b22a677d7 (diff) | |
parent | 8c6cb5241097f2943bfe8e69d97371fc1f16cc9c (diff) |
Merge branch 'exo' of ssh://github.com/zyedidia/pios into exo
-rw-r--r-- | kern/Makefile | 5 | ||||
-rw-r--r-- | kern/interrupts-asm.s | 79 | ||||
-rw-r--r-- | kern/interrupts.c | 13 | ||||
-rw-r--r-- | kern/kern.c | 19 | ||||
-rw-r--r-- | kern/proc.c | 21 | ||||
-rw-r--r-- | kern/proc.h | 1 | ||||
-rw-r--r-- | kern/syscall.c | 4 | ||||
-rw-r--r-- | kern/syscall_list.h | 1 | ||||
-rw-r--r-- | kern/timer.c | 43 | ||||
-rw-r--r-- | kern/timer.h | 6 | ||||
-rw-r--r-- | pid_os/Makefile | 32 | ||||
-rw-r--r-- | pid_os/bits.h | 78 | ||||
-rw-r--r-- | pid_os/dev.h | 5 | ||||
-rw-r--r-- | pid_os/gpio.c | 19 | ||||
-rw-r--r-- | pid_os/gpio.h | 75 | ||||
-rw-r--r-- | pid_os/memmap.ld | 32 | ||||
-rw-r--r-- | pid_os/pidos.c | 18 | ||||
-rw-r--r-- | pid_os/start.s | 34 | ||||
-rw-r--r-- | pid_os/uart.c | 105 | ||||
-rw-r--r-- | pid_os/uart.h | 18 |
20 files changed, 563 insertions, 45 deletions
diff --git a/kern/Makefile b/kern/Makefile index 846ba69..f987b2a 100644 --- a/kern/Makefile +++ b/kern/Makefile @@ -54,4 +54,7 @@ p-basic.o: p-hello.o: make -C $(PIOS)/hello_os exostall -.PHONY: format all install +p-pidos.o: + make -C $(PIOS)/pid_os exostall + +.PHONY: format all install p-basic.o p-hello.o p-pidos.o diff --git a/kern/interrupts-asm.s b/kern/interrupts-asm.s index ee440aa..c90a24c 100644 --- a/kern/interrupts-asm.s +++ b/kern/interrupts-asm.s @@ -4,14 +4,14 @@ .globl _interrupt_table_end .align 5 _interrupt_table: - ldr pc, _reset_h - ldr pc, _undef_insn_h - ldr pc, _software_irq_h - ldr pc, _prefetch_abort_h - ldr pc, _data_abort_h - ldr pc, _reset_h - ldr pc, _irq_h - ldr pc, _fiq_h + ldr pc, _reset_h + ldr pc, _undef_insn_h + ldr pc, _software_irq_h + ldr pc, _prefetch_abort_h + ldr pc, _data_abort_h + ldr pc, _reset_h + ldr pc, _irq_h + ldr pc, _fiq_h _reset_h: .word asm_reset _undef_insn_h: .word asm_undef_insn @@ -23,32 +23,39 @@ _fiq_h: .word asm_fiq _interrupt_table_end: asm_reset: - ldr sp, =kstack - bl reboot + ldr sp, =kstack + bl reboot asm_undef_insn: - ldr sp, =kstack - ldr pc, _vec_undef_insn + ldr sp, =kstack + ldr pc, _vec_undef_insn asm_software_irq: - ldr sp, =kstack - sub lr, lr, #4 - push {lr} - stmfd sp, {r0-r14}^ - sub sp, sp, #60 - mov r0, sp - bl syscall - ldm sp, {r0-r15}^ + ldr sp, =kstack + // sub lr, lr, #4 + push {lr} + stmfd sp, {r0-r14}^ + sub sp, sp, #60 + mov r0, sp + bl syscall + ldm sp, {r0-r15}^ asm_prefetch_abort: - ldr sp, =kstack - ldr pc, _vec_prefetch_abort + ldr sp, =kstack + ldr pc, _vec_prefetch_abort asm_data_abort: - ldr sp, =kstack - ldr pc, _vec_data_abort + ldr sp, =kstack + ldr pc, _vec_data_abort asm_irq: - ldr sp, =kstack - ldr pc, _vec_irq + ldr sp, =kstack + sub lr, lr, #4 + push {lr} + stmfd sp, {r0-r14}^ + sub sp, sp, #60 + mov r0, sp + ldr r1, _vec_irq + blx r1 + ldm sp, {r0-r15}^ asm_fiq: - ldr sp, =kstack - ldr pc, _vec_fiq + ldr sp, =kstack + ldr pc, _vec_fiq .globl _vector_table _vector_table: @@ -61,14 +68,14 @@ _vec_fiq: .word vec_fiq .globl enable_interrupts enable_interrupts: - mrs r0, cpsr - bic r0, r0, #(1 << 7) - msr cpsr_c, r0 - bx lr + mrs r0, cpsr + bic r0, r0, #(1 << 7) + msr cpsr_c, r0 + bx lr .globl disable_interrupts disable_interrupts: - mrs r0, cpsr - orr r0, r0, #(1 << 7) - msr cpsr_c, r0 - bx lr + mrs r0, cpsr + orr r0, r0, #(1 << 7) + msr cpsr_c, r0 + bx lr diff --git a/kern/interrupts.c b/kern/interrupts.c index f211398..f140212 100644 --- a/kern/interrupts.c +++ b/kern/interrupts.c @@ -102,8 +102,17 @@ void __attribute__((interrupt("ABORT"))) vec_data_abort() { printf("!!!!!!! LR was: %x\n", lr); panic_unhandled("data_abort"); } -void __attribute__((interrupt("IRQ"))) vec_irq() { - panic_unhandled("irq"); +#include "proc.h" +#include "timer.h" +void vec_irq(regs_t *regs) { + dev_barrier(); + if (!timer_has_irq()) return; + + proc_scheduler_irq(regs); + + dev_barrier(); + timer_clear_irq(); + dev_barrier(); } void __attribute__((interrupt("FIQ"))) vec_fiq() { panic_unhandled("fiq"); diff --git a/kern/kern.c b/kern/kern.c index 9e36502..a99a8ce 100644 --- a/kern/kern.c +++ b/kern/kern.c @@ -10,6 +10,7 @@ #include "sys.h" #include "uart.h" #include "vm.h" +#include "timer.h" void reboot() { printf("DONE!!!\n"); @@ -38,15 +39,23 @@ void kernel_start() { uart_init(115200); init_printf(NULL, uart_putc); - irq_init(); + kmalloc_init(); + irq_init(); + irq_enable(BASIC_TIMER_IRQ); + timer_irq_load(0x1000); + printf("kernel booted\n"); - extern unsigned char _binary_hello_bin_start; - extern unsigned char _binary_hello_bin_end; - proc_t *p_hello = proc_new(&_binary_hello_bin_start, (size_t) (&_binary_hello_bin_end - &_binary_hello_bin_start)); - proc_run(p_hello); + extern unsigned char _binary_pidos_bin_start; + extern unsigned char _binary_pidos_bin_end; + + proc_t *p_pidos_1 = proc_new(&_binary_pidos_bin_start, (size_t) (&_binary_pidos_bin_end - &_binary_pidos_bin_start)); + proc_new(&_binary_pidos_bin_start, (size_t) (&_binary_pidos_bin_end - &_binary_pidos_bin_start)); + + // TODO/NOTE(masot): Currently, proc_run enables IRQs + proc_run(p_pidos_1); reboot(); return; diff --git a/kern/proc.c b/kern/proc.c index 4df3f3a..d08fad2 100644 --- a/kern/proc.c +++ b/kern/proc.c @@ -42,6 +42,7 @@ void __attribute__((noreturn)) proc_run(proc_t *proc) { vm_set_pt(proc->pt); curproc = proc; + enable_interrupts(); // TODO: Set this in the SPSR // NOTE: To use SPSR, need to be sure we are *NOT* in user/system mode. // TODO(masot): add an assert like that set_spsr((get_cpsr() & ~0b11111) | 0b10000); @@ -49,3 +50,23 @@ void __attribute__((noreturn)) proc_run(proc_t *proc) { while (1) { } } + +thread_id = 0; + +void swippityswap(regs_t *live_state, proc_t *new_thread, proc_t *old_thread) { + memcpy(&(old_thread->regs), live_state, sizeof(regs_t)); + memcpy(live_state, &(new_thread->regs), sizeof(regs_t)); +} + + +void proc_scheduler_irq(regs_t *regs) { + pid_t curr_pid = curproc->id, + next_pid = (curr_pid + 1) % id; + + swippityswap(regs, &(procs[next_pid]), &(procs[curr_pid])); + + curproc->state = PROC_RUNNABLE; + curproc = &(procs[next_pid]); + curproc->state = PROC_RUNNING; + vm_set_pt(curproc->pt); +} diff --git a/kern/proc.h b/kern/proc.h index d908d56..592538e 100644 --- a/kern/proc.h +++ b/kern/proc.h @@ -48,3 +48,4 @@ extern proc_t *curproc; proc_t *proc_new(uint8_t *code, size_t codesz); void proc_run(proc_t *proc); +void proc_scheduler_irq(regs_t *regs); diff --git a/kern/syscall.c b/kern/syscall.c index c108752..b3dab38 100644 --- a/kern/syscall.c +++ b/kern/syscall.c @@ -51,9 +51,11 @@ void syscall(regs_t *regs) { case SYSCALL_VM_MAP: regs->r0 = syscall_vm_map(regs->r1, regs->r2, regs->r3, regs->r4); break; + case SYSCALL_GET_PID: + regs->r0 = curproc->id; + break; default: panic("unhandled syscall %d\n", sysno); break; } - regs->pc += 4; } diff --git a/kern/syscall_list.h b/kern/syscall_list.h index e22d70d..9e4366a 100644 --- a/kern/syscall_list.h +++ b/kern/syscall_list.h @@ -4,6 +4,7 @@ #define SYSCALL_ALLOC_PAGE 1 #define SYSCALL_DEALLOC_PAGE 2 #define SYSCALL_VM_MAP 3 +#define SYSCALL_GET_PID 4 // NOTE: DO NOT CHANGE THESE without changing vm.h #define SYSCALL_ARG_ANY_PAGE 0 diff --git a/kern/timer.c b/kern/timer.c new file mode 100644 index 0000000..addfbcf --- /dev/null +++ b/kern/timer.c @@ -0,0 +1,43 @@ +#include <stdbool.h> +#include <stdint.h> + +typedef struct { + uint32_t load; + uint32_t value; + uint32_t ctrl; + uint32_t irq_clear; + uint32_t raw_irq; + uint32_t masked_irq; + uint32_t reload; + uint32_t pre_divider; + uint32_t free_running_counter; +} timer_t; + +#define TIMER_CTRL_32BIT (1 << 1) + +#define TIMER_CTRL_PRESCALE_1 (0 << 2) +#define TIMER_CTRL_PRESCALE_16 (1 << 2) +#define TIMER_CTRL_PRESCALE_256 (2 << 2) + +#define TIMER_CTRL_INT_ENABLE (1 << 5) +#define TIMER_CTRL_INT_DISABLE (0 << 5) + +#define TIMER_CTRL_ENABLE (1 << 7) +#define TIMER_CTRL_DISABLE (0 << 7) + +#define pa2ka(pa) (((pa) | (1UL << 31))) +static volatile timer_t* const timer = (timer_t*) pa2ka(0x2000b400); + +void timer_irq_load(uint32_t load) { + timer->load = load; + timer->ctrl = TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_INT_ENABLE | + TIMER_CTRL_PRESCALE_256; +} + +bool timer_has_irq() { + return timer->masked_irq; +} + +void timer_clear_irq() { + timer->irq_clear = 1; +} diff --git a/kern/timer.h b/kern/timer.h index 95c22b7..28840b5 100644 --- a/kern/timer.h +++ b/kern/timer.h @@ -1,6 +1,8 @@ #pragma once #include "sys.h" +#include <stdbool.h> +#include <stdint.h> static inline void timer_init() { asm volatile("mcr p15, 0, %0, c15, c12, 0" ::"r"(1)); @@ -34,3 +36,7 @@ static inline void delay_us(unsigned us) { static inline void delay_ms(unsigned ms) { delay_us(ms * 1000); } + +void timer_irq_load(uint32_t load); +bool timer_has_irq(); +void timer_clear_irq(); diff --git a/pid_os/Makefile b/pid_os/Makefile new file mode 100644 index 0000000..614b73c --- /dev/null +++ b/pid_os/Makefile @@ -0,0 +1,32 @@ +include ../defs.mk + +CFLAGS += -MMD + +MEMMAP = memmap.ld +INCLUDE = -I$(KERN) -I$(PIOS) +CFLAGS += $(INCLUDE) +ASFLAGS += $(INCLUDE) +CPPFLAGS += $(INCLUDE) +DEP = $(KERN_OBJ:.o=.d) + +OBJ = pidos.o start.o uart.o gpio.o ../libc/tinyprintf.o + +all: pidos.bin + +pidos.elf: $(OBJ) + $(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@ + +$(PIOS)/kern/p-pidos.o: pidos.bin + $(LD) -r -b binary -o $@ $< + +exostall: $(PIOS)/kern/p-pidos.o + +clean: + rm -f *.d *.list *.o *.elf *.bin + +-include $(DEP) + +format: + clang-format -i $(PIOS_CSRC) $(PIOS_HSRC) + +.PHONY: format all install diff --git a/pid_os/bits.h b/pid_os/bits.h new file mode 100644 index 0000000..f0f16a2 --- /dev/null +++ b/pid_os/bits.h @@ -0,0 +1,78 @@ +#pragma once + +#include <stdint.h> + +static inline uint32_t bit_clr(uint32_t x, unsigned bit) { + return x & ~(1 << bit); +} + +static inline uint32_t bit_set(uint32_t x, unsigned bit) { + return x | (1 << bit); +} + +static inline uint32_t bit_assign(uint32_t x, unsigned bit, unsigned val) { + x = bit_clr(x, bit); + return x | (val << bit); +} + +#define bit_isset bit_is_on +#define bit_get bit_is_on + +static inline unsigned bit_is_on(uint32_t x, unsigned bit) { + return (x >> bit) & 1; +} +static inline unsigned bit_is_off(uint32_t x, unsigned bit) { + return bit_is_on(x, bit) == 0; +} + +static inline uint32_t bits_mask(unsigned nbits) { + if (nbits == 32) + return ~0; + return (1 << nbits) - 1; +} + +static inline uint32_t bits_get(uint32_t x, unsigned lb, unsigned ub) { + return (x >> lb) & bits_mask(ub - lb + 1); +} + +static inline uint32_t bits_clr(uint32_t x, unsigned lb, unsigned ub) { + uint32_t mask = bits_mask(ub - lb + 1); + return x & ~(mask << lb); +} + +static inline uint32_t bits_set(uint32_t x, + unsigned lb, + unsigned ub, + uint32_t v) { + return bits_clr(x, lb, ub) | (v << lb); +} + +static inline unsigned bits_eq(uint32_t x, + unsigned lb, + unsigned ub, + uint32_t val) { + return bits_get(x, lb, ub) == val; +} + +static inline unsigned bit_count(uint32_t x) { + unsigned cnt = 0; + for (unsigned i = 0; i < 32; i++) + if (bit_is_on(x, i)) + cnt++; + return cnt; +} + +static inline uint32_t bits_union(uint32_t x, uint32_t y) { + return x | y; +} + +static inline uint32_t bits_intersect(uint32_t x, uint32_t y) { + return x & y; +} +static inline uint32_t bits_not(uint32_t x) { + return ~x; +} + +static inline uint32_t bits_diff(uint32_t A, uint32_t B) { + return bits_intersect(A, bits_not(B)); +} diff --git a/pid_os/dev.h b/pid_os/dev.h new file mode 100644 index 0000000..1f644f7 --- /dev/null +++ b/pid_os/dev.h @@ -0,0 +1,5 @@ +#pragma once + +static inline void dev_barrier() { + asm volatile("mcr p15, 0, r0, c7, c10, 4"); +} diff --git a/pid_os/gpio.c b/pid_os/gpio.c new file mode 100644 index 0000000..1777031 --- /dev/null +++ b/pid_os/gpio.c @@ -0,0 +1,19 @@ +#include <stdbool.h> +#include <stdint.h> + +#include "bits.h" +#include "gpio.h" + +static volatile uint32_t* gpio_fsel = (uint32_t*) (GPIO_BASE); + +void gpio_set_func(unsigned pin, gpio_func_t fn) { + if (pin >= 32) + return; + unsigned off = (pin % 10) * 3; + unsigned idx = pin / 10; + + uint32_t v = gpio_fsel[idx]; + v &= ~(0b111 << off); + v |= fn << off; + gpio_fsel[idx] = v; +} diff --git a/pid_os/gpio.h b/pid_os/gpio.h new file mode 100644 index 0000000..d3dc3ab --- /dev/null +++ b/pid_os/gpio.h @@ -0,0 +1,75 @@ +#pragma once + +#include <stdbool.h> +#include <stdint.h> + +enum { + GPIO_TX = 14, + GPIO_RX = 15, + GPIO_SDA = 2, + GPIO_SCL = 3, +}; + +typedef enum { + GPIO_FUNC_INPUT = 0, + GPIO_FUNC_OUTPUT = 1, + GPIO_FUNC_ALT0 = 4, + GPIO_FUNC_ALT1 = 5, + GPIO_FUNC_ALT2 = 6, + GPIO_FUNC_ALT3 = 7, + GPIO_FUNC_ALT4 = 3, + GPIO_FUNC_ALT5 = 2, +} gpio_func_t; + +#define GPIO_BASE 0xa0200000 + +static volatile uint32_t* gpio_set = (uint32_t*) (GPIO_BASE + 0x1C); +static volatile uint32_t* gpio_clr = (uint32_t*) (GPIO_BASE + 0x28); +static volatile uint32_t* gpio_lev = (uint32_t*) (GPIO_BASE + 0x34); + +void gpio_set_func(unsigned pin, gpio_func_t fn); +void gpio_set_output(unsigned pin); +void gpio_set_on(unsigned pin); +void gpio_set_off(unsigned pin); +void gpio_set_input(unsigned pin); +void gpio_write(unsigned pin, bool v); +bool gpio_read(unsigned pin); + +static inline void gpio_set_on_fast(unsigned pin) { + gpio_set[0] = 1 << pin; +} + +static inline void gpio_set_off_fast(unsigned pin) { + gpio_clr[0] = 1 << pin; +} + +static inline void gpio_write_fast(unsigned pin, bool v) { + if (v) { + gpio_set_on_fast(pin); + } else { + gpio_set_off_fast(pin); + } +} + +static inline bool gpio_read_fast(unsigned pin) { + return (gpio_lev[0] >> pin) & 1; +} + +void gpio_set_pullup(unsigned pin); +void gpio_set_pulldown(unsigned pin); +void gpio_pud_off(unsigned pin); + +enum { + GPIO_INT0 = 49, + GPIO_INT1, + GPIO_INT2, + GPIO_INT3, +}; + +int is_gpio_int(unsigned gpio_int); +void gpio_int_rise(unsigned pin); +void gpio_int_fall(unsigned pin); +void gpio_int_rise_async(unsigned pin); +void gpio_int_fall_async(unsigned pin); +int gpio_event_detect(unsigned pin); +void gpio_event_clear(unsigned pin); diff --git a/pid_os/memmap.ld b/pid_os/memmap.ld new file mode 100644 index 0000000..f24fd56 --- /dev/null +++ b/pid_os/memmap.ld @@ -0,0 +1,32 @@ +SECTIONS +{ + .text 0x8000 : { + __code_start__ = .; + KEEP(*(.boot)) + *(.text*) + __code_end__ = .; + . = ALIGN(8); + } + .rodata : { + __rodata_start__ = .; + *(.rodata*) + __rodata_end__ = .; + } + .data : { + __data_start__ = .; + *(.data*) + . = ALIGN(4); + __data_end__ = .; + } + .bss : { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(8); + __bss_end__ = .; + . = ALIGN(8); + __prog_end__ = .; + __heap_start__ = .; + } +} diff --git a/pid_os/pidos.c b/pid_os/pidos.c new file mode 100644 index 0000000..9ef6f31 --- /dev/null +++ b/pid_os/pidos.c @@ -0,0 +1,18 @@ +#include "uart.h" +#include "../kern/syscall_list.h" + +extern uint32_t syscall(uint32_t syscall, ...); + +unsigned main() { + init_printf(NULL, uart_putc); + + uint32_t pid = syscall(SYSCALL_GET_PID); + while (true) { + printf("Hello from process %lu\n", pid); + for (size_t i = 0; i < (1 << 21); i++) { + asm volatile ("nop"); + } + } + + return 24; +} diff --git a/pid_os/start.s b/pid_os/start.s new file mode 100644 index 0000000..fb86cff --- /dev/null +++ b/pid_os/start.s @@ -0,0 +1,34 @@ +#include "../kern/syscall_list.h" + +#define STACK_ADDR 0x8000000 + +.section ".boot" + +.globl _start +_start: + mov r0, #SYSCALL_ALLOC_PAGE + mov r1, #SYSCALL_ARG_ANY_PAGE + mov r2, #SIZE_1MB + swi 0 // result in r0 + + mov r1, #STACK_ADDR // virtual page + sub r1, r1, #SIZE_1MB // start of page for stack + mov r2, r0 // physical page + mov r3, #0 // flags + mov r4, #SIZE_1MB // size + mov r0, #SYSCALL_VM_MAP + swi 0 + + mov sp, #STACK_ADDR // Now we have a stack ! + sub sp, sp, #4 + + bl main + + mov r1, r0 + mov r0, #SYSCALL_EXIT + swi 0 + +.globl syscall +syscall: + swi 0 + bx lr diff --git a/pid_os/uart.c b/pid_os/uart.c new file mode 100644 index 0000000..f69a791 --- /dev/null +++ b/pid_os/uart.c @@ -0,0 +1,105 @@ +#include <stdbool.h> +#include <stdint.h> + +#include "bits.h" +#include "dev.h" +#include "gpio.h" +#include "uart.h" + +typedef struct { + uint32_t io; + uint32_t ier; + uint32_t iir; + uint32_t lcr; + uint32_t mcr; + uint32_t lsr; + uint32_t msr; + uint32_t scratch; + uint32_t cntl; + uint32_t stat; + uint32_t baud; +} aux_periphs_t; + +#define ENABLE_UART 1 +#define RX_ENABLE (1 << 0) +#define TX_ENABLE (1 << 1) +#define CLEAR_TX_FIFO (1 << 1) +#define CLEAR_RX_FIFO (1 << 2) +#define CLEAR_FIFOS (CLEAR_TX_FIFO | CLEAR_RX_FIFO) +#define IIR_RESET ((0b11 << 6) | 1) + +// TODO: should eventually ask the kernel for access instead of using its pages +// (eventually these will be write protected) +#define pa2ka(pa) ((pa | (1 << 31))) +#define ka2pa(ka) ((ka & ~(1 << 31))) +static volatile uint32_t* const aux_enables = (uint32_t*) pa2ka(0x20215004); +static volatile aux_periphs_t* const uart = (aux_periphs_t*) pa2ka(0x20215040); + +void uart_init(unsigned baud) { + gpio_set_func(GPIO_TX, GPIO_FUNC_ALT5); + gpio_set_func(GPIO_RX, GPIO_FUNC_ALT5); + + dev_barrier(); + + *aux_enables = *aux_enables | ENABLE_UART; + + dev_barrier(); + + uart->cntl = 0; + uart->ier = 0; + uart->lcr = 0b11; + uart->mcr = 0; + uart->iir = IIR_RESET | CLEAR_FIFOS; + uart->baud = (250 * 1000 * 1000) / (baud * 8) - 1; + uart->cntl = RX_ENABLE | TX_ENABLE; + + dev_barrier(); +} + +bool uart_rx_empty() { + return bit_get(uart->stat, 0) == 0; +} + +unsigned uart_rx_sz() { + return bits_get(uart->stat, 16, 19); +} + +bool uart_can_tx() { + return bit_get(uart->stat, 1) != 0; +} + +uint8_t uart_rx() { + dev_barrier(); + while (uart_rx_empty()) + ; + uint8_t c = uart->io & 0xff; + dev_barrier(); + return c; +} + +void uart_tx(uint8_t c) { + dev_barrier(); + while (!uart_can_tx()) + ; + uart->io = c & 0xff; + dev_barrier(); +} + +void uart_putc(void* p, char c) { + (void) p; + uart_tx(c); +} + +bool uart_tx_empty() { + dev_barrier(); + + // broadcom p 18: "This bit (9) is set if the transmitter is idle and the + // transmit FIFO is empty." + // transmitter done: idle and empty + return bit_get(uart->stat, 9) == 1; +} + +void uart_tx_flush() { + while (!uart_tx_empty()) + ; +} diff --git a/pid_os/uart.h b/pid_os/uart.h new file mode 100644 index 0000000..e7b655f --- /dev/null +++ b/pid_os/uart.h @@ -0,0 +1,18 @@ +#pragma once + +#include <stdbool.h> +#include <stdint.h> + +#include "../libc/tinyprintf.h" + +void uart_init(unsigned baud); +bool uart_rx_empty(); +bool uart_can_tx(); +unsigned uart_rx_sz(); +uint8_t uart_rx(); +void uart_tx(uint8_t c); +bool uart_tx_empty(); +void uart_tx_flush(); + +// for tinyprintf +void uart_putc(void* p, char c); |