# HG changeset patch # User John Tsiombikas # Date 1486796202 -7200 # Node ID 862f8a034caeec49a98fc9f350eb04f6948733d5 # Parent f99eab59e7dce5142906048e2b262eda28b4a210 expanding the megadrive code diff -r f99eab59e7dc -r 862f8a034cae Makefile --- a/Makefile Wed Feb 01 14:40:19 2017 +0200 +++ b/Makefile Sat Feb 11 08:56:42 2017 +0200 @@ -1,4 +1,4 @@ -csrc = $(wildcard src/*.c) +csrc = $(wildcard src/*.c) $(wildcard src/libc/*.c) asrc = $(wildcard src/*.s) aSsrc = $(wildcard src/*.S) obj = $(asrc:.s=.o) $(aSsrc:.S=.o) $(csrc:.c=.o) @@ -9,7 +9,8 @@ warn = -pedantic -Wall dbg = -g -def = -DGAMENAME=\"testgame\" -DVERSTR=\"01\" +def = -DGAMENAME=\"testgame\" -DVERSTR=\"01\" -D__NO_CTYPE +inc = -Isrc/libc tool_prefix = m68k-linux-gnu- @@ -18,16 +19,17 @@ LD = $(tool_prefix)ld OBJCOPY = $(tool_prefix)objcopy -CFLAGS = -m68000 -fno-builtin $(warn) $(dbg) $(opt) $(def) +CFLAGS = -m68000 -ffreestanding -fno-builtin $(warn) $(dbg) $(opt) $(def) $(inc) CPPFLAGS = $(def) ASFLAGS = -m68000 -LDFLAGS = -T megadrive.ldscript -print-gc-sections +LDFLAGS = -T megadrive.ldscript -print-gc-sections \ + -L/usr/lib/gcc-cross/m68k-linux-gnu/6 -lgcc $(bin): $(elf) $(OBJCOPY) -O binary $< $@ $(elf): $(obj) - $(LD) -o $@ $(LDFLAGS) $(obj) -Map link.map + $(LD) -o $@ $(obj) -Map link.map $(LDFLAGS) .PHONY: clean clean: diff -r f99eab59e7dc -r 862f8a034cae src/io.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/io.c Sat Feb 11 08:56:42 2017 +0200 @@ -0,0 +1,11 @@ +#include "io.h" + +int mdg_version(void) +{ + return IO_VERSION & IO_VER_MASK; +} + +int mdg_ispal(void) +{ + return IO_VERSION & IO_VER_VMOD; +} diff -r f99eab59e7dc -r 862f8a034cae src/io.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/io.h Sat Feb 11 08:56:42 2017 +0200 @@ -0,0 +1,16 @@ +#ifndef IO_H_ +#define IO_H_ + +#define IO_VERSION (*(unsigned char*)0xa10001) + +#define IO_VER_MASK 0x0f +#define IO_VER_DISK 0x20 +#define IO_VER_VMOD 0x40 +#define IO_VER_MODE_BIT 0x80 + +#define IO_Z80_MEM_START 0xa00000 + +int mdg_version(void); +int mdg_ispal(void); + +#endif /* IO_H_ */ diff -r f99eab59e7dc -r 862f8a034cae src/libc/ctype.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libc/ctype.c Sat Feb 11 08:56:42 2017 +0200 @@ -0,0 +1,60 @@ +int isalpha(int c); +int isdigit(int c); +int islower(int c); +int isupper(int c); + + +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 -r f99eab59e7dc -r 862f8a034cae src/libc/printf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libc/printf.c Sat Feb 11 08:56:42 2017 +0200 @@ -0,0 +1,323 @@ +#include +#include +#include +#include +#include + +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); +static void itoa(int val, char *buf, int base); +static void utoa(unsigned int val, char *buf, int base); + + +int putchar(int c) +{ + /* TODO */ + 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= rbuf) { + *buf++ = *ptr--; + } + *buf = 0; +} + +static 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; +} + diff -r f99eab59e7dc -r 862f8a034cae src/libc/stdlib.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libc/stdlib.c Sat Feb 11 08:56:42 2017 +0200 @@ -0,0 +1,62 @@ +#include +#include + +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; +} diff -r f99eab59e7dc -r 862f8a034cae src/libc/string.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/libc/string.c Sat Feb 11 08:56:42 2017 +0200 @@ -0,0 +1,107 @@ +#include + +void *memset(void *s, int c, size_t n) +{ + char *ptr = s; + while(n--) { + *ptr++ = c; + } + return s; +} + +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= 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; +} diff -r f99eab59e7dc -r 862f8a034cae src/main.c --- a/src/main.c Wed Feb 01 14:40:19 2017 +0200 +++ b/src/main.c Sat Feb 11 08:56:42 2017 +0200 @@ -1,12 +1,32 @@ #include "vdp.h" +static const unsigned char pal[][3] = { + {0, 0, 0}, {64, 128, 255}, {255, 128, 32}, {255, 255, 255} +}; + +static const unsigned char pat[8] = { + 0, 0, 0, 0, /* 0 0 0 0 0 0 0 0 */ + 1, 0x11, 0x11, 0x11, /* 0 1 1 1 1 1 1 1 */ + 1, 0x11, 0x11, 0x11, /* 0 1 1 1 1 1 1 1 */ + 1, 0x11, 0x11, 0x12, /* 0 1 1 1 1 1 1 2 */ + 1, 0x11, 0x12, 0x22, /* 0 1 1 1 1 2 2 2 */ + 1, 0x11, 0x22, 0x22, /* 0 1 1 1 2 2 2 2 */ + 1, 0x11, 0x22, 0x22, /* 0 1 1 1 2 2 2 2 */ + 1, 0x12, 0x22, 0x22 /* 0 1 1 2 2 2 2 2 */ +}; + int main(void) { - VDP_SET_CRAM_ADDR(0); - VDP_SET_CRAM_RGB24(64, 128, 255); + unsigned char *tmap; + + vdp_init(); + + vdp_setpal(0, sizeof pal / sizeof *pal, (unsigned char*)pal); VDP_SET_BGCOLOR(0, 0); - /* enable display */ - VDP_SET_REG(0, VDP_REG0_BASE); - VDP_SET_REG(1, VDP_REG1_BASE | VDP_REG1_DISP_BIT); + + vdp_set_tilemap_slot(VDP_PLANE_A, 0); + tmap = vdp_tilemap_ptr(VDP_PLANE_A); + + return 0; } diff -r f99eab59e7dc -r 862f8a034cae src/misc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/misc.c Sat Feb 11 08:56:42 2017 +0200 @@ -0,0 +1,17 @@ +#include +#include +#include "misc.h" + +void panic(const char *fmt, ...) +{ + va_list ap; + + printf("~~~~ panic ~~~~\n"); + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + + /*printf("registers:\n");*/ + + halt_cpu(); +} diff -r f99eab59e7dc -r 862f8a034cae src/misc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/misc.h Sat Feb 11 08:56:42 2017 +0200 @@ -0,0 +1,9 @@ +#ifndef MISC_H_ +#define MISC_H_ + +void panic(const char *fmt, ...); + +/* defined in startup.s */ +void halt_cpu(void); + +#endif /* MISC_H_ */ diff -r f99eab59e7dc -r 862f8a034cae src/startup.s --- a/src/startup.s Wed Feb 01 14:40:19 2017 +0200 +++ b/src/startup.s Sat Feb 11 08:56:42 2017 +0200 @@ -2,6 +2,7 @@ .extern main .global start + .global halt_cpu start: | copy .data section from ROM to RAM move.l #_data_lma, %a0 @@ -24,4 +25,5 @@ bne.s 0b 1: jsr main +halt_cpu: stop #0x2700 diff -r f99eab59e7dc -r 862f8a034cae src/vdp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vdp.c Sat Feb 11 08:56:42 2017 +0200 @@ -0,0 +1,85 @@ +#include +#include "vdp.h" +#include "io.h" +#include "misc.h" + +static void *tilemap_ptr[3]; + +int vdp_init(void) +{ + unsigned int mode1_flags = VDP_REG1_DISP_BIT; + + if(mdg_ispal()) { + mode1_flags |= VDP_REG1_30CELL_BIT; + } + + VDP_SET_REG(0, VDP_REG0_BASE); + VDP_SET_REG(1, VDP_REG1_BASE | mode1_flags); + + return 0; +} + +void vdp_set_tilemap_slot(int plane, int slot) +{ + switch(plane) { + case VDP_PLANE_A: + VDP_SET_REG(VDP_REG_PADDR_A, (slot & 7) << 3); + tilemap_ptr[VDP_PLANE_A] = (void*)((uint32_t)slot << 13); + break; + + case VDP_PLANE_WIN: + VDP_SET_REG(VDP_REG_PADDR_WIN, (slot & 0x1f) << 1); + tilemap_ptr[VDP_PLANE_WIN] = (void*)((uint32_t)slot << 11); + break; + + case VDP_PLANE_B: + VDP_SET_REG(VDP_REG_PADDR_B, slot & 7); + tilemap_ptr[VDP_PLANE_B] = (void*)((uint32_t)slot << 13); + break; + } +} + +void *vdp_tilemap_ptr(int plane) +{ + return tilemap_ptr[plane]; +} + +void vdp_setpal_rgb24(int idx, int r, int g, int b) +{ + VDP_SET_CRAM_ADDR(idx); + VDP_SET_CRAM_RGB24(r, g, b); +} + +void vdp_setpal(int idx0, int count, unsigned char *pal) +{ + int i; + + VDP_SET_CRAM_ADDR(idx0); + for(i=0; i>= 6; \ + break; \ + case 128: \ + (x) = 3; \ + break; \ + default: \ + panic("invalid argument to %s: %d\n", (x), __func__); \ + } \ + } while(0) + +void vdp_set_scroll_size(int xtiles, int ytiles) +{ + SCROLLSIZE(xtiles); + SCROLLSIZE(ytiles); + + VDP_SET_REG(VDP_REG_SCROLL_SIZE, (ytiles << 4) | xtiles); +} diff -r f99eab59e7dc -r 862f8a034cae src/vdp.h --- a/src/vdp.h Wed Feb 01 14:40:19 2017 +0200 +++ b/src/vdp.h Sat Feb 11 08:56:42 2017 +0200 @@ -10,6 +10,28 @@ #define VDP_PORT_HVCOUNT (*(volatile uint16_t*)0xc00008) #define VDP_PORT_PSG (*(volatile uint16_t*)0xc00010) +/* registers */ +#define VDP_REG_MODE1 0 +#define VDP_REG_MODE2 1 +#define VDP_REG_PADDR_A 2 +#define VDP_REG_PADDR_WIN 3 +#define VDP_REG_PADDR_B 4 +#define VDP_REG_SPRITE 5 +#define VDP_REG_BGCOLOR 7 +#define VDP_REG_HINT 10 +#define VDP_REG_MODE3 11 +#define VDP_REG_MODE4 12 +#define VDP_REG_HSCROLL 13 +#define VDP_REG_AUTOINC 15 +#define VDP_REG_SCROLL_SIZE 16 +#define VDP_REG_WINXPOS 17 +#define VDP_REG_WINYPOS 18 +#define VDP_REG_DMALEN_LOW 19 +#define VDP_REG_DMALEN_HIGH 20 +#define VDP_REG_DMA_SADDR_LOW 21 +#define VDP_REG_DMA_SADDR_MID 22 +#define VDP_REG_DMA_SADDR_HIGH 23 + /* control register read flags */ #define VDP_CTL_PAL_BIT 0x0001 #define VDP_CTL_HBLANK_BIT 0x0002 @@ -42,12 +64,17 @@ #define VDP_REG1_DMA_BIT 0x10 #define VDP_REG1_VINTR_BIT 0x20 #define VDP_REG1_DISP_BIT 0x40 +#define VDP_REG1_XVRAM_BIT 0x80 #define VDP_MODE_WR_BIT 1 #define VDP_VRAM_WR 1 #define VDP_CRAM_WR 3 +#define VDP_DMA_MEM_TO_VRAM 0 +#define VDP_DMA_VRAM_FILL 2 +#define VDP_DMA_VRAM_COPY 3 + #define VDP_ADDRSET(addr, mode) /* TODO */ #define VDP_CRAM_ADDR32(addr) (0xc0000000 | ((uint32_t)(addr) << 16)) @@ -55,15 +82,38 @@ #define VDP_SET_CRAM_ADDR(addr) \ do { VDP_PORT_CTL32 = VDP_CRAM_ADDR32(addr); } while(0) +#define VDP_RGB(r, g, b) \ + ((((uint16_t)(r) << 1) & 0xe) | \ + (((uint16_t)(g) << 5) & 0xe0) | \ + (((uint16_t)(b) << 9) & 0xe00)) + #define VDP_RGB24(r, g, b) \ ((((uint16_t)(r) >> 4) & 0xe) | \ ((uint16_t)(g) & 0xe0) | \ (((uint16_t)(b) << 4) & 0xe00)) +#define VDP_SET_CRAM_RGB(r, g, b) \ + do { VDP_PORT_DATA = VDP_RGB(r, g, b); } while(0) + #define VDP_SET_CRAM_RGB24(r, g, b) \ do { VDP_PORT_DATA = VDP_RGB24(r, g, b); } while(0) #define VDP_SET_BGCOLOR(pal, col) \ - do { VDP_SET_REG(7, ((pal) << 4) | (col)); } while(0) + do { VDP_SET_REG(VDP_REG_BGCOLOR, ((pal) << 4) | (col)); } while(0) + +/* arguments to vdp_tilemap_slot */ +#define VDP_PLANE_A 0 +#define VDP_PLANE_WIN 1 +#define VDP_PLANE_B 2 + +int vdp_init(void); +void vdp_set_tilemap_slot(int plane, int slot); +void *vdp_tilemap_ptr(int plane); +void vdp_setpal_rgb24(int idx, int r, int g, int b); +void vdp_setpal(int idx0, int count, unsigned char *pal); +/* TODO vdp_setpal_dma */ + +/* xtiles and ytiles can only be 32, 64, or 128 */ +void vdp_set_scroll_size(int xtiles, int ytiles); #endif /* VDP_H_ */