libc for the amiga version
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Sat, 4 Aug 2018 01:47:34 +0000 (04:47 +0300)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Sat, 4 Aug 2018 01:47:34 +0000 (04:47 +0300)
14 files changed:
Makefile.amiga
src/amiga/libc/ctype.c [new file with mode: 0644]
src/amiga/libc/ctype.h [new file with mode: 0644]
src/amiga/libc/inttypes.h [new file with mode: 0644]
src/amiga/libc/libc_asm.s [deleted file]
src/amiga/libc/stdarg.h [new file with mode: 0644]
src/amiga/libc/stdint.h [new file with mode: 0644]
src/amiga/libc/stdio.c [new file with mode: 0644]
src/amiga/libc/stdio.h [new file with mode: 0644]
src/amiga/libc/stdlib.c [new file with mode: 0644]
src/amiga/libc/stdlib.h
src/amiga/libc/string.c [new file with mode: 0644]
src/amiga/libc/string.h
src/game.c

index c6fbfbd..7d9a255 100644 (file)
@@ -1,5 +1,6 @@
 src = $(wildcard src/*.c) \
-         $(wildcard src/amiga/*.c)
+         $(wildcard src/amiga/*.c) \
+         $(wildcard src/amiga/libc/*.c)
 asrc = $(wildcard src/*.s) \
           $(wildcard src/amiga/*.s) \
           $(wildcard src/amiga/libc/*.s)
diff --git a/src/amiga/libc/ctype.c b/src/amiga/libc/ctype.c
new file mode 100644 (file)
index 0000000..9676441
--- /dev/null
@@ -0,0 +1,56 @@
+#include "ctype.h"
+
+int isalnum(int c)
+{
+       return isalpha(c) || isdigit(c);
+}
+
+int isalpha(int c)
+{
+       return isupper(c) || islower(c);
+}
+
+int isblank(int c)
+{
+       return c == ' ' || c == '\t';
+}
+
+int isdigit(int c)
+{
+       return c >= '0' && c <= '9';
+}
+
+int isupper(int c)
+{
+       return c >= 'A' && c <= 'Z';
+}
+
+int islower(int c)
+{
+       return c >= 'a' && c <= 'z';
+}
+
+int isgraph(int c)
+{
+       return c > ' ' && c <= '~';
+}
+
+int isprint(int c)
+{
+       return isgraph(c) || c == ' ';
+}
+
+int isspace(int c)
+{
+       return isblank(c) || c == '\f' || c == '\n' || c == '\r' || c == '\v';
+}
+
+int toupper(int c)
+{
+       return islower(c) ? (c + ('A' - 'a')) : c;
+}
+
+int tolower(int c)
+{
+       return isupper(c) ? (c + ('A' - 'a')) : c;
+}
diff --git a/src/amiga/libc/ctype.h b/src/amiga/libc/ctype.h
new file mode 100644 (file)
index 0000000..5b010d4
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef CTYPE_H_
+#define CTYPE_H_
+
+int isalnum(int c);
+int isalpha(int c);
+#define isascii(c)     ((c) < 128)
+int isblank(int c);
+int isdigit(int c);
+int isupper(int c);
+int islower(int c);
+int isprint(int c);
+int isspace(int c);
+
+int toupper(int c);
+int tolower(int c);
+
+#endif /* CTYPE_H_ */
diff --git a/src/amiga/libc/inttypes.h b/src/amiga/libc/inttypes.h
new file mode 100644 (file)
index 0000000..1edfed1
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef AMIGA_LIBC_INTTYPES_H_
+#define AMIGA_LIBC_INTTYPES_H_
+
+typedef char int8_t;
+typedef short int16_t;
+typedef int int32_t;
+typedef long long int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef int32_t intptr_t;
+typedef uint32_t uintptr_t;
+
+#endif /* AMIGA_LIBC_INTTYPES_H_ */
diff --git a/src/amiga/libc/libc_asm.s b/src/amiga/libc/libc_asm.s
deleted file mode 100644 (file)
index 095c8df..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-| vi:filetype=gas68k:
-       .text
-
-       | optimize: transfer words at a time
-       .global memcpy
-memcpy:
-       move.l 4(%sp), %a0
-       move.l 8(%sp), %a1
-       move.l 12(%sp), %d0
-       sub.l #1, %d0
-0:     move.b (%a1)+, (%a0)+
-       dbra %d0, 0b
-       rts
-
-       | optimize: same as above
-       .global memset
-memset:
-       move.l 4(%sp), %a0
-       move.l 8(%sp), %d1
-       move.l 12(%sp), %d0
-       sub.l #1, %d0
-0:     move.b %d1, (%a0)+
-       dbra %d0, 0b
-       rts
diff --git a/src/amiga/libc/stdarg.h b/src/amiga/libc/stdarg.h
new file mode 100644 (file)
index 0000000..696aab2
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef STDARG_H_
+#define STDARG_H_
+
+typedef __builtin_va_list va_list;
+
+#define va_start(v,l) __builtin_va_start(v,l)
+#define va_end(v) __builtin_va_end(v)
+#define va_arg(v,l) __builtin_va_arg(v,l)
+
+#endif /* STDARG_H_ */
diff --git a/src/amiga/libc/stdint.h b/src/amiga/libc/stdint.h
new file mode 100644 (file)
index 0000000..775c434
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef AMIGA_LIBC_STDINT_H_
+#define AMIGA_LIBC_STDINT_H_
+
+#include <inttypes.h>
+
+#endif /* AMIGA_LIBC_STDINT_H_ */
diff --git a/src/amiga/libc/stdio.c b/src/amiga/libc/stdio.c
new file mode 100644 (file)
index 0000000..45e8aec
--- /dev/null
@@ -0,0 +1,262 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "serial.h"
+
+static void bwrite(char *buf, size_t buf_sz, char *str, int sz);
+static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap);
+
+int putchar(int c)
+{
+       ser_putchar(c);
+       return c;
+}
+
+int puts(const char *s)
+{
+       while(*s) {
+               putchar(*s++);
+       }
+       putchar('\n');
+       return 0;
+}
+
+/* -- printf and friends -- */
+
+static char *convc = "dioxXucsfeEgGpn%";
+
+#define IS_CONV(c)     strchr(convc, c)
+
+int printf(const char *fmt, ...)
+{
+       int res;
+       va_list ap;
+
+       va_start(ap, fmt);
+       res = intern_printf(0, 0, fmt, ap);
+       va_end(ap);
+       return res;
+}
+
+int vprintf(const char *fmt, va_list ap)
+{
+       return intern_printf(0, 0, fmt, ap);
+}
+
+int sprintf(char *buf, const char *fmt, ...)
+{
+       int res;
+       va_list ap;
+
+       va_start(ap, fmt);
+       res = intern_printf(buf, 0, fmt, ap);
+       va_end(ap);
+       return res;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list ap)
+{
+       return intern_printf(buf, 0, fmt, ap);
+}
+
+int snprintf(char *buf, size_t sz, const char *fmt, ...)
+{
+       int res;
+       va_list ap;
+
+       va_start(ap, fmt);
+       res = intern_printf(buf, sz, fmt, ap);
+       va_end(ap);
+       return res;
+}
+
+int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap)
+{
+       return intern_printf(buf, sz, fmt, ap);
+}
+
+
+/* intern_printf provides all the functionality needed by all the printf
+ * variants.
+ * - buf: optional buffer onto which the formatted results are written. If null
+ *   then the output goes to the terminal through putchar calls. This is used
+ *   by the (v)sprintf variants which write to an array of char.
+ * - sz: optional maximum size of the output, 0 means unlimited. This is used
+ *   by the (v)snprintf variants to avoid buffer overflows.
+ * The rest are obvious, format string and variable argument list.
+ */
+
+#define BUF(x) ((x) ? (x) + cnum : (x))
+#define SZ(x)  ((x) ? (x) - cnum : (x))
+
+static int intern_printf(char *buf, size_t sz, const char *fmt, va_list ap)
+{
+       char conv_buf[32];
+       char *str;
+       int i, slen;
+       const char *fstart = 0;
+
+       /* state */
+       int cnum = 0;
+       int base = 10;
+       int alt = 0;
+       int fwidth = 0;
+       int padc = ' ';
+       int sign = 0;
+       int left_align = 0;     /* not implemented yet */
+       int hex_caps = 0;
+       int unsig = 0;
+
+       while(*fmt) {
+               if(*fmt == '%') {
+                       fstart = fmt++;
+                       continue;
+               }
+
+               if(fstart) {
+                       if(IS_CONV(*fmt)) {
+                               switch(*fmt) {
+                               case 'X':
+                                       hex_caps = 1;
+
+                               case 'x':
+                               case 'p':
+                                       base = 16;
+
+                                       if(alt) {
+                                               bwrite(BUF(buf), SZ(sz), "0x", 2);
+                                       }
+
+                               case 'u':
+                                       unsig = 1;
+
+                                       if(0) {
+                               case 'o':
+                                               base = 8;
+
+                                               if(alt) {
+                                                       bwrite(BUF(buf), SZ(sz), "0", 1);
+                                               }
+                                       }
+
+                               case 'd':
+                               case 'i':
+                                       if(unsig) {
+                                               utoa(va_arg(ap, unsigned int), conv_buf, base);
+                                       } else {
+                                               itoa(va_arg(ap, int), conv_buf, base);
+                                       }
+                                       if(hex_caps) {
+                                               for(i=0; conv_buf[i]; i++) {
+                                                       conv_buf[i] = toupper(conv_buf[i]);
+                                               }
+                                       }
+
+                                       slen = strlen(conv_buf);
+                                       for(i=slen; i<fwidth; i++) {
+                                               bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
+                                               cnum++;
+                                       }
+
+                                       bwrite(BUF(buf), SZ(sz), conv_buf, strlen(conv_buf));
+                                       cnum += slen;
+                                       break;
+
+                               case 'c':
+                                       {
+                                               char c = va_arg(ap, int);
+                                               bwrite(BUF(buf), SZ(sz), &c, 1);
+                                               cnum++;
+                                       }
+                                       break;
+
+                               case 's':
+                                       str = va_arg(ap, char*);
+                                       slen = strlen(str);
+
+                                       for(i=slen; i<fwidth; i++) {
+                                               bwrite(BUF(buf), SZ(sz), (char*)&padc, 1);
+                                               cnum++;
+                                       }
+                                       bwrite(BUF(buf), SZ(sz), str, slen);
+                                       cnum += slen;
+                                       break;
+
+                               case 'n':
+                                       *va_arg(ap, int*) = cnum;
+                                       break;
+
+                               default:
+                                       break;
+                               }
+
+                               /* restore default conversion state */
+                               base = 10;
+                               alt = 0;
+                               fwidth = 0;
+                               padc = ' ';
+                               hex_caps = 0;
+
+                               fstart = 0;
+                               fmt++;
+                       } else {
+                               switch(*fmt) {
+                               case '#':
+                                       alt = 1;
+                                       break;
+
+                               case '+':
+                                       sign = 1;
+                                       break;
+
+                               case '-':
+                                       left_align = 1;
+                                       break;
+
+                               case 'l':
+                               case 'L':
+                                       break;
+
+                               case '0':
+                                       padc = '0';
+                                       break;
+
+                               default:
+                                       if(isdigit(*fmt)) {
+                                               const char *fw = fmt;
+                                               while(*fmt && isdigit(*fmt)) fmt++;
+
+                                               fwidth = atoi(fw);
+                                               continue;
+                                       }
+                               }
+                               fmt++;
+                       }
+               } else {
+                       bwrite(BUF(buf), SZ(sz), (char*)fmt++, 1);
+                       cnum++;
+               }
+       }
+
+       return 0;
+}
+
+
+/* bwrite is called by intern_printf to transparently handle writing into a
+ * buffer (if buf is non-null) or to the terminal (if buf is null).
+ */
+static void bwrite(char *buf, size_t buf_sz, char *str, int sz)
+{
+       if(buf) {
+               if(buf_sz && buf_sz <= sz) sz = buf_sz - 1;
+               memcpy(buf, str, sz);
+
+               buf[sz] = 0;
+       } else {
+               int i;
+               for(i=0; i<sz; i++) {
+                       putchar(*str++);
+               }
+       }
+}
+
diff --git a/src/amiga/libc/stdio.h b/src/amiga/libc/stdio.h
new file mode 100644 (file)
index 0000000..50daaaa
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef STDIO_H_
+#define STDIO_H_
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+int putchar(int c);
+int getchar(void);
+
+int puts(const char *s);
+
+int printf(const char *fmt, ...);
+int vprintf(const char *fmt, va_list ap);
+
+int sprintf(char *buf, const char *fmt, ...);
+int vsprintf(char *buf, const char *fmt, va_list ap);
+
+int snprintf(char *buf, size_t sz, const char *fmt, ...);
+int vsnprintf(char *buf, size_t sz, const char *fmt, va_list ap);
+
+#endif /* STDIO_H_ */
diff --git a/src/amiga/libc/stdlib.c b/src/amiga/libc/stdlib.c
new file mode 100644 (file)
index 0000000..6496c8d
--- /dev/null
@@ -0,0 +1,119 @@
+#include <stdlib.h>
+#include <ctype.h>
+
+int atoi(const char *str)
+{
+       return strtol(str, 0, 10);
+}
+
+long atol(const char *str)
+{
+       return strtol(str, 0, 10);
+}
+
+long strtol(const char *str, char **endp, int base)
+{
+       long acc = 0;
+       int sign = 1;
+
+       while(isspace(*str)) str++;
+
+       if(base == 0) {
+               if(str[0] == '0') {
+                       if(str[1] == 'x' || str[1] == 'X') {
+                               base = 16;
+                       } else {
+                               base = 8;
+                       }
+               } else {
+                       base = 10;
+               }
+       }
+
+       if(*str == '+') {
+               str++;
+       } else if(*str == '-') {
+               sign = -1;
+               str++;
+       }
+
+       while(*str) {
+               long val;
+               char c = tolower(*str);
+
+               if(isdigit(c)) {
+                       val = *str - '0';
+               } else if(c >= 'a' || c <= 'f') {
+                       val = 10 + c - 'a';
+               }
+               if(val >= base) {
+                       break;
+               }
+
+               acc = acc * base + val;
+               str++;
+       }
+
+       if(endp) {
+               *endp = (char*)str;
+       }
+
+       return sign > 0 ? acc : -acc;
+}
+
+void itoa(int val, char *buf, int base)
+{
+       static char rbuf[16];
+       char *ptr = rbuf;
+       int neg = 0;
+
+       if(val < 0) {
+               neg = 1;
+               val = -val;
+       }
+
+       if(val == 0) {
+               *ptr++ = '0';
+       }
+
+       while(val) {
+               int digit = val % 10;
+               *ptr++ = digit < 10 ? (digit + '0') : (digit - 10 + 'a');
+               val /= 10;
+       }
+
+       if(neg) {
+               *ptr++ = '-';
+       }
+
+       ptr--;
+
+       while(ptr >= rbuf) {
+               *buf++ = *ptr--;
+       }
+       *buf = 0;
+}
+
+void utoa(unsigned int val, char *buf, int base)
+{
+       static char rbuf[16];
+       char *ptr = rbuf;
+
+       if(val == 0) {
+               *ptr++ = '0';
+       }
+
+       while(val) {
+               unsigned int digit = val % base;
+               *ptr++ = digit < 10 ? (digit + '0') : (digit - 10 + 'a');
+               val /= base;
+       }
+
+       ptr--;
+
+       while(ptr >= rbuf) {
+               *buf++ = *ptr--;
+       }
+       *buf = 0;
+}
+
index e0a11dc..ea0a6dc 100644 (file)
@@ -1,6 +1,16 @@
 #ifndef AMIGA_LIBC_STDLIB_H_
 #define AMIGA_LIBC_STDLIB_H_
 
-typedef long size_t;
+#include <stdint.h>
+
+typedef int32_t ssize_t;
+typedef uint32_t size_t;
+
+int atoi(const char *str);
+long atol(const char *str);
+long strtol(const char *str, char **endp, int base);
+
+void itoa(int val, char *buf, int base);
+void utoa(unsigned int val, char *buf, int base);
 
 #endif /* AMIGA_LIBC_STDLIB_H_ */
diff --git a/src/amiga/libc/string.c b/src/amiga/libc/string.c
new file mode 100644 (file)
index 0000000..9260cca
--- /dev/null
@@ -0,0 +1,116 @@
+#include <string.h>
+#include <ctype.h>
+
+void memset(void *s, int c, size_t n)
+{
+       char *ptr = s;
+       while(n--) {
+               *ptr++ = c;
+       }
+}
+
+void *memcpy(void *dest, const void *src, size_t n)
+{
+       char *dptr = dest;
+       const char *sptr = src;
+
+       while(n--) {
+               *dptr++ = *sptr++;
+       }
+       return dest;
+}
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+       int i;
+       char *dptr;
+       const char *sptr;
+
+       if(dest <= src) {
+               /* forward copy */
+               dptr = dest;
+               sptr = src;
+               for(i=0; i<n; i++) {
+                       *dptr++ = *sptr++;
+               }
+       } else {
+               /* backwards copy */
+               dptr = (char*)dest + n - 1;
+               sptr = (char*)src + n - 1;
+               for(i=0; i<n; i++) {
+                       *dptr-- = *sptr--;
+               }
+       }
+
+       return dest;
+}
+
+size_t strlen(const char *s)
+{
+       size_t len = 0;
+       while(*s++) len++;
+       return len;
+}
+
+char *strchr(const char *s, int c)
+{
+       while(*s) {
+               if(*s == c) {
+                       return (char*)s;
+               }
+               s++;
+       }
+       return 0;
+}
+
+char *strrchr(const char *s, int c)
+{
+       const char *ptr = s;
+
+       /* find the end */
+       while(*ptr) ptr++;
+
+       /* go back checking for c */
+       while(--ptr >= s) {
+               if(*ptr == c) {
+                       return (char*)ptr;
+               }
+       }
+       return 0;
+}
+
+char *strstr(const char *str, const char *substr)
+{
+       while(*str) {
+               const char *s1 = str;
+               const char *s2 = substr;
+
+               while(*s1 && *s1 == *s2) {
+                       s1++;
+                       s2++;
+               }
+               if(!*s2) {
+                       return (char*)str;
+               }
+               str++;
+       }
+       return 0;
+}
+
+int strcmp(const char *s1, const char *s2)
+{
+       while(*s1 && *s1 == *s2) {
+               s1++;
+               s2++;
+       }
+       return *s1 - *s2;
+}
+
+int strcasecmp(const char *s1, const char *s2)
+{
+       while(*s1 && tolower(*s1) == tolower(*s2)) {
+               s1++;
+               s2++;
+       }
+       return tolower(*s1) - tolower(*s2);
+}
index a2e4c74..e1a1182 100644 (file)
@@ -3,7 +3,18 @@
 
 #include <stdlib.h>
 
-void memcpy(void *dest, const void *src, size_t n);
 void memset(void *dest, int c, size_t n);
+void *memcpy(void *dest, const void *src, size_t n);
+void *memmove(void *dest, const void *src, size_t n);
+
+size_t strlen(const char *s);
+
+char *strchr(const char *s, int c);
+char *strrchr(const char *s, int c);
+
+char *strstr(const char *str, const char *substr);
+
+int strcmp(const char *s1, const char *s2);
+int strcasecmp(const char *s1, const char *s2);
 
 #endif /* AMIGA_LIBC_STRING_H_ */
index 89b4e5a..87edac7 100644 (file)
@@ -1,3 +1,4 @@
+#include <stdio.h>
 #include <string.h>
 #include "game.h"
 #include "gfx.h"
@@ -21,6 +22,8 @@ int game_init(void)
 {
        int i;
 
+       printf("hello world\n");
+
        REG_COLOR0 = 0x221;
        REG_COLOR1 = 0x222;
        REG_COLOR2 = 0x332;