From: Robin Krens Date: Tue, 23 Jul 2019 19:00:45 +0000 (+0800) Subject: basic terminal X-Git-Url: https://robinkrens.nl/gitweb/?p=cortex-from-scratch;a=commitdiff_plain;h=41d25ed67df8b6acd6126c41c8b0882586db0b0d basic terminal --- diff --git a/AUTHORS b/AUTHORS index e69de29..6975af5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -0,0 +1 @@ +Robin Krens - robin@robinkrens.nl diff --git a/Makefile b/Makefile index d7e1652..b4a4133 100644 --- a/Makefile +++ b/Makefile @@ -15,12 +15,13 @@ LDFLAGS+= -mthumb -mcpu=cortex-m3 ASFLAGS+= -mcpu=cortex-m3 -mthumb -g CFLAGS+= -mcpu=cortex-m3 -mthumb -g -ffreestanding +BIN = bin + ODIR = obj -_OBJ = main.o uart.o ivt.o systick.o sysinfo.o lib.o regf.o pool.o +_OBJ = ivt.o uart.o systick.o sysinfo.o lib.o regf.o pool.o term.o main.o OBJ = $(patsubst %, $(ODIR)/%,$(_OBJ)) - -$(ODIR)/%.o: %.c $(DEPS) +$(ODIR)/%.o: %.c @mkdir -p $(@D) $(CC) -c $< $(CFLAGS) -I./include -o $@ @@ -31,30 +32,31 @@ as: # Compile and link all kernel: $(OBJ) $(AS) $(ASFLAGS) -o start.o start.asm - $(LD) -nostartfiles -Map $@.MAP -T link.ld -o $@.ELF start.o $^ --print-memory-usage + $(LD) -nostartfiles -Map $@.MAP -T link.ld -o $(BIN)/$@.ELF start.o $^ --print-memory-usage @echo "Creating binary..." - $(MKIMG) -Obinary -R .data $@.ELF $@.bin + @mkdir -p $(BIN) + $(MKIMG) -Obinary -R .data $(BIN)/$@.ELF $(BIN)/$@.bin # Run in Qemu; note this is a patched version for stm32-f103c8 run: - /usr/local/bin/qemu-system-arm -serial stdio -M stm32-f103c8 -kernel kernel.bin + /usr/local/bin/qemu-system-arm -serial stdio -M stm32-f103c8 -kernel $(BIN)/kernel.bin # Examine all sections examine-all: - arm-none-eabi-objdump -D kernel.ELF | less + arm-none-eabi-objdump -D $(BIN)/kernel.ELF | less # Examine just headers examine-header: - arm-none-eabi-objdump -x kernel.ELF | less + arm-none-eabi-objdump -x $(BIN)/kernel.ELF | less # Flash kernel to board flash: - stm32flash -w kernel.bin -v /dev/ttyUSB0 + stm32flash -w $(BIN)/kernel.bin -v /dev/ttyUSB0 .PHONY: clean clean: - rm -rf $(ODIR)/*.o start.o kernel.* + rm -rf $(ODIR)/*.o start.o $(BIN)/kernel.* # Altijd handig deze template #%.o: %.c diff --git a/include/mmap.h b/include/mmap.h index aa8a902..e88c752 100644 --- a/include/mmap.h +++ b/include/mmap.h @@ -1,59 +1,74 @@ -/* +/* (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 BSS_BASE ((volatile uint32_t *)(0x20000800)) //TODO: .data flexible siz -#define TOTAL_MEM_SIZE 64000; +#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 ((volatile uint32_t*)( 0xE000ED00)) -#define FLASH_MEM ((volatile uint32_t*)( 0x1FFFF000)) +#define MCU_ID MEM_ADDR(0xE000ED00) +#define FLASH_MEM MEM_ADDR(0x1FFFF000) /* SYSTEM CONTROL BLOCK REGISTER */ -#define SCB_VTOR ((volatile uint32_t *)( 0xE000ED08)) // VECTOR TABLE -#define SCB_VTOR_ST ((volatile uint32_t *)( 0xE000ED04)) // STATUS OF VECTOR -#define SCB_CCR ((volatile uint32_t *)( 0xE000ED14)) // SET SOFTWARE TRAPS +#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 ((volatile uint32_t*)( 0xE000E100)) // interrupt set enable register -#define NVIC_ISER1 ((volatile uint32_t*)( 0xE000E104)) // interrupt set enable 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 ((volatile uint32_t *)(0xE000E010)) -#define STK_RELOAD ((volatile uint32_t *)(0xE000E014)) +#define STK_CTRL MEM_ADDR(0xE000E010) +#define STK_RELOAD MEM_ADDR(0xE000E014) /* CLOCK REGISTER */ -#define RCC_CR ((volatile uint32_t *)(0x40021000)) -#define RCC_CFGR ((volatile uint32_t *)(RCC_CR + 0x04)) +#define RCC_CR MEM_ADDR(0x40021000) +#define RCC_CFGR MEM_ADDR(0x40021004) /* SYSTEM CONTROL REGISTER */ -#define SYSCTRL_RCC ((volatile unsigned long *)(0x40021000)) -#define RCC_APB2ENR ((volatile uint32_t *)(0x40021018)) // register to enable USART1 +#define SYSCTRL_RCC MEM_ADDR(0x40021000) +#define RCC_APB2ENR MEM_ADDR(0x40021018) // register to enable USART1 -#define SYSCTRL_RIS ((volatile unsigned long *)(0x400FE050)) -#define SYSCTRL_RCGC1 ((volatile unsigned long *)(0x400FE104)) -#define SYSCTRL_RCGC2 ((volatile unsigned long *)(0x400FE108)) -#define GPIOPA_AFSEL ((volatile unsigned long *)(0x40004420)) +#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 ((volatile unsigned long *)(0x40010804)) +#define GPIOA_CRH MEM_ADDR(0x40010804) -#define AFIO_EVCR ((volatile uint32_t *)(0x40010000)) -//#define AFIO_EXTICR1 ((volatile uint32_t *)(AFIO_EVCR + 0x08)) +#define AFIO_EVCR MEM_ADDR(0x40010000) /* EXTERNAL INTERRUPTS */ -#define EXTI_IMR ((volatile uint32_t *)(0x40010400)) -#define EXTI_RTSR ((volatile uint32_t *) (EXTI_IMR + 0x08)) -//#define EXTI_FTSR ((volatile uint32_t *) (EXTI_IMR + 0x04)) +#define EXTI_IMR MEM_ADDR(0x40010400) +#define EXTI_RTSR MEM_ADDR(0x40010408) /* UART1 REGISTERS */ -#define USART1_BASE ((volatile uint32_t) (0x40013800)) -#define USART1_SR ((volatile uint32_t *) (USART1_BASE)) -#define USART1_DR ((volatile uint32_t *) (USART1_BASE + 0x04)) -#define USART1_BRR ((volatile uint32_t *) (USART1_BASE + 0x08)) -#define USART1_CR1 ((volatile uint32_t *) (USART1_BASE + 0x0C)) -#define USART1_CR2 ((volatile uint32_t *) (USART1_BASE + 0x10)) -#define USART1_CR3 ((volatile uint32_t *) (USART1_BASE + 0x14)) +#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 index bc510d4..433c5d4 100644 --- a/include/stm32.h +++ b/include/stm32.h @@ -14,6 +14,7 @@ extern void clock_init(); 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(); @@ -43,4 +44,11 @@ extern void free(); 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/ivt.c b/ivt.c index 33a2bd4..b3854f1 100644 --- a/ivt.c +++ b/ivt.c @@ -45,7 +45,7 @@ struct interrupt_frame { * interrupt vector 16-92: irq0 - irq .. * */ -uint32_t ivt[92]; +uint32_t __attribute__((aligned(0x100))) ivt[92]; /* each message corresponds to each and every exception. * We get the correct message by accessing @@ -126,6 +126,6 @@ void ivt_init() { * 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, 0x01); + regw_u32(SCB_VTOR, (uint32_t) &ivt, 0, OWRITE); } diff --git a/lib.c b/lib.c index d753ac3..ba55c01 100644 --- a/lib.c +++ b/lib.c @@ -26,13 +26,12 @@ void addrtohex(uint32_t addr) { } } - //uart_puts("ADDRESS: 0x"); for (int i = 7; i >= 0; i--) { - uart_putc(hexbuf[i]); + cputchar(hexbuf[i]); } - //uart_puts(hexbuf); - //uart_putc('\n'); } + + diff --git a/link.ld b/link.ld index db37888..1f6b5f6 100644 --- a/link.ld +++ b/link.ld @@ -12,7 +12,7 @@ SECTIONS . = 0x0; .text : ALIGN(4) { - /* (.vector_table */ + /* (.vector_table */ *(.text) *(.rodata) } @@ -21,7 +21,7 @@ SECTIONS { *(.data) } - .bss : ALIGN(256) + .bss : ALIGN(4) { *(.bss) } diff --git a/main.c b/main.c index 19d0eb5..2b6fdba 100644 --- a/main.c +++ b/main.c @@ -44,30 +44,14 @@ void main() { ivt_init(); -// clock_init(); uart_init(); - //uart_puts("LOADING SYSTEM 0.1 ...\n"); + systick_init(); -// mm_init(); - sysinfo(); - - - pool_init(20, 5, 0x20000800); - - //addrtohex(p2); - //addrtohex(*p2); - - /* extern stub(); - stub(); - __asm__ __volatile__ ("udiv r1, r3 ,%0" :: "r"(0)); */ - //regw_u32(p, 0x0CCCCCCCC, 4, 0x01); - - //regw_u8(p, 0xFF, 0, 0x02); + sysinfo(); -// asm("cpsie i"); // enable irq , cpsied f (disable faukts( + terminal(); - // loop for(;;) { } diff --git a/pool.c b/pool.c index fa08c29..0e0b94d 100644 --- a/pool.c +++ b/pool.c @@ -5,24 +5,22 @@ * 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. + * 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 + * This work is based on an article of Ben Kenwright. * - * Preconditions: programmer should make sure the - * SRAM entry point + (blocks * blocksize) is free. + * Preconditions: programmer should make sure the SRAM entry point + * + (blocks * blocksize) is free. * * $SAMPLE USAGE$ - * KERNEL: can use initialize a big pool for all - * user tasks + * 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) + * USER TASKS/PROCESS: can use this to dynamically allocate their + * own memory (i.e. heap) * * * * */ @@ -76,6 +74,7 @@ void pool_init(size_t size_arg, unsigned int blocks_arg, uint32_t * entry_SRAM) mem.SRAM_entry = NULL; } */ +/* Helper functions */ uint32_t * AddrFromIndex(unsigned int i) { return mem.SRAM_entry + ( i * mem.block_size ); @@ -86,6 +85,7 @@ unsigned int IndexFromAddr(const uint32_t * p) { } +/* alloc and free */ void * alloc() { if (mem.blocks_alloc < mem.blocks ) { unsigned int * p = (unsigned int *)AddrFromIndex( mem.blocks_alloc ); diff --git a/regf.c b/regf.c index 257a417..75f0a3c 100644 --- a/regf.c +++ b/regf.c @@ -2,24 +2,20 @@ #include #include #include - -#define O_WRITE 0x01 -#define SET 0x02 -#define CLEAR 0x03 +#include /* write value (uint8_t) to register */ void regw_u8(volatile uint32_t * reg, uint8_t val, short shift, short flag) { switch(flag) { - case O_WRITE: - (*(volatile uint32_t *) (reg)) = (val << shift); + case OWRITE: + *reg = (val << shift); break; - case SET: - (*(volatile uint32_t *) (reg)) = - ((*(volatile uint32_t *) (reg)) | (val << shift)); + case SETBIT: + *reg = *reg | (val << shift); break; - case CLEAR: - (*(volatile uint32_t *) (reg)) = (val << shift); + case CLRBIT: + *reg = (val << shift); break; } } @@ -28,13 +24,14 @@ void regw_u8(volatile uint32_t * reg, uint8_t val, short shift, short flag) { void regw_u32(volatile uint32_t * reg, uint32_t val, short shift, short flag) { switch(flag) { - case O_WRITE: - (*(volatile uint32_t *) (reg)) = (val << shift); + case OWRITE: + //*reg = (val << shift); + *reg = (val << shift); + break; + case SETBIT: + *reg = *reg | (val << shift); break; - case SET: - (*(volatile uint32_t *) (reg)) = - ((*(volatile uint32_t *) (reg)) | (val << shift)); - case CLEAR: + case CLRBIT: // break; } diff --git a/sysinfo.c b/sysinfo.c index 2d6f047..fe544ee 100644 --- a/sysinfo.c +++ b/sysinfo.c @@ -12,29 +12,29 @@ uint32_t get_msp(void); void sysinfo() { uint32_t tmp = *MCU_ID; - uart_puts("# ROBSYS 0.1 LOADING...\n"); - uart_puts("# DEVICE ID: "); + cputs("# ROBSYS 0.1 LOADING...\n"); + cputs("# DEVICE ID: "); if (tmp & 0x414) - uart_puts("HIGH DENSITY\n"); + cputs("HIGH DENSITY\n"); else { - uart_puts("UNKNOWN\n"); + cputs("UNKNOWN\n"); } tmp = (tmp >> 16); uart_puts("# REVISION: "); switch (tmp) { case 0x1000: - uart_puts("REVISION A\n"); + cputs("REVISION A\n"); break; case 0x1001: - uart_puts("REVISION Z\n"); + cputs("REVISION Z\n"); break; case 0x1003: - uart_puts("REVISION 1/2/3/X/Y\n"); + cputs("REVISION 1/2/3/X/Y\n"); break; default: - uart_puts("UNKNOWN\n"); + cputs("UNKNOWN\n"); } extern char _endofbss; @@ -44,15 +44,15 @@ void sysinfo() { uint32_t data_bss = &_endofbss - MEM_OFFSET; uint32_t mem_free = MEM_SIZE - stack_usage - data_bss; - uart_puts("# TOTAL MEMORY: "); + cputs("# TOTAL MEMORY: "); addrtohex(MEM_SIZE); - uart_putc('\n'); - uart_puts("# FREE MEMORY: "); + cputchar('\n'); + cputs("# FREE MEMORY: "); addrtohex(mem_free); - uart_putc('\n'); - uart_puts("# STACK USAGE: "); + cputchar('\n'); + cputs("# STACK USAGE: "); addrtohex(stack_usage); - uart_putc('\n'); + cputchar('\n'); } diff --git a/systick.c b/systick.c index ed062c0..40e7862 100644 --- a/systick.c +++ b/systick.c @@ -20,7 +20,7 @@ struct interrupt_frame { void * systick_handler(/* struct interrupt_frame * frame */) { // uint32_t volatile status; - uart_puts("TICKING\n"); + //uart_puts("TICKING\n"); // for(;;); } diff --git a/term.c b/term.c new file mode 100644 index 0000000..8b81255 --- /dev/null +++ b/term.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include + +#define SERIAL 1 +#define BUFSIZE 256 + +static char buf[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]); + } + +} + +void terminal() { + + char *buf; + cputs("Terminal running!\n"); + + while (1) { + buf = readline("> "); + /* 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 index 86bf9fe..9dbc01c 100644 --- a/uart.c +++ b/uart.c @@ -3,41 +3,45 @@ #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; -#define O_WRITE 0x01 -#define SET 0x02 -#define CLEAR 0x03 void * uart_handler() { - uart_puts("echo: "); + //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(echochar); } - uart_putc('\n'); + //uart_putc('\n'); - } -void uart_init() { - // global interrupt setup -// regw_u32(EXTI_IMR, 0x000FFFFF, 0, O_WRITE); -// regw_u32(EXTI_RTSR, 0x000FFFFF, 0, O_WRITE); +void uart_init() { - - regw_u32(RCC_APB2ENR, 0x4005, 0, SET);// enable clock to UART1, AFIO and GPIOA + 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, O_WRITE); - regw_u8(AFIO_EVCR, 0x89, 0, O_WRITE);// set event control register, output on PA, Pin 9 + 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, SET); + regw_u8(USART1_CR1, 0x0, 13, SETBIT); /* baud rate 115200, 8MHz / (16 * USARTDIV) * USARTDIV = 4.34 @@ -45,20 +49,20 @@ void uart_init() { * MANTISSA: 0d4.34 0d4 -> 0x4 * USART_BRR = 0x45*/ - regw_u32(USART1_BRR, 0x00000045, 0, O_WRITE); - regw_u32(USART1_CR2, 0x0000, 0, O_WRITE); //set stop bit, default is 1 stop bit 0x00 + 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, 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 } -void wait() { +static void wait() { for (int i = 0; i < 100; i++); } @@ -66,15 +70,29 @@ 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, O_WRITE); // return line + regw_u8(USART1_DR, 0x0D, 0, OWRITE); // return line } while (*USART1_SR & 0x0C) {} - regw_u8(USART1_DR, ch, 0, O_WRITE); + 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++) { @@ -82,17 +100,3 @@ extern void uart_puts(unsigned char *str) { } } - - -char uart_read() { - - /* while (buffer not empty) - * read() - * uart_putc(ch) // echo - * if ch = enter - * process inquiry. - */ - -} - -