From: Robin Krens Date: Wed, 24 Jul 2019 20:26:08 +0000 (+0800) Subject: tested working terminal and reordering of code X-Git-Url: https://robinkrens.nl/gitweb/?a=commitdiff_plain;h=918e9bbf26d44cb0087d35637e2e0f90ca37d7c3;p=cortex-from-scratch tested working terminal and reordering of code --- diff --git a/Makefile b/Makefile index b4a4133..520f0f1 100644 --- a/Makefile +++ b/Makefile @@ -15,24 +15,42 @@ LDFLAGS+= -mthumb -mcpu=cortex-m3 ASFLAGS+= -mcpu=cortex-m3 -mthumb -g CFLAGS+= -mcpu=cortex-m3 -mthumb -g -ffreestanding +INCLUDE+= -Iinclude + BIN = bin ODIR = obj -_OBJ = ivt.o uart.o systick.o sysinfo.o lib.o regf.o pool.o term.o main.o +_OBJ = ivt.o systick.o sysinfo.o term.o main.o OBJ = $(patsubst %, $(ODIR)/%,$(_OBJ)) +DDIR = obj/drivers +_DRIVERS = uart.o +DRIVERS = $(patsubst %, $(DDIR)/%,$(_DRIVERS)) + +LDIR = obj/lib +_LIBS = string.o stdio.o regfunc.o pool.o +LIBS = $(patsubst %, $(LDIR)/%,$(_LIBS)) + +$(DDIR)/%.o: drivers/%.c + @mkdir -p $(@D) + $(CC) -c $< $(CFLAGS) $(INCLUDE) -o $@ + $(ODIR)/%.o: %.c @mkdir -p $(@D) $(CC) -c $< $(CFLAGS) -I./include -o $@ +$(LDIR)/%.o: lib/%.c + @mkdir -p $(@D) + $(CC) -c $< $(CFLAGS) -I./include -o $@ + # Start up machine assembly as: $(AS) $(ASFLAGS) -o start.o start.asm # Compile and link all -kernel: $(OBJ) +kernel: $(OBJ) $(DRIVERS) $(LIBS) $(AS) $(ASFLAGS) -o start.o start.asm - $(LD) -nostartfiles -Map $@.MAP -T link.ld -o $(BIN)/$@.ELF start.o $^ --print-memory-usage + $(LD) -nostartfiles -Map $(BIN)/$@.MAP -T link.ld -o $(BIN)/$@.ELF start.o $^ --print-memory-usage @echo "Creating binary..." @mkdir -p $(BIN) $(MKIMG) -Obinary -R .data $(BIN)/$@.ELF $(BIN)/$@.bin @@ -56,7 +74,7 @@ flash: .PHONY: clean clean: - rm -rf $(ODIR)/*.o start.o $(BIN)/kernel.* + rm -rf $(ODIR)/* start.o $(BIN)/kernel.* # Altijd handig deze template #%.o: %.c diff --git a/drivers/README b/drivers/README new file mode 100644 index 0000000..61c2416 --- /dev/null +++ b/drivers/README @@ -0,0 +1,2 @@ +Note to self: Place drivers or loadable modules here + diff --git a/drivers/uart.c b/drivers/uart.c new file mode 100644 index 0000000..6fc940b --- /dev/null +++ b/drivers/uart.c @@ -0,0 +1,111 @@ +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#define RXNE ((*USART1_SR >> 5) & 0x1) +#define UARTBUF 256 +#define ECHO 1 + +static struct { + uint8_t buf[UARTBUF]; + uint32_t rpos; + uint32_t wpos; +} linefeed; + + +void * uart_handler() { + + //uart_puts("echo: "); + while (RXNE) { + char echochar = *USART1_DR; +// uart_putc(echochar); + linefeed.buf[linefeed.wpos++] = echochar; + if (linefeed.wpos == UARTBUF) + linefeed.wpos = 0; + //regw_u32(USART1_DR, echochar, 0, O_WRITE); + } + //uart_putc('\n'); + +} + +void uart_init() { + + linefeed.rpos = 0; + linefeed.wpos = 0; + + //memset(&linefeed, 0, (sizeof(struct linefeed) )); + regw_u32(RCC_APB2ENR, 0x4005, 0, SETBIT);// enable clock to UART1, AFIO and GPIOA + + /* (after enable GPIOA), on PA9&PA10 and set mode + * to alternative output */ + regw_u32(GPIOA_CRH, 0x444444D4, 0, OWRITE); + regw_u8(AFIO_EVCR, 0x89, 0, OWRITE);// set event control register, output on PA, Pin 9 + + //disable temporarily to set values + regw_u8(USART1_CR1, 0x0, 13, SETBIT); + + /* baud rate 115200, 8MHz / (16 * USARTDIV) + * USARTDIV = 4.34 + * FRACTION: 16 x 0.34 = 0d5.44 0d5 -> 0x5 + * MANTISSA: 0d4.34 0d4 -> 0x4 + * USART_BRR = 0x45*/ + + regw_u32(USART1_BRR, 0x00000045, 0, OWRITE); + regw_u32(USART1_CR2, 0x0000, 0, OWRITE); //set stop bit, default is 1 stop bit 0x00 + + /* parity = 8 bit, UART1 enabled, + * TX and RX enabled, interrupts enabled */ + //regw_u32(USART1_CR1, 0x000030AC, 0, O_WRITE); + regw_u32(USART1_CR1, 0x0000302C, 0, OWRITE); + + ivt_set_gate(53, uart_handler, 0); + + *NVIC_ISER1 = (1 << 5); // Enable UART interrupt at NVIC +} + +static void wait() { + for (int i = 0; i < 100; i++); +} + +extern void uart_putc(unsigned char ch) { + + if (ch == '\n') { + while (*USART1_SR & 0x0C) { } // transmit data register empty and complete + regw_u8(USART1_DR, 0x0D, 0, OWRITE); // return line + } + + while (*USART1_SR & 0x0C) {} + regw_u8(USART1_DR, ch, 0, OWRITE); + + wait(); +} + +char uart_getc(void) { + char c; + + if (linefeed.rpos != linefeed.wpos) { + c = linefeed.buf[linefeed.rpos++]; + if (linefeed.rpos == UARTBUF) + linefeed.rpos = 0; + return c; + } + return 0; + } + + +// move to library +extern void uart_puts(unsigned char *str) { + int i; + for (i = 0; i < strlen(str); i++) { + uart_putc(str[i]); + } +} + diff --git a/include/drivers/uart.h b/include/drivers/uart.h new file mode 100644 index 0000000..5b0badc --- /dev/null +++ b/include/drivers/uart.h @@ -0,0 +1,12 @@ +#ifndef __UART_H +#define __UART_H + +/* SERIAL INIT AND BASIC I/O + * DON'T USE DIRECTLY USE, RATHER + * USE HIGHER LEVEL I/O + * */ +extern void uart_init(); +extern void uart_putc(unsigned char ch); +char uart_getc(void); + +#endif diff --git a/include/lib/pool.h b/include/lib/pool.h new file mode 100644 index 0000000..9204d36 --- /dev/null +++ b/include/lib/pool.h @@ -0,0 +1,4 @@ +/* Fixed size memory pool allocation */ +extern void pool_init(size_t size_arg, unsigned int blocks_arg, uint32_t * entry_SRAM); +extern void * alloc(); +extern void free(void* p); diff --git a/include/lib/regfunc.h b/include/lib/regfunc.h new file mode 100644 index 0000000..6b0c50b --- /dev/null +++ b/include/lib/regfunc.h @@ -0,0 +1,4 @@ +/* regfunc.h */ +extern char * regtohex(uint32_t ); +extern void regw_u8(volatile uint32_t *, uint8_t, short, short); +extern void regw_u32(volatile uint32_t *, uint32_t, short, short); diff --git a/include/lib/stdio.h b/include/lib/stdio.h new file mode 100644 index 0000000..cf3075b --- /dev/null +++ b/include/lib/stdio.h @@ -0,0 +1,8 @@ +/* + * Not really "standard" but doable + * for small programs + * */ +extern char getchar(); +extern void cputchar(char); +extern void cputs(unsigned char *); +extern char * readline(); diff --git a/include/lib/string.h b/include/lib/string.h new file mode 100644 index 0000000..e8e52f7 --- /dev/null +++ b/include/lib/string.h @@ -0,0 +1,5 @@ +/* string.h TODO */ +extern void *memcpy(void*, void*, size_t); +extern void *memset(void*, unsigned char, size_t); +extern unsigned short *memsetw(unsigned short *dest, unsigned short val, size_t count); +extern int strlen(const char *); diff --git a/include/mmap.h b/include/mmap.h deleted file mode 100644 index e88c752..0000000 --- a/include/mmap.h +++ /dev/null @@ -1,74 +0,0 @@ -/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL - * - * $LOG$ - * 2019/7/20 - ROBIN KRENS - * Initial version - * - * $DESCRIPTION$ - * Example memory map for the Cortex-A3 - * Implementations vary among manufacturers. This one is - * a STM32F013RC6. Addresses of peripherals vary amongst - * manufacturers of boards with similar chips - * - * $USAGE$ - * These are volatile memory addresses of 32 bit. The macro's - * MEM_VALUE and MEM_ADDR should used. - * In case you want to use a address on the lside of a assigment - * use volatile uint32_t * p = MEM_ADDR(0x20000000); - * - * */ - -#define OWRITE 0x01 -#define SETBIT 0x02 -#define CLRBIT 0x03 - -/* Safety macro's to get the address or value */ -#define MEM_VALUE(addr) *((volatile uint32_t(*) (addr)) -#define MEM_ADDR(addr) ((volatile uint32_t *) (addr)) - -/* SYSTEM INFO AND DEBUG */ -#define MCU_ID MEM_ADDR(0xE000ED00) -#define FLASH_MEM MEM_ADDR(0x1FFFF000) - -/* SYSTEM CONTROL BLOCK REGISTER */ -#define SCB_VTOR MEM_ADDR(0xE000ED08) // VECTOR TABLE -#define SCB_VTOR_ST MEM_ADDR(0xE000ED04) // STATUS OF VECTOR -#define SCB_CCR MEM_ADDR(0xE000ED14) // SET SOFTWARE TRAPS - -/* NESTED VECTOR INTERRUPT CONTROL REGISTER */ -#define NVIC_ISER0 MEM_ADDR(0xE000E100) // interrupt set enable register -#define NVIC_ISER1 MEM_ADDR(0xE000E104) // interrupt set enable register - -/* SYSTICK REGISTER */ -#define STK_CTRL MEM_ADDR(0xE000E010) -#define STK_RELOAD MEM_ADDR(0xE000E014) - -/* CLOCK REGISTER */ -#define RCC_CR MEM_ADDR(0x40021000) -#define RCC_CFGR MEM_ADDR(0x40021004) - -/* SYSTEM CONTROL REGISTER */ -#define SYSCTRL_RCC MEM_ADDR(0x40021000) -#define RCC_APB2ENR MEM_ADDR(0x40021018) // register to enable USART1 - -#define SYSCTRL_RIS MEM_ADDR(0x400FE050) -#define SYSCTRL_RCGC1 MEM_ADDR(0x400FE104) -#define SYSCTRL_RCGC2 MEM_ADDR(0x400FE108) -#define GPIOPA_AFSEL MEM_ADDR(0x40004420) - -#define GPIOA_CRH MEM_ADDR(0x40010804) - -#define AFIO_EVCR MEM_ADDR(0x40010000) - -/* EXTERNAL INTERRUPTS */ -#define EXTI_IMR MEM_ADDR(0x40010400) -#define EXTI_RTSR MEM_ADDR(0x40010408) - -/* UART1 REGISTERS */ -#define USART1_BASE MEM_ADDR(0x40013800) -#define USART1_SR MEM_ADDR(0x40013800) -#define USART1_DR MEM_ADDR(0x40013804) -#define USART1_BRR MEM_ADDR(0x40013808) -#define USART1_CR1 MEM_ADDR(0x4001380C) -#define USART1_CR2 MEM_ADDR(0x40013810) -#define USART1_CR3 MEM_ADDR(0x40013814) diff --git a/include/stm32.h b/include/stm32.h deleted file mode 100644 index 433c5d4..0000000 --- a/include/stm32.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef __SYSTEM_H -#define __SYSTEM_H - -/* MAIN.C */ -extern void *memcpy(void*, void*, size_t); -extern void *memset(void*, unsigned char, size_t); -extern unsigned short *memsetw(unsigned short *dest, unsigned short val, size_t count); -extern int strlen(const char *); - -/* CLOCK.C */ -extern void clock_init(); - -/* UART.C */ -extern void uart_init(); -extern void uart_putc(unsigned char); -extern void uart_puts(unsigned char *); -extern char uart_getc(); - -/* IVT.C */ -extern void ivt_init(); -extern void ivt_set_gate(unsigned char, void *(), short); - -/* SYSTICK.C */ -extern void systick_init(); - -/* SYSINFO.C */ -extern void sysinfo(); - -/* LIB.C */ -extern void addrtohex(const uint32_t); - -/* MM.C */ -extern void mm_init(); -extern void * malloc(size_t); -extern void free(void *); -extern void test_memory(uint32_t *); - -/* POOL.c */ -extern void pool_init(size_t, unsigned int, uint32_t *); -extern void * alloc(); -extern void free(); - -/* REGF.C */ -extern void regw_u8(volatile uint32_t *, uint8_t, short, short); -extern void regw_u32(volatile uint32_t *, uint32_t, short, short); - -/* TERM.C */ -extern char getchar(); -extern void cputchar(char); -extern void cputs(unsigned char *); -extern char * readline(); -extern void terminal(); - -#endif diff --git a/include/sys/mmap.h b/include/sys/mmap.h new file mode 100644 index 0000000..a5921d2 --- /dev/null +++ b/include/sys/mmap.h @@ -0,0 +1,74 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/20 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * Memory map for the Cortex-A3 + * Implementations vary among manufacturers. This one is + * a STM32F013RC6. Addresses of peripherals vary amongst + * manufacturers of boards with similar chips + * + * $USAGE$ + * These are volatile memory addresses of 32 bit. The macro's + * MEM_VALUE and MEM_ADDR should used. + * In case you want to use a address on the lside of a assigment + * use volatile uint32_t * p = MEM_ADDR(0x20000000); + * + * */ + +#define OWRITE 0x01 +#define SETBIT 0x02 +#define CLRBIT 0x03 + +/* Safety macro's to get the address or value */ +#define MEM_VALUE(addr) *((volatile uint32_t(*) (addr)) +#define MEM_ADDR(addr) ((volatile uint32_t *) (addr)) + +/* SYSTEM INFO AND DEBUG */ +#define MCU_ID MEM_ADDR(0xE000ED00) +#define FLASH_MEM MEM_ADDR(0x1FFFF000) + +/* SYSTEM CONTROL BLOCK REGISTER */ +#define SCB_VTOR MEM_ADDR(0xE000ED08) // VECTOR TABLE +#define SCB_VTOR_ST MEM_ADDR(0xE000ED04) // STATUS OF VECTOR +#define SCB_CCR MEM_ADDR(0xE000ED14) // SET SOFTWARE TRAPS + +/* NESTED VECTOR INTERRUPT CONTROL REGISTER */ +#define NVIC_ISER0 MEM_ADDR(0xE000E100) // interrupt set enable register +#define NVIC_ISER1 MEM_ADDR(0xE000E104) // interrupt set enable register + +/* SYSTICK REGISTER */ +#define STK_CTRL MEM_ADDR(0xE000E010) +#define STK_RELOAD MEM_ADDR(0xE000E014) + +/* CLOCK REGISTER */ +#define RCC_CR MEM_ADDR(0x40021000) +#define RCC_CFGR MEM_ADDR(0x40021004) + +/* SYSTEM CONTROL REGISTER */ +#define SYSCTRL_RCC MEM_ADDR(0x40021000) +#define RCC_APB2ENR MEM_ADDR(0x40021018) // register to enable USART1 + +#define SYSCTRL_RIS MEM_ADDR(0x400FE050) +#define SYSCTRL_RCGC1 MEM_ADDR(0x400FE104) +#define SYSCTRL_RCGC2 MEM_ADDR(0x400FE108) +#define GPIOPA_AFSEL MEM_ADDR(0x40004420) + +#define GPIOA_CRH MEM_ADDR(0x40010804) + +#define AFIO_EVCR MEM_ADDR(0x40010000) + +/* EXTERNAL INTERRUPTS */ +#define EXTI_IMR MEM_ADDR(0x40010400) +#define EXTI_RTSR MEM_ADDR(0x40010408) + +/* UART1 REGISTERS */ +#define USART1_BASE MEM_ADDR(0x40013800) +#define USART1_SR MEM_ADDR(0x40013800) +#define USART1_DR MEM_ADDR(0x40013804) +#define USART1_BRR MEM_ADDR(0x40013808) +#define USART1_CR1 MEM_ADDR(0x4001380C) +#define USART1_CR2 MEM_ADDR(0x40013810) +#define USART1_CR3 MEM_ADDR(0x40013814) diff --git a/include/sys/robsys.h b/include/sys/robsys.h new file mode 100644 index 0000000..e02eded --- /dev/null +++ b/include/sys/robsys.h @@ -0,0 +1,31 @@ +#ifndef __SYSTEM_H +#define __SYSTEM_H + +/* CLOCK.C */ +extern void clock_init(); + +/* IVT.C */ +extern void ivt_init(); +extern void ivt_set_gate(unsigned char, void *(), short); + +/* SYSTICK.C */ +extern void systick_init(); + +/* SYSINFO.C */ +extern void sysinfo(); + +/* MM.C DELETE TODO */ +//extern void mm_init(); +//extern void * malloc(size_t); +//extern void free(void *); +//extern void test_memory(uint32_t *); + +/* POOL.c */ +extern void pool_init(size_t, unsigned int, uint32_t *); +extern void * alloc(); +extern void free(); + +/* TERM.C */ +extern void terminal(); + +#endif diff --git a/ivt.c b/ivt.c index b3854f1..a6761d0 100644 --- a/ivt.c +++ b/ivt.c @@ -5,14 +5,31 @@ * Initial version * * $DESCRIPTION$ + * Set up of basic exceptions and interrupts. These interrupts + * don't do much, except for halting the system. + * ivt_set_gate(interrupt nr, function, priority) can be used + * later to define more appropriate handling. See timer (timer.c) + * or serial or (uart.c) handling for non-trivial examples. + * + * The actual code is not much, but there are a lot of details + * to consider. Besides that, in case more control is desired over + * entering and exiting interrupts (what is pushed on the stack) + * A so-called naked function can be used. See below for more + * details. * + * * */ #include #include #include -#include -#include + +#include +#include + +#include +#include +#include /* * These values are pushed on the stack just before @@ -22,7 +39,7 @@ * gives me a little bit more control over the caller * * The following register are pushed to the stack - * in reverse order + * in reverse order: * * */ struct interrupt_frame { @@ -43,6 +60,8 @@ struct interrupt_frame { * * interrupt vector 1-15: processor exceptions * interrupt vector 16-92: irq0 - irq .. + * + * Vector table needs to be aligned in memory. * */ uint32_t __attribute__((aligned(0x100))) ivt[92]; @@ -92,15 +111,17 @@ void ivt_set_gate(unsigned char num, void * isr(), short pri) { } -/* Dummy interrupt */ +/* Dummy interrupt: comment out the comment to use a naked f + * function */ + // __attribute__ ((interrupt)) void * dummy_isr(/* struct interrupt_frame * frame */) { uint8_t nr = *SCB_VTOR_ST & 0xFF; - uart_puts("EXCEPTION: "); - uart_puts(exception_message(nr)); - uart_puts("\nSYSTEM HALTED\n"); + cputs("EXCEPTION: "); + cputs(exception_message(nr)); + cputs("\nSYSTEM HALTED\n"); for(;;); } @@ -108,7 +129,7 @@ void * dummy_isr(/* struct interrupt_frame * frame */) { /* Initialize interrupt vector */ void ivt_init() { - /* clear entiry IVT, in SRAM location for SRAM + .data (in .bss section) */ + /* clear entire IVT, in SRAM location for SRAM + .data (in .bss section) */ memset(&ivt, 0, (sizeof(uint32_t) * 92)); // stack top is loaded from the first entry table on boot/reset @@ -119,13 +140,10 @@ void ivt_init() { ivt_set_gate(i, dummy_isr, 0); } - - /* the vector table starts at 0x0. Since the address 0x0 point to - * bootcode, it is on ROM or FLASH. The vector table can be + /* The vector table is intially at 0x0. The vector table can be * relocated to other memory locations. We can do this by setting * a register in the NVIC called the vector table offset register */ - //*SCB_VTOR = (volatile uint32_t) &ivt; regw_u32(SCB_VTOR, (uint32_t) &ivt, 0, OWRITE); } diff --git a/lib.c b/lib.c deleted file mode 100644 index ba55c01..0000000 --- a/lib.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include -//#include - -/* Temporary libc functions, which can later be - * replaced by a *real* library */ - -char hexbuf[8]; - -/* Still kind of a debug function */ -void addrtohex(uint32_t addr) { - char tmpbuf[6] = {'A', 'B', 'C', 'D', 'E', 'F'}; - memset(&hexbuf, 0, sizeof(uint32_t) * 8); - - for (int i = 0; i < 8 ; i++) { - uint32_t tmp = addr; - tmp = tmp >> (i * 4); - tmp = tmp & 0xF; - if ((tmp >= 0) && tmp < 10) { - hexbuf[i] = (char) tmp + 48; - } - else { - hexbuf[i] = tmpbuf[tmp - 10]; - } - } - - for (int i = 7; i >= 0; i--) { - cputchar(hexbuf[i]); - } -} - - - - - diff --git a/lib/pool.c b/lib/pool.c new file mode 100644 index 0000000..63cf3fd --- /dev/null +++ b/lib/pool.c @@ -0,0 +1,108 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/20 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * Fixed-sized memory pool allocation. A so called * memory-pool + * (i.e. 4kB * 12 blocks) can be initialized. Note: this allocator + * is for use on processors without an MMU (memory management + * unit). A MPU (memory protection unit), if available can be used + * to protect certain zones. + * + * This work is based on an article of Ben Kenwright. + * + * Preconditions: programmer should make sure the SRAM entry point + * + (blocks * blocksize) is free. + * + * $SAMPLE USAGE$ + * KERNEL: can initialize a big pool for all user tasks + * + * USER TASKS/PROCESS: can use this to dynamically allocate their + * own memory (i.e. heap) + * + * + * * */ + +#include +#include +#include + +#include +#include + +struct MEMPOOL { + + unsigned short blocks; + unsigned short block_size; + unsigned short free_blocks; + unsigned short blocks_alloc; + uint32_t * SRAM_entry; + uint32_t * m_next; + +}; + +struct MEMPOOL mem; + + +void pool_init(size_t size_arg, unsigned int blocks_arg, uint32_t * entry_SRAM) { + + mem.blocks = blocks_arg; + mem.block_size = size_arg; + mem.SRAM_entry = entry_SRAM; + memset(entry_SRAM, 0x00, (sizeof(char) * (size_arg * blocks_arg))); + mem.free_blocks = blocks_arg; + mem.m_next = mem.SRAM_entry; + } + + /* void deletepool() { + mem.SRAM_entry = NULL; + } */ + +/* Helper functions */ +uint32_t * AddrFromIndex(unsigned int i) { + return mem.SRAM_entry + ( i * mem.block_size ); + + } + +unsigned int IndexFromAddr(const uint32_t * p) { + return (((unsigned int)(p - mem.SRAM_entry)) / mem.block_size); + +} + +/* alloc and free */ +void * alloc() { + if (mem.blocks_alloc < mem.blocks ) { + unsigned int * p = (unsigned int *)AddrFromIndex( mem.blocks_alloc ); + *p = mem.blocks_alloc + 1; + mem.blocks_alloc++; + } + + void* ret = NULL; + if ( mem.free_blocks > 0 ) { + ret = (void*)mem.m_next; + --mem.free_blocks; + if (mem.free_blocks!=0) { + mem.m_next = AddrFromIndex( *((unsigned int*)mem.m_next) ); + } + else { + mem.m_next = NULL; + } + } + + return ret; + } + +void free(void* p) { + if (mem.m_next != NULL) { + (*(unsigned int *)p) = IndexFromAddr( mem.m_next ); + mem.m_next = (uint32_t *)p; + } + else { + *((unsigned int*)p) = mem.blocks; + mem.m_next = (uint32_t *) p; + } + + ++mem.free_blocks; + } diff --git a/lib/regfunc.c b/lib/regfunc.c new file mode 100644 index 0000000..6add220 --- /dev/null +++ b/lib/regfunc.c @@ -0,0 +1,64 @@ +#include +#include +#include + +#include +#include +#include + +#include + +/* write value (uint8_t) to register */ +void regw_u8(volatile uint32_t * reg, uint8_t val, short shift, short flag) { + + switch(flag) { + case OWRITE: + *reg = (val << shift); + break; + case SETBIT: + *reg = *reg | (val << shift); + break; + case CLRBIT: + *reg = (val << shift); + break; + } +} + +/* write value (uint32_t) to register */ +void regw_u32(volatile uint32_t * reg, uint32_t val, short shift, short flag) { + + switch(flag) { + case OWRITE: + *reg = (val << shift); + break; + case SETBIT: + *reg = *reg | (val << shift); + break; + case CLRBIT: + break; + } +} + +/* Print out the hexidecimal representation of an integer + After implementation of a printf function, this code + will be obsolete. */ + +char hexbuf[8]; +char * regtohex(uint32_t addr) { + char tmpbuf[6] = {'A', 'B', 'C', 'D', 'E', 'F'}; + memset(&hexbuf, 0, sizeof(uint32_t) * 8); + + + for (int i = 0; i < 8 ; i++) { + uint32_t tmp = addr; + tmp = tmp >> (28 - (i * 4)); + tmp = tmp & 0xF; + if ((tmp >= 0) && tmp < 10) { + hexbuf[i] = (char) tmp + 48; + } + else { + hexbuf[i] = tmpbuf[tmp - 10]; + } + } + return &hexbuf[0]; +} diff --git a/lib/stdio.c b/lib/stdio.c new file mode 100644 index 0000000..ac26165 --- /dev/null +++ b/lib/stdio.c @@ -0,0 +1,72 @@ +#include +#include +#include + +#include +#include +#include + +#define SERIAL 1 +#define TFT 0 +#define BUFSIZE 256 + +static char stdbuf[BUFSIZE]; + +/* Abstraction layer for I/O communication */ + +char getchar(void) { + char c; + if (SERIAL) { + while ((c = uart_getc()) == 0); + /* do nothing */ + } + return c; +} + +void cputchar(char c) { + + if (SERIAL) { + uart_putc(c); + } + +} + +void cputs(unsigned char *str) { + + int i; + for (i = 0; i < strlen(str); i++) { + cputchar(str[i]); + } + +} + +char * readline(char *prompt) +{ + int i, c, echoing; + + if (prompt != NULL) + cputs(prompt); + + i = 0; + echoing = 1; + while (1) { + c = getchar(); + if (c < 0) { + cputs("read error"); + return NULL; + } else if ((c == '\b' || c == '\x7f') && i > 0) { + if (echoing) + cputchar('\b'); + i--; + } else if (c >= ' ' && i < BUFSIZE-1) { + if (echoing) + cputchar(c); + stdbuf[i++] = c; + } else if (c == '\n' || c == '\r') { + if (echoing) + cputchar('\n'); + stdbuf[i] = 0; + return stdbuf; + } + } +} diff --git a/lib/string.c b/lib/string.c new file mode 100644 index 0000000..b1618b0 --- /dev/null +++ b/lib/string.c @@ -0,0 +1,38 @@ +#include +#include +#include + +#include + +// TODO: add more +void *memcpy(void *dest, void *src, size_t count) +{ + const char *sp = (const char *)src; + char *dp = (char *)dest; + for(; count != 0; count--) *dp++ = *sp++; + return dest; +} + +/* fillout memory with 'val' (i.e. all zeroes) + */ +void *memset(void *dest, unsigned char val, size_t count) +{ + char *temp = (char *)dest; + for( ; count != 0; count--) *temp++ = val; + return dest; +} + +/* same as above but shorter */ +unsigned short *memsetw(unsigned short *dest, unsigned short val, size_t count) +{ + unsigned short *temp = (unsigned short *)dest; + for( ; count != 0; count--) *temp++ = val; + return dest; +} + +int strlen(const char *str) +{ + int retval; + for(retval = 0; *str != '\0'; str++) retval++; + return retval; +} diff --git a/main.c b/main.c index 2b6fdba..35b718e 100644 --- a/main.c +++ b/main.c @@ -1,55 +1,35 @@ +/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL + * + * $LOG$ + * 2019/7/20 - ROBIN KRENS + * Initial version + * + * $DESCRIPTION$ + * + * */ + #include #include #include -#include // <-- my own header file located located in ./include -#include - - -void *memcpy(void *dest, void *src, size_t count) -{ - const char *sp = (const char *)src; - char *dp = (char *)dest; - for(; count != 0; count--) *dp++ = *sp++; - return dest; -} - -/* fillout memory with 'val' (i.e. all zeroes) - */ -void *memset(void *dest, unsigned char val, size_t count) -{ - char *temp = (char *)dest; - for( ; count != 0; count--) *temp++ = val; - return dest; -} - -/* same as above but shorter */ -unsigned short *memsetw(unsigned short *dest, unsigned short val, size_t count) -{ - unsigned short *temp = (unsigned short *)dest; - for( ; count != 0; count--) *temp++ = val; - return dest; -} - -int strlen(const char *str) -{ - int retval; - for(retval = 0; *str != '\0'; str++) retval++; - return retval; -} - +#include +#include +#include void main() { - ivt_init(); uart_init(); - + systick_init(); sysinfo(); + extern void stub(); + //stub(); + //__asm__ __volatile__ ("ldc p1, cr1, r0"); + terminal(); for(;;) { diff --git a/mm.c b/mm.c deleted file mode 100644 index 1e20f75..0000000 --- a/mm.c +++ /dev/null @@ -1,131 +0,0 @@ -/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL - * - * $LOG$ - * 2019/7/20 - ROBIN KRENS - * Initial version - * - * $DESCRIPTION$ - * Simple bitmap on bitband memory implementation for kernel - * heap. Sensitive to fragmentation over time. Bitband - * memory makes it possible to access each bit of memory - * atomically. - * - * DEPRECATED - * - * */ - - -#include -#include -#include -#include -#include - - -#define CHUNKS 256 - -#define MEM_VALUE(addr) *((volatile uint32_t *) (addr)) -#define MEM_ADDR(addr) ((uint32_t *) (addr)) -#define BITBAND(a, b) ((a & 0xF0000000) + 0x02000000 + ((a &0xFFFFF)<<5) + (b<<2)) -#define INDEXTOADDR(a) (((a & 0xFFFFF) >> 5) + ((a & 0xFF000000) - 0x02000000)) - - -/* Total SRAM: ~ 64kB - * Divided into chunks (256 bytes) - * Each bit will index a chunk - * Bits needed: 0x100 (= 4 uint32_t) - * */ - -//uint32_t chunk_index[4]; - -void mm_init() { - - -// memset(&chunk_index, 0, sizeof(uint32_t) * 4); - - -// uint32_t *p = MEM_ADDR(0x20000278); - -// extern stub(); -// stub(); - // __asm__ __volatile__ ("udiv r1, r3 ,%0" :: "r"(0)); -// -// for(;;); -// *p = (uint32_t volatile) 0x12345678; -// *x = (uint32_t volatile) 0x12345679; -// addrtohex(p); -// addrtohex(*p); -// MEM_ADDR(x) = 0x1; -// - - -// char * new = malloc(10); -// addrtohex(new); -// char * new2 = malloc(10); -// addrtohex(new2); - - - //uint32_t * test = MEM_ADDR(0x20000000); - //uint32_t random_location = MEM_VALUE(0x20000000); - - //uint32_t random_location = 0x20000900; - - //MEM_VALUE(random_location); - //MEM_VALUE(BITBAND(random_location, 0)) = 0x1; - - //addrtohex(MEM_VALUE(random_location)); - - - -} - - void test_memory(uint32_t * ptr) { - - *ptr = 0xEEEEEEEE; - for (int i = 0; i < 100; i++) { - ptr++; - *ptr = 0xEEEEEEEE; - } - -} - -/* BIT BAND SCAN */ - - /* uint32_t fits(uint32_t * current, size_t size) { - - uint32_t addr_start = current; - - for (int i = 1; i < size; i++) { - current + 4; // next bit offset is 0x4 - if ((MEM_VALUE(current)) == 0x1) - return 0x0; - } - return addr_start; - } */ - - -/* void * malloc(size_t size) { - - if (size < 256) { - - extern char * _endofbss; - - uint32_t start = (uint32_t) &chunk_index[0]; - uint32_t current; - int offset = 0x100; - - uint32_t * index = MEM_ADDR(BITBAND(start, 0)); - for(int i = 0; i < CHUNKS; i++) { - if (*index == 0x0) { - addrtohex(*index); - *index = 0x1; - return INDEXTOADDR(((uint32_t)index)) + (i * offset); - } - index += 0x04; - } - return NULL; - } -} */ - - - diff --git a/pool.c b/pool.c deleted file mode 100644 index 0e0b94d..0000000 --- a/pool.c +++ /dev/null @@ -1,122 +0,0 @@ -/* (CC-BY-NC-SA) ROBIN KRENS - ROBIN @ ROBINKRENS.NL - * - * $LOG$ - * 2019/7/20 - ROBIN KRENS - * Initial version - * - * $DESCRIPTION$ - * Fixed-sized memory pool allocation. A so called * memory-pool - * (i.e. 4kB * 12 blocks) can be initialized. Note: this allocator - * is for use on processors without an MMU (memory management - * unit). A MPU (memory protection unit), if available can be used - * to protect certain zones. - * - * This work is based on an article of Ben Kenwright. - * - * Preconditions: programmer should make sure the SRAM entry point - * + (blocks * blocksize) is free. - * - * $SAMPLE USAGE$ - * KERNEL: can initialize a big pool for all user tasks - * - * USER TASKS/PROCESS: can use this to dynamically allocate their - * own memory (i.e. heap) - * - * - * * */ - -#include -#include -#include -#include -#include - - -struct MEMPOOL { - - unsigned short blocks; - unsigned short block_size; - unsigned short free_blocks; - unsigned short blocks_alloc; - uint32_t * SRAM_entry; - uint32_t * m_next; - -}; - -struct MEMPOOL mem; - - -void pool_init(size_t size_arg, unsigned int blocks_arg, uint32_t * entry_SRAM) { - - mem.blocks = blocks_arg; - mem.block_size = size_arg; - mem.SRAM_entry = entry_SRAM; - memset(entry_SRAM, 0x00, (sizeof(char) * (size_arg * blocks_arg))); - mem.free_blocks = blocks_arg; - mem.m_next = mem.SRAM_entry; - - -/* uint32_t * a = alloc(); - uint32_t * b = alloc(); - uint32_t * c = alloc(); - free(c); - uint32_t * d = alloc(); - - addrtohex(a); - addrtohex(b); - addrtohex(c); - addrtohex(d); */ - - } - - - /* void deletepool() { - mem.SRAM_entry = NULL; - } */ - -/* Helper functions */ -uint32_t * AddrFromIndex(unsigned int i) { - return mem.SRAM_entry + ( i * mem.block_size ); - - } - -unsigned int IndexFromAddr(const uint32_t * p) { - return (((unsigned int)(p - mem.SRAM_entry)) / mem.block_size); - -} - -/* alloc and free */ -void * alloc() { - if (mem.blocks_alloc < mem.blocks ) { - unsigned int * p = (unsigned int *)AddrFromIndex( mem.blocks_alloc ); - *p = mem.blocks_alloc + 1; - mem.blocks_alloc++; - } - - void* ret = NULL; - if ( mem.free_blocks > 0 ) { - ret = (void*)mem.m_next; - --mem.free_blocks; - if (mem.free_blocks!=0) { - mem.m_next = AddrFromIndex( *((unsigned int*)mem.m_next) ); - } - else { - mem.m_next = NULL; - } - } - - return ret; - } - -void free(void* p) { - if (mem.m_next != NULL) { - (*(unsigned int *)p) = IndexFromAddr( mem.m_next ); - mem.m_next = (uint32_t *)p; - } - else { - *((unsigned int*)p) = mem.blocks; - mem.m_next = (uint32_t *) p; - } - - ++mem.free_blocks; - } diff --git a/regf.c b/regf.c deleted file mode 100644 index 75f0a3c..0000000 --- a/regf.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include -#include -#include - -/* write value (uint8_t) to register */ -void regw_u8(volatile uint32_t * reg, uint8_t val, short shift, short flag) { - - switch(flag) { - case OWRITE: - *reg = (val << shift); - break; - case SETBIT: - *reg = *reg | (val << shift); - break; - case CLRBIT: - *reg = (val << shift); - break; - } -} - -/* write value (uint32_t) to register */ -void regw_u32(volatile uint32_t * reg, uint32_t val, short shift, short flag) { - - switch(flag) { - case OWRITE: - //*reg = (val << shift); - *reg = (val << shift); - break; - case SETBIT: - *reg = *reg | (val << shift); - break; - case CLRBIT: - // - break; - } -} - - diff --git a/start.asm b/start.asm index ba161a2..54d2b91 100644 --- a/start.asm +++ b/start.asm @@ -29,6 +29,7 @@ hardfault: stub: ldr R0,=10 mov R1,#0 + ldc2 11, cr0, [r1, #4] udiv.w R2, R0, R1 .data diff --git a/sysinfo.c b/sysinfo.c index fe544ee..e9b2429 100644 --- a/sysinfo.c +++ b/sysinfo.c @@ -1,8 +1,12 @@ #include #include #include -#include -#include + +#include +#include + +#include +#include #define MEM_SIZE 0x00010000 #define MEM_OFFSET 0x20000000 @@ -22,7 +26,7 @@ void sysinfo() { } tmp = (tmp >> 16); - uart_puts("# REVISION: "); + cputs("# REVISION: "); switch (tmp) { case 0x1000: cputs("REVISION A\n"); @@ -45,13 +49,13 @@ void sysinfo() { uint32_t mem_free = MEM_SIZE - stack_usage - data_bss; cputs("# TOTAL MEMORY: "); - addrtohex(MEM_SIZE); + cputs(regtohex(MEM_SIZE)); cputchar('\n'); cputs("# FREE MEMORY: "); - addrtohex(mem_free); + cputs(regtohex(mem_free)); cputchar('\n'); cputs("# STACK USAGE: "); - addrtohex(stack_usage); + cputs(regtohex(stack_usage)); cputchar('\n'); } diff --git a/systick.c b/systick.c index 40e7862..1d632ec 100644 --- a/systick.c +++ b/systick.c @@ -1,8 +1,11 @@ #include #include #include -#include -#include + +#include +#include + +#include // TODO struct interrupt_frame { diff --git a/term.c b/term.c index 8b81255..0628e1e 100644 --- a/term.c +++ b/term.c @@ -1,40 +1,41 @@ #include #include #include -#include -#include + +#include +#include + +#include #define SERIAL 1 -#define BUFSIZE 256 +#define BUFSIZE 200 -static char buf[BUFSIZE]; -/* Abstraction layer for I/O communication */ +int help(int, char**); -char getchar(void) { - char c; - if (SERIAL) { - while ((c = uart_getc()) == 0); - /* do nothing */ - } - return c; -} +/* + * Built in commands + * info -- shows basic info of system + * reset -- software reset + * show [ADDRESS-ADDRESS] -- shows SRAM range + * switchmode -- switch to unprivileged mode + * */ -void cputchar(char c) { +static char buf[BUFSIZE]; - if (SERIAL) { - uart_putc(c); - } -} +struct cmd { + char * name; + char * description; + int (*function)(int argc, char ** argsv); +}; -void cputs(unsigned char *str) { - - int i; - for (i = 0; i < strlen(str); i++) { - cputchar(str[i]); - } +static struct cmd builtin[] = + { "info", "show info", help}; +int help(int argc, char ** argsv) { + sysinfo(); + return 0; } void terminal() { @@ -43,40 +44,9 @@ void terminal() { cputs("Terminal running!\n"); while (1) { - buf = readline("> "); + buf = readline("root# "); /* if (buf != NULL) if (runcmd(buf, tf) < 0) break; */ } } - -char * readline(char *prompt) -{ - int i, c, echoing; - - if (prompt != NULL) - cputs(prompt); - - i = 0; - echoing = 1; - while (1) { - c = getchar(); - if (c < 0) { - cputs("read error"); - return NULL; - } else if ((c == '\b' || c == '\x7f') && i > 0) { - if (echoing) - cputchar('\b'); - i--; - } else if (c >= ' ' && i < BUFSIZE-1) { - if (echoing) - cputchar(c); - buf[i++] = c; - } else if (c == '\n' || c == '\r') { - if (echoing) - cputchar('\n'); - buf[i] = 0; - return buf; - } - } -} diff --git a/uart.c b/uart.c deleted file mode 100644 index 9dbc01c..0000000 --- a/uart.c +++ /dev/null @@ -1,102 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#define RXNE ((*USART1_SR >> 5) & 0x1) -#define UARTBUF 256 -#define ECHO 1 - -static struct { - uint8_t buf[UARTBUF] ; - uint32_t rpos; - uint32_t wpos; -} linefeed; - - -void * uart_handler() { - - //uart_puts("echo: "); - while (RXNE) { - char echochar = *USART1_DR; - //uart_putc(echochar); - linefeed.buf[linefeed.wpos++] = echochar; - if (linefeed.wpos == UARTBUF) - linefeed.wpos = 0; - //regw_u32(USART1_DR, echochar, 0, O_WRITE); - } - //uart_putc('\n'); - -} - -void uart_init() { - - regw_u32(RCC_APB2ENR, 0x4005, 0, SETBIT);// enable clock to UART1, AFIO and GPIOA - - /* (after enable GPIOA), on PA9&PA10 and set mode - * to alternative output */ - regw_u32(GPIOA_CRH, 0x444444D4, 0, OWRITE); - regw_u8(AFIO_EVCR, 0x89, 0, OWRITE);// set event control register, output on PA, Pin 9 - - //disable temporarily to set values - regw_u8(USART1_CR1, 0x0, 13, SETBIT); - - /* baud rate 115200, 8MHz / (16 * USARTDIV) - * USARTDIV = 4.34 - * FRACTION: 16 x 0.34 = 0d5.44 0d5 -> 0x5 - * MANTISSA: 0d4.34 0d4 -> 0x4 - * USART_BRR = 0x45*/ - - regw_u32(USART1_BRR, 0x00000045, 0, OWRITE); - regw_u32(USART1_CR2, 0x0000, 0, OWRITE); //set stop bit, default is 1 stop bit 0x00 - - /* parity = 8 bit, UART1 enabled, - * TX and RX enabled, interrupts enabled */ - //regw_u32(USART1_CR1, 0x000030AC, 0, O_WRITE); - regw_u32(USART1_CR1, 0x0000302C, 0, OWRITE); - - ivt_set_gate(53, uart_handler, 0); - - *NVIC_ISER1 = (1 << 5); // Enable UART interrupt at NVIC -} - -static void wait() { - for (int i = 0; i < 100; i++); -} - -extern void uart_putc(unsigned char ch) { - - if (ch == '\n') { - while (*USART1_SR & 0x0C) { } // transmit data register empty and complete - regw_u8(USART1_DR, 0x0D, 0, OWRITE); // return line - } - - while (*USART1_SR & 0x0C) {} - regw_u8(USART1_DR, ch, 0, OWRITE); - - wait(); -} - -char uart_getc(void) { - char c; - - if (linefeed.rpos != linefeed.wpos) { - c = linefeed.buf[linefeed.rpos++]; - if (linefeed.rpos == UARTBUF) - linefeed.rpos = 0; - return c; - } - return 0; - } - - -// move to library -extern void uart_puts(unsigned char *str) { - int i; - for (i = 0; i < strlen(str); i++) { - uart_putc(str[i]); - } -} -