Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| vbcc [2024/08/20 19:46] – [The linker script] Add missing __DD variable pulkomandy | vbcc [2024/08/27 17:20] (current) – [The configuration file] Fix typos, add missing asv pulkomandy | ||
|---|---|---|---|
| Line 50: | Line 50: | ||
| * lib/ | * lib/ | ||
| * startup.o | * startup.o | ||
| + | * libvc.a | ||
| + | * include/ | ||
| + | * ctype.h | ||
| + | * stdlib.h | ||
| + | * string.h | ||
| * vlink.cmd | * vlink.cmd | ||
| + | The content of each file or how to generate them is detailed below. | ||
| ===== The configuration file ===== | ===== The configuration file ===== | ||
| Line 60: | Line 66: | ||
| -ccv=vbccunsp -I" | -ccv=vbccunsp -I" | ||
| -as=vasmunsp_std -quiet -ile -Fvobj %s -o %s | -as=vasmunsp_std -quiet -ile -Fvobj %s -o %s | ||
| + | -asv=vasmunsp_std -ile -Fvobj %s -o %s | ||
| -rm=rm %s | -rm=rm %s | ||
| -rmv=rm %s | -rmv=rm %s | ||
| - | -ld=vlink -ole -b rawbin1 -Cvbcc -T" | + | -ld=vlink -ole -b rawbin1 -Cvbcc -T" |
| - | -ldv=vlink -ole -b rawbin1 -Cvbcc -T" | + | -ldv=vlink -ole -b rawbin1 -Cvbcc -T" |
| - | -l2=vlink -ole -b rawbin1 -Cvbcc -T" | + | -l2=vlink -ole -b rawbin1 -Cvbcc -T" |
| - | -l2v=vlink -ole -b rawbin1 -Cvbcc -T" | + | -l2v=vlink -ole -b rawbin1 -Cvbcc -T" |
| </ | </ | ||
| Line 186: | Line 193: | ||
| ; Copy the initialized variables into RAM | ; Copy the initialized variables into RAM | ||
| ; __DL = length of variables section | ; __DL = length of variables section | ||
| - | ; __DS = start of variables section in ROM | + | ; __DS = start of variables section in RAM |
| - | LD R1, 0x0000 | + | ; __DD = start of variables section in ROM |
| - | LD R2, __DS | + | LD R1, __DS |
| + | LD R2, __DD | ||
| LD R3, __DL | LD R3, __DL | ||
| JZ gomain | JZ gomain | ||
| Line 202: | Line 210: | ||
| gomain: | gomain: | ||
| GOTO main | GOTO main | ||
| + | |||
| + | ; Handlers for indirect calls. Used by VBCC to handle function pointers, because unSP does not have | ||
| + | ; an indirect call (CALL R1 or similar) operation and it is not trivial to emulate one. | ||
| + | .globl __indirect_R1 | ||
| + | .globl __indirect_R2 | ||
| + | .globl __indirect_R3 | ||
| + | .globl __indirect_R4 | ||
| + | __indirect_R1: | ||
| + | LD PC,R1 | ||
| + | __indirect_R2: | ||
| + | LD PC,R2 | ||
| + | __indirect_R3: | ||
| + | LD PC,R3 | ||
| + | __indirect_R4: | ||
| + | LD PC,R4 | ||
| ; The interrupt vectors section, contains pointers to the interrupt handlers | ; The interrupt vectors section, contains pointers to the interrupt handlers | ||
| Line 240: | Line 263: | ||
| Note: the -ile option tells vasm that files included using the incbin directive are in little endian. This gives the same results as the official unSP toolchain when importing binary files. | Note: the -ile option tells vasm that files included using the incbin directive are in little endian. This gives the same results as the official unSP toolchain when importing binary files. | ||
| + | |||
| + | ===== The C library ===== | ||
| + | |||
| + | vbcc does not come with an open source C library. A full one from other sources could be compiled, but we don't need a complete C library. | ||
| + | |||
| + | So here is a very minimal one with enough support to run the compiler and to run Contiki, which has minimal needs from the C library (just a few string functions). | ||
| + | |||
| + | <code c> | ||
| + | /* | ||
| + | * Copyright (C) 2024 Adrien Destugues < | ||
| + | * | ||
| + | * Distributed under terms of the MIT license. | ||
| + | */ | ||
| + | |||
| + | int strlen(const char* str) | ||
| + | { | ||
| + | int i = 0; | ||
| + | while(*str++) i++; | ||
| + | return i; | ||
| + | } | ||
| + | |||
| + | int isprint(char c) | ||
| + | { | ||
| + | return c >= 32; | ||
| + | } | ||
| + | |||
| + | void strcpy(const char* src, char* dst) | ||
| + | { | ||
| + | char c; | ||
| + | while (c = *src++) | ||
| + | *dst++ = c; | ||
| + | *dst = 0; | ||
| + | } | ||
| + | |||
| + | void memset(int* s, int v, int n) | ||
| + | { | ||
| + | while(--n >= 0) | ||
| + | *s++ = v; | ||
| + | } | ||
| + | |||
| + | int strncmp(const char* a, const char* b, int n) | ||
| + | { | ||
| + | while(--n >= 0) { | ||
| + | if (*a != *b) | ||
| + | return *a - *b; | ||
| + | if (*a == 0) | ||
| + | return *b; | ||
| + | if (*b == 0) | ||
| + | return -*a; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | int __div(int a, int b) | ||
| + | { | ||
| + | int c = 0; | ||
| + | while (a >= b) { | ||
| + | a -= b; | ||
| + | c++; | ||
| + | } | ||
| + | return c; | ||
| + | } | ||
| + | |||
| + | int __mod(int a, int b) | ||
| + | { | ||
| + | while (a >= b) { | ||
| + | a -= b; | ||
| + | } | ||
| + | return a; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | To generate the libc.a file: | ||
| + | |||
| + | <code sh> | ||
| + | vc +vsmile -nostdlib -O3 -c libc.c | ||
| + | ar cru libvc.a libc.o | ||
| + | </ | ||
| + | |||
| + | We also need some include files. ctype.h and stdlib.h can be empty, but they are used by Contiki so they must exist. | ||
| + | |||
| + | string.h has some basic functions declarations and type definitions: | ||
| + | |||
| + | <code c> | ||
| + | #ifndef __STRING_H | ||
| + | #define __STRING_H 1 | ||
| + | |||
| + | /* | ||
| + | Adapt according to stddef.h. | ||
| + | */ | ||
| + | #ifndef __SIZE_T | ||
| + | #define __SIZE_T 1 | ||
| + | typedef unsigned int size_t; | ||
| + | #endif | ||
| + | |||
| + | #undef NULL | ||
| + | #define NULL ((void *)0) | ||
| + | |||
| + | /* | ||
| + | Many of these functions should perhaps be implemented as | ||
| + | inline-assembly or assembly-functions. | ||
| + | |||
| + | Most suitable are: | ||
| + | - memcpy | ||
| + | - strcpy | ||
| + | - strlen | ||
| + | - strcmp | ||
| + | - strcat | ||
| + | */ | ||
| + | void *memcpy(void *,const void *,size_t n); | ||
| + | void *memmove(void *,const void *,size_t); | ||
| + | void *memset(void *, | ||
| + | int memcmp(const void *,const void *,size_t); | ||
| + | void *memchr(const void *, | ||
| + | char *strcat(char *,const char *); | ||
| + | char *strncat(char *,const char *,size_t); | ||
| + | char *strchr(const char *,int); | ||
| + | size_t strcspn(const char *,const char *); | ||
| + | char *strpbrk(const char *,const char *); | ||
| + | char *strrchr(const char *,int); | ||
| + | size_t strspn(const char *,const char *); | ||
| + | char *strstr(const char *,const char *); | ||
| + | char *strtok(char *,const char *); | ||
| + | char *strerror(int); | ||
| + | size_t strlen(const char *); | ||
| + | char *strcpy(char *,const char *); | ||
| + | char *strncpy(char *,const char *,size_t); | ||
| + | int strcmp(const char *,const char *); | ||
| + | int strncmp(const char *,const char *,size_t); | ||
| + | int strcoll(const char *,const char *); | ||
| + | size_t strxfrm(char *,const char *,size_t); | ||
| + | |||
| + | #endif | ||
| + | </ | ||
| ====== Running the compiler ====== | ====== Running the compiler ====== | ||
| + | |||
| + | Note: make sure you have set the VBCC environment variable as explained earlier, otherwise the compiler will not find the target configuration and will complain and not compile anything. | ||
| To compile a .c file into a .o file: | To compile a .c file into a .o file: | ||
