From 07b075cdd9ef336005e7eca13a0500db764b6f39 Mon Sep 17 00:00:00 2001 From: Andress Barajas Date: Fri, 31 May 2024 11:33:44 -0700 Subject: [PATCH 1/2] Video/exception overhaul by moop --- Makefile.cfg | 7 +- NETWORK | 2 +- example-src/Makefile | 26 +-- example-src/README | 2 + example-src/console-test.c | 2 +- example-src/crt0.S | 36 +++-- example-src/dc3.x | 11 +- example-src/dc4.x | 12 +- example-src/dcload-syscall.h | 4 +- example-src/dcload-syscalls.c | 42 +++-- example-src/dcload-syscalls.h | 31 ++-- example-src/exception-test.c | 15 +- example-src/gethostinfo.c | 2 +- example-src/startup_support.c | 33 ++++ host-src/tool/dc-tool.c | 20 +-- host-src/tool/syscalls.c | 33 +++- host-src/tool/syscalls.h | 3 + host-src/tool/utils.c | 90 +++++++++-- host-src/tool/utils.h | 78 +++++++++ make-cd/Makefile | 3 +- target-src/1st_read/Makefile | 4 +- target-src/dcload/Makefile | 10 +- target-src/dcload/dcload-crt0.s | 16 +- target-src/dcload/dcload.c | 17 +- target-src/dcload/dcload.h | 16 +- target-src/dcload/dcload.old | 241 ---------------------------- target-src/dcload/exception.s | 131 +++++++++------ target-src/dcload/perfctr.c | 11 +- target-src/dcload/startup_support.c | 197 +++++++++++++++++++++++ target-src/dcload/video.h | 2 - target-src/dcload/video.s | 154 +----------------- 31 files changed, 681 insertions(+), 570 deletions(-) create mode 100644 example-src/startup_support.c delete mode 100644 target-src/dcload/dcload.old create mode 100644 target-src/dcload/startup_support.c diff --git a/Makefile.cfg b/Makefile.cfg index 46e62d7..24306db 100644 --- a/Makefile.cfg +++ b/Makefile.cfg @@ -86,7 +86,7 @@ TARGETCCVER = 4 # You generally shouldn't change this unless you are making forked # versions (or test versions) -VERSION = 1.0.5 +VERSION = 1.1.1 # Define this if you want a standalone, statically linked, no dependency binary # This is on by default for MinGW/MSYS @@ -98,6 +98,11 @@ VERSION = 1.0.5 # Set to 1 to enable, 0 to disable. SAVE_MY_FANS = 0 +# This sets the number of seconds to show the register dump on-screen if an +# exception occurs. Maximum is 60 seconds, minimum is 0 seconds (no display), +# default is 15 seconds. +EXCEPTION_SECONDS = 15 + # # IMPORTANT IP ADDRESS INFORMATION: # diff --git a/NETWORK b/NETWORK index e5ac9b0..ac06ff6 100644 --- a/NETWORK +++ b/NETWORK @@ -11,6 +11,6 @@ dcload-ip implements (to some extent) the following protocols: * UDP - dcload-ip uses UDP for transfering data and commands - +* DHCP - dcload-ip can use IPv4 DHCP to get an IP address now diff --git a/example-src/Makefile b/example-src/Makefile index 0b11d19..3ba5e53 100644 --- a/example-src/Makefile +++ b/example-src/Makefile @@ -2,44 +2,44 @@ include ../Makefile.cfg CC = $(TARGETCC) INCLUDE = -I../target-inc -CFLAGS = $(TARGETCFLAGS) +CFLAGS = $(TARGETCFLAGS) -Wall -Wextra -Wno-unused -ffreestanding -fno-zero-initialized-in-bss -fomit-frame-pointer -fno-strict-aliasing -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-exceptions -fno-delete-null-pointer-checks -fno-stack-protector -fno-stack-check -fmerge-constants -fmerge-all-constants -std=gnu11 OBJCOPY = $(TARGETOBJCOPY) -OBJECTS = crt0.o dcload-syscall.o dcload-syscalls.o memcpy.o +OBJECTS = crt0.o startup_support.o dcload-syscall.o dcload-syscalls.o memcpy.o .c.o: - $(CC) $(CFLAGS) $(INCLUDE) -o $@ -c $< + $(CC) $(CFLAGS) $(INCLUDE) -Wa,-adghlmns=$*.asm -o $@ -c $< .S.o: - $(CC) $(CFLAGS) $(INCLUDE) -o $@ -c $< + $(CC) $(CFLAGS) $(INCLUDE) -Wa,-adghlmns=$*.asm -o $@ -c $< .s.o: - $(CC) $(CFLAGS) $(INCLUDE) -o $@ -c $< + $(CC) $(CFLAGS) $(INCLUDE) -Wa,-adghlmns=$*.asm -o $@ -c $< all: console-test.bin exception-test.bin gethostinfo.bin console-test.bin: console-test - $(OBJCOPY) -O binary $< $@ + $(OBJCOPY) -O binary $< $@ exception-test.bin: exception-test - $(OBJCOPY) -O binary $< $@ + $(OBJCOPY) -O binary $< $@ gethostinfo.bin: gethostinfo - $(OBJCOPY) -O binary $< $@ + $(OBJCOPY) -O binary $< $@ console-test: $(OBJECTS) console-test.o - $(CC) $(CFLAGS) -Wl,-Tdc$(TARGETCCVER).x -nostartfiles -nostdlib $^ -o $@ -lgcc + $(CC) $(CFLAGS) -Wl,--warn-common -Wl,--no-undefined -Wl,-Map,console-test.map -Wl,-Tdc$(TARGETCCVER).x -nostartfiles -nostdlib $^ -o $@ -lgcc gethostinfo: $(OBJECTS) gethostinfo.o - $(CC) $(CFLAGS) -Wl,-Tdc$(TARGETCCVER).x -nostartfiles -nostdlib $^ -o $@ -lgcc + $(CC) $(CFLAGS) -Wl,--warn-common -Wl,--no-undefined -Wl,-Map,gethostinfo.map -Wl,-Tdc$(TARGETCCVER).x -nostartfiles -nostdlib $^ -o $@ -lgcc exception-test: $(OBJECTS) exception-test.o - $(CC) $(CFLAGS) -Wl,-Tdc$(TARGETCCVER).x -nostartfiles -nostdlib $^ -o $@ -lgcc + $(CC) $(CFLAGS) -Wl,--warn-common -Wl,--no-undefined -Wl,-Map,exception-test.map -Wl,-Tdc$(TARGETCCVER).x -nostartfiles -nostdlib $^ -o $@ -lgcc .PHONY : clean clean: - rm -f *.o console-test exception-test gethostinfo + rm -f *.o console-test exception-test gethostinfo *.map *.asm .PHONY : distclean -distclean: clean +distclean: clean rm -f *.bin diff --git a/example-src/README b/example-src/README index b8011ea..a282818 100644 --- a/example-src/README +++ b/example-src/README @@ -1,4 +1,5 @@ crt0.S a version of crt0.S +startup_support.c a helper file for crt0.S dc.x a linker script for the Dreamcast dcload-syscall.S assembly to call a dcload syscall dcload-syscall.h lowlevel dcload syscall header @@ -6,6 +7,7 @@ dcload-syscalls.c dcload syscall c source dcload-syscalls.h dcload syscall header To use this stuff in your own code, #include "dcload-syscalls.h" and link with dcload-syscalls.o and dcload-syscall.o. +(Well, it's not quite that simple. There are a bunch of headers in target-inc that are needed, as well. The way this was put together initially was very sloppily and did not stand the test of time.) You're welcome to use any of the code in this directory in any way you please. I'm not responsible if it causes you to fart fire, grow a third eye, etc, etc. diff --git a/example-src/console-test.c b/example-src/console-test.c index 3a71e72..d84cfdb 100644 --- a/example-src/console-test.c +++ b/example-src/console-test.c @@ -1,6 +1,6 @@ #include "dcload-syscalls.h" -int main(void) +void main(void) { int fd; unsigned char buffer[2048]; diff --git a/example-src/crt0.S b/example-src/crt0.S index c4ff866..8302af1 100644 --- a/example-src/crt0.S +++ b/example-src/crt0.S @@ -12,7 +12,7 @@ setup_cache: mov.l ccr_addr,r0 mov.w ccr_data,r1 mov.l r1,@r0 - mov.l start_2_k,r0 + mov.l start_2_k,r0 nop nop nop @@ -20,9 +20,9 @@ setup_cache: nop nop nop - jmp @r0 + jmp @r0 nop -start_2: +start_2: mov.l old_stack_k,r14 mov.l r15,@r14 mov.l old_pr_k,r14 @@ -33,21 +33,30 @@ start_2: ! zero out bss mov.l edata_k,r0 mov.l end_k,r1 + cmp/eq r0,r1 ! unless there is no bss + bt no_bss mov #0,r2 start_l: mov.l r2,@r0 add #4,r0 - cmp/ge r0,r1 + cmp/hi r0,r1 ! This was cmp/ge before, which would always write 4 bytes beyond the end... bt start_l +no_bss: #if defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || defined(__SH4_SINGLE_ONLY) mov.l set_fpscr_k, r1 jsr @r1 mov #0,r4 - lds r3,fpscr +! lds r3,fpscr ! This isn't necessary. #endif /* defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || defined(__SH4_SINGLE_ONLY__) */ + ! enable exceptions and the FPU + stc sr,r0 + mov.l sr_mask,r1 + and r1,r0 + or #0xf0,r0 + ldc r0,sr - ! call the mainline + ! call the mainline mov.l main_k,r0 jsr @r0 or r0,r0 @@ -60,10 +69,10 @@ start_l: ___exit: mov.l old_pr_k,r14 - mov.l @r14,r15 + mov.l @r14,r15 lds r15,pr mov.l old_stack_k,r14 - mov.l @r14,r15 + mov.l @r14,r15 rts nop @@ -72,12 +81,15 @@ _atexit: nop .align 4 +sr_mask: + .long 0xefff7fff #if defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || defined(__SH4_SINGLE_ONLY__) set_fpscr_k: - .long ___set_fpscr +! __set_fpscr() is deprecated, use this wrapper for builtin instead + .long ___call_builtin_sh_set_fpscr #endif /* defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || defined(SH4_SINGLE_ONLY) */ stack_k: - .long _stack + .long _stack edata_k: .long _edata end_k: @@ -100,7 +112,7 @@ _old_pr: setup_cache_k: .long setup_cache start_2_k: - .long start_2 + .long start_2 p2_mask: .long 0xa0000000 ccr_addr: @@ -109,7 +121,7 @@ ccr_data: .word 0x090b .align 4 - + #ifdef __ELF__ .section .stack,"aw" #else diff --git a/example-src/dc3.x b/example-src/dc3.x index 5ea23dc..c4e7045 100644 --- a/example-src/dc3.x +++ b/example-src/dc3.x @@ -88,8 +88,8 @@ SECTIONS .rela.bss : { *(.rela.bss) } .rel.plt : { *(.rel.plt) } .rela.plt : { *(.rela.plt) } - .init : - { + .init : + { KEEP (*(.init)) } =0 .plt : { *(.plt) } @@ -123,7 +123,7 @@ SECTIONS .data1 : { *(.data1) } .eh_frame : { *(.eh_frame) } .gcc_except_table : { *(.gcc_except_table) } - .ctors ALIGN(4): + .ctors ALIGN(4): { ___ctors = .; /* gcc uses crtbegin.o to find the start of @@ -159,12 +159,13 @@ SECTIONS /* We want the small data sections together, so single-instruction offsets can access them all, and initialized data all before uninitialized, so we can shorten the on-disk segment size. */ - .sdata : + .sdata : { - *(.sdata) + *(.sdata) *(.sdata.*) *(.gnu.linkonce.s.*) } + . = ALIGN(32 / 8); _edata = .; PROVIDE (edata = .); __bss_start = .; diff --git a/example-src/dc4.x b/example-src/dc4.x index aa78489..16409a9 100644 --- a/example-src/dc4.x +++ b/example-src/dc4.x @@ -163,6 +163,7 @@ SECTIONS { *(.sdata .sdata.* .gnu.linkonce.s.*) } + . = ALIGN(32 / 8); _edata = .; PROVIDE (edata = .); __bss_start = .; .sbss : @@ -179,9 +180,16 @@ SECTIONS /* Align here to ensure that the .bss section occupies space up to _end. Align after .bss to ensure correct alignment even if the .bss section disappears because there are no input sections. - FIXME: Why do we need it? When there is no .bss section, we don't + Question: Why do we need it? When there is no .bss section, we don't pad the .data section. */ - . = ALIGN(. != 0 ? 32 / 8 : 1); + /* Answer: bss must exist and be at least 4 bytes in size because + crt0.S will try to zero out bss even if there isn't one. So we + always need a bss section, and moreover it (_edata in particular) + must be aligned to 4 bytes as 'mov.l Rm,@Rn' will crash otherwise. + This now still needs to be aligned to 4 bytes (to line up with _end if + there is no bss), but with a change to crt0.S it at least will check if + there is a bss section first... */ + . = ALIGN(. != 0 ? 32 /8 : 1); } . = ALIGN(32 / 8); . = ALIGN(32 / 8); diff --git a/example-src/dcload-syscall.h b/example-src/dcload-syscall.h index 27f0a0b..e281db6 100644 --- a/example-src/dcload-syscall.h +++ b/example-src/dcload-syscall.h @@ -2,6 +2,8 @@ #define __DCLOAD_SYSCALL_H__ int dcloadsyscall(unsigned int syscall, ...); +void __exit(int status); +void __call_builtin_sh_set_fpscr(unsigned int value); #define pcreadnr 0 #define pcwritenr 1 @@ -11,7 +13,7 @@ int dcloadsyscall(unsigned int syscall, ...); #define pclinknr 5 #define pcunlinknr 6 #define pcchdirnr 7 -#define pcchmodnr 8 +#define pcchmodnr 8 #define pclseeknr 9 #define pcfstatnr 10 #define pctimenr 11 diff --git a/example-src/dcload-syscalls.c b/example-src/dcload-syscalls.c index 30db9f3..d715f2d 100644 --- a/example-src/dcload-syscalls.c +++ b/example-src/dcload-syscalls.c @@ -1,3 +1,4 @@ +#include "dcload-syscalls.h" #include "dcload-syscall.h" int link (const char *oldpath, const char *newpath) @@ -8,26 +9,26 @@ int link (const char *oldpath, const char *newpath) return -1; } -int read (int file, char *ptr, int len) +int read (int file, void *buf, size_t len) { if (*DCLOADMAGICADDR == DCLOADMAGICVALUE) - return dcloadsyscall(pcreadnr, file, ptr, len); + return dcloadsyscall(pcreadnr, file, buf, len); else return -1; } -int lseek (int file, int ptr, int dir) +int lseek (int filedes, off_t offset, int dir) { if (*DCLOADMAGICADDR == DCLOADMAGICVALUE) - return dcloadsyscall(pclseeknr, file, ptr, dir); + return dcloadsyscall(pclseeknr, filedes, offset, dir); else return -1; } -int write ( int file, char *ptr, int len) +int write ( int file, const void *buf, size_t len) { if (*DCLOADMAGICADDR == DCLOADMAGICVALUE) - return dcloadsyscall(pcwritenr, file, ptr, len); + return dcloadsyscall(pcwritenr, file, buf, len); else return -1; } @@ -40,23 +41,30 @@ int close (int file) return -1; } -int fstat (int file, struct stat *st) +int fstat (int file, struct stat *buf) { if (*DCLOADMAGICADDR == DCLOADMAGICVALUE) - return dcloadsyscall(pcfstatnr, file, st); + return dcloadsyscall(pcfstatnr, file, buf); else return -1; } -int open (const char *path, int flags) +int open (const char *path, int flags, ...) { + va_list ap; + if (*DCLOADMAGICADDR == DCLOADMAGICVALUE) - return dcloadsyscall(pcopennr, path, flags); + { + va_start(ap, flags); + int return_value = dcloadsyscall(pcopennr, path, flags, va_arg(ap, int)); + va_end(ap); + return return_value; + } else return -1; } -int creat (const char *path, int mode) +int creat (const char *path, mode_t mode) { if (*DCLOADMAGICADDR == DCLOADMAGICVALUE) return dcloadsyscall(pccreatnr, path, mode); @@ -79,15 +87,15 @@ void exit (int status) __exit(status); } -int stat (const char *path, struct stat *st) +int stat (const char *path, struct stat *buf) { if (*DCLOADMAGICADDR == DCLOADMAGICVALUE) - return dcloadsyscall(pcstatnr, path, st); + return dcloadsyscall(pcstatnr, path, buf); else return -1; } -int chmod (const char *path, short mode) +int chmod (const char *path, mode_t mode) { if (*DCLOADMAGICADDR == DCLOADMAGICVALUE) return dcloadsyscall(pcchmodnr, path, mode); @@ -95,10 +103,10 @@ int chmod (const char *path, short mode) return -1; } -int utime (const char *path, char *times) +int utime (const char *path, struct utimbuf *buf) { if (*DCLOADMAGICADDR == DCLOADMAGICVALUE) - return dcloadsyscall(pcutimenr, path, times); + return dcloadsyscall(pcutimenr, path, buf); else return -1; } @@ -111,7 +119,7 @@ int chdir (const char *path) return -1; } -long time(long *t) +time_t time(time_t *t) { if (*DCLOADMAGICADDR == DCLOADMAGICVALUE) return dcloadsyscall(pctimenr, t); diff --git a/example-src/dcload-syscalls.h b/example-src/dcload-syscalls.h index 6284c63..083920e 100644 --- a/example-src/dcload-syscalls.h +++ b/example-src/dcload-syscalls.h @@ -1,26 +1,35 @@ #ifndef __DCLOAD_SYSCALLS_H__ #define __DCLOAD_SYSCALLS_H__ +#include +#include +#include +#include +#include +#include +#include +#include + #define O_RDONLY 0 #define O_WRONLY 1 #define O_RDWR 2 int link (const char *oldpath, const char *newpath); -int read (int file, char *ptr, int len); -int lseek (int file, int ptr, int dir); -int write ( int file, char *ptr, int len); +int read(int file, void *buf, size_t len); +off_t lseek(int filedes, off_t offset, int dir); +int write(int file, const void *buf, size_t len); int close (int file); -int fstat (int file, struct stat *st); -int open (const char *path, int flags); -int creat (const char *path, int mode); +int fstat (int file, struct stat *buf); +int open (const char *path, int flags, ...); +int creat (const char *path, mode_t mode); int unlink (const char *path); void exit (int status); -int stat (const char *path, struct stat *st); -int chmod (const char *path, short mode); -int utime (const char *path, char *times); +int stat (const char *path, struct stat *buf); +int chmod (const char *path, mode_t mode); +int utime (const char *path, struct utimbuf *buf); int chdir (const char *path); -long time(long *t); +time_t time(time_t *t); void assign_wrkmem(unsigned char *wrkmem); int gethostinfo(unsigned int *ip, unsigned int *port); -#endif +#endif \ No newline at end of file diff --git a/example-src/exception-test.c b/example-src/exception-test.c index c0c2036..b6f6b6a 100644 --- a/example-src/exception-test.c +++ b/example-src/exception-test.c @@ -1,9 +1,8 @@ -int main(void) +void main(void) { - int i; - - i = *((volatile unsigned int *)2); -} - - - + __builtin_sh_set_fpscr(0x40001 | (1 << 10) ); // enable FPU exception (divide by 0) + asm volatile ("fldi0 fr0\n\t" // load 0.0f + "fldi1 fr1\n\t" // load 1.0f + "fdiv fr0, fr1\n\t" // divide by 0 + ); +} \ No newline at end of file diff --git a/example-src/gethostinfo.c b/example-src/gethostinfo.c index 57b3847..0a38b51 100644 --- a/example-src/gethostinfo.c +++ b/example-src/gethostinfo.c @@ -12,7 +12,7 @@ void uint_to_string(unsigned int foo, unsigned char *bar) bar[8] = 0; } -int main(void) +void main(void) { unsigned int tool_ip; unsigned int tool_port; diff --git a/example-src/startup_support.c b/example-src/startup_support.c new file mode 100644 index 0000000..f336fa9 --- /dev/null +++ b/example-src/startup_support.c @@ -0,0 +1,33 @@ +// This file just contains some C code that is required by crt0.S. +// Based on the DreamHAL one, but adapted for dcload purposes. +// --Moopthehedgehog + +#include "dcload-syscall.h" + +// crt0.S needs this to set FPSCR since GCC deprecated __set_fpscr and +// __get_fpscr and replaced them with builtins. +// +// void __builtin_sh_set_fpscr(uint32_t val) doesn't affect SZ, PR, and FR, +// unlike the old void __set_fpscr(uint32_t val) macro. +// +// uint32_t __builtin_sh_get_fpscr(void), on the other hand, behaves the same as +// the old uint32_t __get_fpscr(void) macro. +// +// Also: the old macros were in libgcc, and the new ones are not (yay!). +// + +#if __GNUC__ <= 4 + +void __call_builtin_sh_set_fpscr(unsigned int value) +{ + __set_fpscr(value); +} + +#else + +void __call_builtin_sh_set_fpscr(unsigned int value) +{ + __builtin_sh_set_fpscr(value); +} + +#endif \ No newline at end of file diff --git a/host-src/tool/dc-tool.c b/host-src/tool/dc-tool.c index 84049f1..192aadf 100644 --- a/host-src/tool/dc-tool.c +++ b/host-src/tool/dc-tool.c @@ -503,17 +503,14 @@ int open_socket(char *hostname) { sin.sin_family = AF_INET; sin.sin_port = htons(31313); + // Try to remove leading zeros from hostname... + cleanup_ip_address(hostname); host = gethostbyname(hostname); if(!host) { - // Try to remove leading zeros from hostname... - cleanup_ip_address(hostname); - host = gethostbyname(hostname); - if(!host) { - // definitely, we can't do nothing - log_error("gethostbyname"); - return -1; - } + // definitely, we can't do nothing + log_error("gethostbyname"); + return -1; } memcpy((char *)&sin.sin_addr, host->h_addr, host->h_length); @@ -945,7 +942,7 @@ int main(int argc, char *argv[]) char *filename = 0; char *isofile = 0; char *path = 0; - char *hostname = DREAMCAST_IP; + char *hostname = 0; char *cleanlist[4] = { 0, 0, 0, 0 }; if(argc < 2) { @@ -953,6 +950,10 @@ int main(int argc, char *argv[]) return 0; } + hostname = malloc(strlen(DREAMCAST_IP) + 1); + cleanlist[3] = hostname; + strcpy(hostname, DREAMCAST_IP); + #ifdef __MINGW32__ if(start_ws()) return -1; @@ -1011,6 +1012,7 @@ int main(int argc, char *argv[]) size = strtoul(optarg, NULL, 0); break; case 't': + free(hostname); hostname = malloc(strlen(optarg) + 1); cleanlist[3] = hostname; strcpy(hostname, optarg); diff --git a/host-src/tool/syscalls.c b/host-src/tool/syscalls.c index 9eac90e..3a8e5bf 100644 --- a/host-src/tool/syscalls.c +++ b/host-src/tool/syscalls.c @@ -117,7 +117,34 @@ int dc_write(unsigned char * buffer) recv_data(data, ntohl(command->value1), ntohl(command->value2), 1); - retval = write(ntohl(command->value0), data, ntohl(command->value2)); + // Check for exception messages. This compare is pretty quick, so it + // shouldn't slow anything down unless someone is really pelting the console + // hard.. Although, in that case printf() will probably become a big + // bottleneck before this memcmp() ever does... + if(!(memcmp(data, CMD_EXCEPTION, 4))) + { + // Exception data starts with "EXPT" + exception_struct_t *exception_frame = (exception_struct_t*)data; + unsigned int *exception_frame_uints = (unsigned int*)data; + + printf("\n\n"); + printf(exception_code_to_string(exception_frame->expt_code)); + for(unsigned int regdump = 0; regdump < 66; regdump++) + { + printf(exception_label_array[regdump]); + printf(": 0x%x\n", exception_frame_uints[regdump + 2]); + } + + // Write out to a file as well + // It will end up in the working directory of the terminal + int out_file = open("dcload_exception_dump.bin", O_CREAT | O_WRONLY | O_TRUNC); + retval = write(out_file, data, ntohl(command->value2)); + close(out_file); + } + else + { + retval = write(ntohl(command->value0), data, ntohl(command->value2)); + } if(send_command(CMD_RETVAL, retval, retval, NULL, 0) == -1) { free(data); @@ -481,8 +508,8 @@ int dc_gdbpacket(unsigned char * buffer) size_t in_size, out_size; static char gdb_buf[GDBBUFSIZE]; int retval = 0; - -#ifdef __MINGW32__ + +#ifdef __MINGW32__ if (gdb_server_socket == INVALID_SOCKET) { #else if (gdb_server_socket < 0) { diff --git a/host-src/tool/syscalls.h b/host-src/tool/syscalls.h index 7be9bb9..1fa1822 100644 --- a/host-src/tool/syscalls.h +++ b/host-src/tool/syscalls.h @@ -69,6 +69,9 @@ int dc_gdbpacket(unsigned char * buffer); #define CMD_GDBPACKET "DC20" #define CMD_REWINDDIR "DC21" +// Special definition for exception handler data +#define CMD_EXCEPTION "EXPT" + struct _command_3int_t { unsigned char id[4]; unsigned int value0; diff --git a/host-src/tool/utils.c b/host-src/tool/utils.c index f9fc593..02e4998 100644 --- a/host-src/tool/utils.c +++ b/host-src/tool/utils.c @@ -1,18 +1,18 @@ #include #include #include -#ifdef __MINGW32__ +#ifdef __MINGW32__ #include #endif void log_error( const char * prefix ) { perror( prefix ); - -#ifdef __MINGW32__ + +#ifdef __MINGW32__ DWORD dwError = WSAGetLastError(); if(dwError) { TCHAR *err = NULL; - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&err, 0, NULL); fprintf(stderr, "WSAGetLastError: %d / %s\n", dwError, err); LocalFree(err); @@ -22,15 +22,15 @@ void log_error( const char * prefix ) { void cleanup_ip_address( char *hostname ) { int bufsize = strlen(hostname) + 1; - + char *buf = malloc(bufsize); memset(buf, '\0', bufsize); - int i = 0, - j = 0, - leading_zero = 1, + int i = 0, + j = 0, + leading_zero = 1, has_value = 0; - + while(i < strlen(hostname)) { char c = hostname[i]; @@ -38,7 +38,7 @@ void cleanup_ip_address( char *hostname ) { case '0': if (!leading_zero) { buf[j++] = c; - has_value = 1; + has_value = 1; } break; case '.': @@ -56,13 +56,75 @@ void cleanup_ip_address( char *hostname ) { break; } - i++; + i++; } - + if(!has_value) { buf[j++] = '0'; } - - strcpy(hostname, buf); + + strcpy(hostname, buf); free(buf); } + +/* converts expevt value to description, used by dc-tool exception processing */ +char * exception_code_to_string(unsigned int expevt) +{ + switch(expevt) { + case 0x1e0: + return "User break\n"; + break; + case 0x0e0: + return "Address error (read)\n"; + break; + case 0x040: + return "TLB miss exception (read)\n"; + break; + case 0x0a0: + return "TLB protection violation exception (read)\n"; + break; + case 0x180: + return "General illegal instruction exception\n"; + break; + case 0x1a0: + return "Slot illegal instruction exception\n"; + break; + case 0x800: + return "General FPU disable exception\n"; + break; + case 0x820: + return "Slot FPU disable exception\n"; + break; + case 0x100: + return "Address error (write)\n"; + break; + case 0x060: + return "TLB miss exception (write)\n"; + break; + case 0x0c0: + return "TLB protection violation exception (write)\n"; + break; + case 0x120: + return "FPU exception\n"; + break; + case 0x080: + return "Initial page write exception\n"; + break; + case 0x160: + return "Unconditional trap (TRAPA)\n"; + break; + default: + return "Unknown exception\n"; + break; + } +} + +// Exception label array +const char * const exception_label_array[66] = {"PC ", "PR ", "SR ", "GBR ", \ +"VBR ", "DBR ", "MACH", "MACL", "R0B0", "R1B0", "R2B0", "R3B0", "R4B0", "R5B0", \ +"R6B0", "R7B0", "R0B1", "R1B1", "R2B1", "R3B1", "R4B1", "R5B1", "R6B1", "R7B1", \ +"R8 ", "R9 ", "R10 ", "R11 ", "R12 ", "R13 ", "R14 ", "R15 ", "FPSC", "FR0 ", \ +"FR1 ", "FR2 ", "FR3 ", "FR4 ", "FR5 ", "FR6 ", "FR7 ", "FR8 ", "FR9 ", "FR10", \ +"FR11", "FR12", "FR13", "FR14", "FR15", "FPUL", "XF0 ", "XF1 ", "XF2 ", "XF3 ", \ +"XF4 ", "XF5 ", "XF6 ", "XF7 ", "XF8 ", "XF9 ", "XF10", "XF11", "XF12", "XF13", \ +"XF14", "XF15"}; diff --git a/host-src/tool/utils.h b/host-src/tool/utils.h index f6105e1..5d3daa1 100644 --- a/host-src/tool/utils.h +++ b/host-src/tool/utils.h @@ -4,4 +4,82 @@ void log_error(const char * prefix); void cleanup_ip_address(char *hostname); +char * exception_code_to_string(unsigned int expevt); + +// Exception struct +struct _exception_struct_t { + unsigned char id[4]; // EXPT + unsigned int expt_code; // Exception code + unsigned int pc; + unsigned int pr; + unsigned int sr; + unsigned int gbr; + unsigned int vbr; + unsigned int dbr; + unsigned int mach; + unsigned int macl; + unsigned int r0b0; + unsigned int r1b0; + unsigned int r2b0; + unsigned int r3b0; + unsigned int r4b0; + unsigned int r5b0; + unsigned int r6b0; + unsigned int r7b0; + unsigned int r0b1; + unsigned int r1b1; + unsigned int r2b1; + unsigned int r3b1; + unsigned int r4b1; + unsigned int r5b1; + unsigned int r6b1; + unsigned int r7b1; + unsigned int r8; + unsigned int r9; + unsigned int r10; + unsigned int r11; + unsigned int r12; + unsigned int r13; + unsigned int r14; + unsigned int r15; // saved from SGR + unsigned int fpscr; + unsigned int fr0; + unsigned int fr1; + unsigned int fr2; + unsigned int fr3; + unsigned int fr4; + unsigned int fr5; + unsigned int fr6; + unsigned int fr7; + unsigned int fr8; + unsigned int fr9; + unsigned int fr10; + unsigned int fr11; + unsigned int fr12; + unsigned int fr13; + unsigned int fr14; + unsigned int fr15; + unsigned int fpul; + unsigned int xf0; + unsigned int xf1; + unsigned int xf2; + unsigned int xf3; + unsigned int xf4; + unsigned int xf5; + unsigned int xf6; + unsigned int xf7; + unsigned int xf8; + unsigned int xf9; + unsigned int xf10; + unsigned int xf11; + unsigned int xf12; + unsigned int xf13; + unsigned int xf14; + unsigned int xf15; +} __attribute__ ((__packed__)); + +typedef struct _exception_struct_t exception_struct_t; + +extern const char * const exception_label_array[66]; + #endif /* __UTILS_H__ */ diff --git a/make-cd/Makefile b/make-cd/Makefile index e6bc9f8..633253a 100644 --- a/make-cd/Makefile +++ b/make-cd/Makefile @@ -1,5 +1,4 @@ CDRECORD = wodim dev=0,0,0 speed=8 -SCRAMBLE = scramble DD = dd CP = cp MKISOFS = genisoimage @@ -20,7 +19,7 @@ burn-audio: audio.raw touch burn-audio 1st_read.bin: $(1ST_READ) - $(SCRAMBLE) $(1ST_READ) 1st_read.bin + cp $(1ST_READ) 1st_read.bin data.raw: tmp.iso IP.BIN ( cat IP.BIN ; dd if=tmp.iso bs=2048 skip=16 ) > data.raw diff --git a/target-src/1st_read/Makefile b/target-src/1st_read/Makefile index 25b4225..6b25d75 100644 --- a/target-src/1st_read/Makefile +++ b/target-src/1st_read/Makefile @@ -10,7 +10,7 @@ asm_only: .PHONY : clean clean: - -rm -f $(TARGET) loader.bin loader.elf loader.o *.asm + -rm -f $(TARGET) loader.bin loader.elf loader.o *.asm *.map .PHONY : distclean distclean: clean @@ -21,7 +21,7 @@ rm-elf: loader.elf: loader.s disable.s ../dcload/dcload.bin ../dcload/exception.bin $(TARGETCC) $(TARGETCFLAGS) -o $@ loader.s disable.s -nostartfiles \ - -nostdlib -Ttext=0x8c010000 -Wa,-I../dcload + -nostdlib -Ttext=0x8c010000 -Wl,-Map=loader.map -Wa,-I../dcload loader.bin: loader.elf $(TARGETOBJCOPY) -O binary $^ $@ diff --git a/target-src/dcload/Makefile b/target-src/dcload/Makefile index 6248b4c..858cb11 100644 --- a/target-src/dcload/Makefile +++ b/target-src/dcload/Makefile @@ -1,12 +1,12 @@ include ../../Makefile.cfg CC = $(TARGETCC) -CFLAGS = $(TARGETCFLAGS) -DDCLOAD_VERSION=\"$(VERSION)\" -DDREAMCAST_IP=\"$(DREAMCAST_IP)\" -Wall -Wextra -Wno-unused -ffreestanding -fno-zero-initialized-in-bss -fomit-frame-pointer -fno-strict-aliasing -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-exceptions -fno-delete-null-pointer-checks -fno-stack-protector -fno-stack-check -fmerge-constants -fmerge-all-constants -std=gnu11 +CFLAGS = $(TARGETCFLAGS) -DDCLOAD_VERSION=\"$(VERSION)\" -DDREAMCAST_IP=\"$(DREAMCAST_IP)\" -DEXCEPTION_SECONDS=$(EXCEPTION_SECONDS) -Wall -Wextra -Wno-unused -ffreestanding -fno-zero-initialized-in-bss -fomit-frame-pointer -fno-strict-aliasing -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-exceptions -fno-delete-null-pointer-checks -fno-stack-protector -fno-stack-check -fmerge-constants -fmerge-all-constants -std=gnu11 INCLUDE = -I../../target-inc OBJCOPY = $(TARGETOBJCOPY) -DCLOBJECTS = dcload-crt0.o syscalls.o memcpy.o memset.o memcmp.o disable.o go.o video.o dcload.o cdfs_redir.o cdfs_syscalls.o bswap.o packet.o rtl8139.o net.o commands.o adapter.o lan_adapter.o maple.o dhcp.o perfctr.o +DCLOBJECTS = dcload-crt0.o startup_support.o syscalls.o memcpy.o memset.o memcmp.o disable.o go.o video.o dcload.o cdfs_redir.o cdfs_syscalls.o bswap.o packet.o rtl8139.o net.o commands.o adapter.o lan_adapter.o maple.o dhcp.o perfctr.o EXCOBJECTS = exception.o %.o : %.c @@ -21,14 +21,14 @@ EXCOBJECTS = exception.o all: dcload.bin exception.bin dcload: $(DCLOBJECTS) - $(CC) $(CFLAGS) -Wl,-Map,output.map -Wl,-Tdcload.x -nostartfiles -nostdlib -static -Wl,-z,now $^ -o $@ -lgcc + $(CC) $(CFLAGS) -Wl,--warn-common -Wl,--no-undefined -Wl,-Map,output.map -Wl,-Tdcload.x -nostartfiles -nostdlib -static -Wl,-z,now $^ -o $@ -lgcc exception: $(EXCOBJECTS) - $(CC) $(CFLAGS) -Wl,-Ttext=0x8c00f400 -nostartfiles -nostdlib -static -Wl,-z,now $^ -o $@ + $(CC) $(CFLAGS) -Wl,-Ttext=0x8c00f400 -Wl,-Map,exception.map -nostartfiles -nostdlib -static -Wl,-z,now $^ -o $@ .PHONY : clean clean: - rm -f $(DCLOBJECTS) $(EXCOBJECTS) dcload exception *.asm output.map + rm -f $(DCLOBJECTS) $(EXCOBJECTS) dcload exception *.asm *.map .PHONY : distclean distclean: clean diff --git a/target-src/dcload/dcload-crt0.s b/target-src/dcload/dcload-crt0.s index dc5f87b..9b77ad3 100644 --- a/target-src/dcload/dcload-crt0.s +++ b/target-src/dcload/dcload-crt0.s @@ -5,7 +5,7 @@ .extern _draw_string .extern _uint_to_string .extern _exception_code_to_string - .extern ___set_fpscr + .extern ___call_builtin_sh_set_fpscr .extern _edata .extern _end @@ -66,12 +66,15 @@ uint_to_string_k: exc_to_string_k: .long _exception_code_to_string +! end of dcload hardcoded stuff + realstart: stc sr,r0 mov.l sr_mask,r1 and r1,r0 or #0xf0,r0 ldc r0,sr + ! register banks may flip here if returning from an exception (but that's ok) mov.l setup_cache_k,r0 mov.l p2_mask,r1 or r1,r0 @@ -98,18 +101,20 @@ start_2: ! zero out bss mov.l edata_k,r0 mov.l end_k,r1 + cmp/eq r0,r1 ! unless there is no bss + bt no_bss mov #0,r2 start_l: mov.l r2,@r0 add #4,r0 - cmp/ge r0,r1 + cmp/hi r0,r1 ! This was cmp/ge before, which would always write 4 bytes beyond the end... bt start_l mov.l set_fpscr_k, r1 jsr @r1 mov #0,r4 - lds r3,fpscr +! lds r3,fpscr ! This isn't necessary. ! call main mov.l main_k,r0 @@ -126,9 +131,10 @@ _atexit: .align 4 sr_mask: - .long 0xefff7fff + .long 0xcfff7fff ! want to be in bank 0, especially after exception handler runs set_fpscr_k: - .long ___set_fpscr +! __set_fpscr() is deprecated, use this wrapper for builtin instead + .long ___call_builtin_sh_set_fpscr stack_k: .long _stack edata_k: diff --git a/target-src/dcload/dcload.c b/target-src/dcload/dcload.c index 5a385e8..531b2ad 100644 --- a/target-src/dcload/dcload.c +++ b/target-src/dcload/dcload.c @@ -38,9 +38,6 @@ // Modify the branding slightly to prevent confusing it with stock DCLoad-IP #define NAME "dcload-ip " DCLOAD_VERSION " - with DHCP" -#define VIDMODEREG (volatile unsigned int *)0xa05f8044 -#define VIDBORDER (volatile unsigned int *)0xa05f8040 - // Scale up the onscreen refresh interval #define ONSCREEN_REFRESH_SCALED ((unsigned long long int)ONSCREEN_DHCP_LEASE_TIME_REFRESH_INTERVAL * (unsigned long long int)PERFCOUNTER_SCALE) @@ -238,16 +235,19 @@ void draw_progress(unsigned int current, unsigned int total) // called by exception.s void setup_video(unsigned int mode, unsigned int color) { - init_video(check_cable(), mode); + STARTUP_Init_Video(mode); clrscr(color); } static void error_bb(char *msg) { - setup_video(0, 0x2000); // Red screen + setup_video(FB_RGB0555, 0x2000); // Red screen draw_string(30, 54, NAME, STR_COLOR); draw_string(30, 78, msg, STR_COLOR); - while(1); + while(1) + { + asm volatile ("sleep"); // This way it doesn't actually halt and catch fire ;) + } } void disp_info(void) @@ -255,7 +255,7 @@ void disp_info(void) int c; unsigned char *ip = (unsigned char *)&our_ip; - setup_video(0, BG_COLOR); + setup_video(FB_RGB0555, BG_COLOR); draw_string(30, 54, NAME, STR_COLOR); draw_string(30, 78, bb->name, STR_COLOR); draw_string(30, 102, mac_string, STR_COLOR); @@ -498,7 +498,7 @@ void set_ip_dhcp(void) // GCC has no clobber for fpscr, so this needs to be its own line asm volatile ("lds r1,fpscr\n\t"); // Load R1 into fpscr - // Using paired would reduce this to 2 instructions and minimize memory accesses + // Using paired moves would reduce this to 2 instructions and minimize memory accesses // Unpaired moves take 2 instructions (memory accesses) per double // Don't be fooled: I already flipped the two 32-bit halves of the doubles in memory // because I wanted to try using paired moves (via fmov.d). ;) @@ -754,7 +754,6 @@ int main(void) #endif while (1) { - *VIDBORDER = 0; if (booted) { disp_status("idle..."); diff --git a/target-src/dcload/dcload.h b/target-src/dcload/dcload.h index ad90387..32f546b 100644 --- a/target-src/dcload/dcload.h +++ b/target-src/dcload/dcload.h @@ -65,7 +65,7 @@ // Enable for perf counter debugging printouts, placed under the disp_status area // It's perf high stuck to perf low, and then the contents of the pmcr reg in use // (i.e. the reg specified by DCLOAD_PMCR) -#define PERFCTR_DEBUG +//#define PERFCTR_DEBUG // Use FPSCR PR=1, SZ=1 to improve double-precision loading performance (use 2x // 64-bit "paired moves" via fmov.d versus 4x 32-bit "single moves" via fmov.s). @@ -83,6 +83,7 @@ extern volatile unsigned char running; // Called by asm functions char * exception_code_to_string(unsigned int expevt); void uint_to_string(unsigned int foo, unsigned char *bar); +void setup_video(unsigned int mode, unsigned int color); void disp_info(void); void disp_status(const char * status); @@ -91,4 +92,17 @@ void clear_lines(unsigned int y, unsigned int n, unsigned int c); // Exported for bb->loop void set_ip_dhcp(void); +// For dcload-crt0.s to interface with startup_support.c +void __call_builtin_sh_set_fpscr(unsigned int value); + +// These definitions correspond to 'fbuffer_color_mode' in STARTUP_Init_Video() +// dcload only supports 16-bit color modes +#define FB_RGB0555 0 +#define FB_RGB565 1 + +// To set video modes via startup_support.c +// dcload only supports 640x480 modes +void STARTUP_Init_Video(unsigned char fbuffer_color_mode); +void STARTUP_Set_Video(unsigned char fbuffer_color_mode); + #endif diff --git a/target-src/dcload/dcload.old b/target-src/dcload/dcload.old deleted file mode 100644 index 500db9b..0000000 --- a/target-src/dcload/dcload.old +++ /dev/null @@ -1,241 +0,0 @@ -/* - * dcload, a Dreamcast ethernet loader - * - * Copyright (C) 2001 Andrew Kieschnick - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* uncomment following line to enable crappy screensaver (it just blanks) */ -/* #define SCREENSAVER */ - -#include "scif.h" -#include "video.h" -#include "packet.h" -#include "commands.h" -#include "adapter.h" -#include "net.h" -#include "cdfs.h" -#include "maple.h" - -#define NAME "dcload-ip " DCLOAD_VERSION - -#define VIDMODEREG (volatile unsigned int *)0xa05f8044 -#define VIDBORDER (volatile unsigned int *)0xa05f8040 - -unsigned int booted = 0; -unsigned int running = 0; - -/* converts expevt value to description, used by exception handler */ -unsigned char * exception_code_to_string(unsigned int expevt) -{ - switch(expevt) { - case 0x1e0: - return "User break"; - break; - case 0x0e0: - return "Address error (read)"; - break; - case 0x040: - return "TLB miss exception (read)"; - break; - case 0x0a0: - return "TLB protection violation exception (read)"; - break; - case 0x180: - return "General illegal instruction exception"; - break; - case 0x1a0: - return "Slot illegal instruction exception"; - break; - case 0x800: - return "General FPU disable exception"; - break; - case 0x820: - return "Slot FPU disable exception"; - break; - case 0x100: - return "Address error (write)"; - break; - case 0x060: - return "TLB miss exception (write)"; - break; - case 0x0c0: - return "TLB protection violation exception (write)"; - break; - case 0x120: - return "FPU exception"; - break; - case 0x080: - return "Initial page write exception"; - break; - case 0x160: - return "Unconditional trap (TRAPA)"; - break; - default: - return "Unknown exception"; - break; - } -} - -void uint_to_string(unsigned int foo, unsigned char *bar) -{ - char hexdigit[16] = "0123456789abcdef"; - int i; - - for(i=7; i>=0; i--) { - bar[i] = hexdigit[(foo & 0x0f)]; - foo = foo >> 4; - } - bar[8] = 0; -} - -void uchar_to_string(unsigned int foo, unsigned char *bar) -{ - char hexdigit[16] = "0123456789abcdef"; - int i; - - bar[1] = hexdigit[foo & 0x0f]; - bar[0] = hexdigit[foo >> 4]; -} - -/* set n lines starting at line y to value c */ -void clear_lines(unsigned int y, unsigned int n, unsigned int c) -{ - unsigned short * vmem = (unsigned short *)(0xa5000000 + y*640*2); - n = n * 640; - while (n-- > 0) - *vmem++ = c; -} - -void draw_progress(unsigned int current, unsigned int total) -{ - unsigned char current_string[9]; - unsigned char total_string[9]; - - uint_to_string(total, total_string); - uint_to_string(current, current_string); - clear_lines(120, 24, 0x0010); - draw_string(30, 174, "(", 0xffff); - draw_string(42, 174, current_string, 0xffff); - draw_string(138, 174, "/", 0xffff); - draw_string(150, 174, total_string, 0xffff); - draw_string(246, 174, ")", 0xffff); -} - -void setup_video(unsigned int mode, unsigned int color) -{ - init_video(check_cable(), mode); - clrscr(color); -} - -void error_bb(unsigned char *msg) -{ - setup_video(0,0x2000); - draw_string(30, 54, NAME, 0xffff); - draw_string(30, 78, msg, 0xffff); - while(1); -} - -unsigned char *mac_string = "de:ad:be:ef:ba:be"; -unsigned char *ip_string = "00.00.00.00"; - -void disp_info(void) -{ - int c; - unsigned char *ip = (unsigned char *)&our_ip; - - setup_video(0,0x0010); - draw_string(30, 54, NAME, 0xffff); - draw_string(30, 78, bb->name, 0xffff); - draw_string(30, 102, mac_string, 0xffff); - for(c = 0; c < 4; c++) - uchar_to_string(ip[3-c], &ip_string[c*3]); - draw_string(30, 126, ip_string, 0xffff); - booted = 1; -} - -void disp_status(const char * status) { - clear_lines(150, 24, 0x0010); - draw_string(30, 150, status, 0xffff); -} - -void set_ip(void) -{ - int i; - int c; - unsigned char *ip = (unsigned char *)&our_ip; - - i = 0; - c = 0; - - while(DREAMCAST_IP[c] != 0) { - if (DREAMCAST_IP[c] != '.') { - ip[i] *= 10; - ip[i] += DREAMCAST_IP[c] - '0'; - } - else - i++; - c++; - } - - our_ip = ntohl(our_ip); - -} - -int main(void) -{ - unsigned char crap; - unsigned int addr; - unsigned int size; - unsigned int console; - unsigned int start; - - running = 0; - - /* scif_init(115200); */ - - if (adapter_detect() < 0) - error_bb("NO ETHERNET ADAPTER DETECTED!"); - - for(start = 0; start < 6; start++) - uchar_to_string(bb->mac[start], mac_string + start*3); - - set_ip(); - - cdfs_redir_save(); /* will only save value once */ - cdfs_redir_disable(); - - maple_init(); - - if (!booted) { - disp_info(); - } else - booted = 0; - /* - scif_puts(NAME); - scif_puts("\n"); - */ - while (1) { - *VIDBORDER = 0; - - if (booted) { - disp_status("idle..."); - } - - bb->loop(0); - } -} diff --git a/target-src/dcload/exception.s b/target-src/dcload/exception.s index 0959290..ddd39db 100644 --- a/target-src/dcload/exception.s +++ b/target-src/dcload/exception.s @@ -3,8 +3,13 @@ ! a general exception handler that displays a register dump onscreen ! for general exceptions (VBR + 0x100) and TLB miss exceptions (VBR + 0x400) ! - + .globl start .section .text + +! The 'start' label just stops a scary-looking, but ultimately meaningless (for +! our purposes) warning that is thrown by the ld linker. + +start: disp_labels: ! r4 -> @(0,r15) = addr of labels @@ -25,11 +30,10 @@ disp_loop: mov.l @(12,r15),r4 mov.l @(8,r15),r5 mov.l @(0,r15),r6 - mov #0xff,r7 mov.l draw_k,r0 mov.l @r0,r0 jsr @r0 - nop + mov #0xff,r7 ! increment / decrement / blahblahblah mov.l @(8,r15),r0 add #24,r0 @@ -61,24 +65,22 @@ disp_values: val_loop: mov.l r0,@(4,r15) mov.l @(0,r15),r4 - mov.l @r4,r4 ! convert string mova misc_string,r0 mov r0,r5 mov.l uint_to_string_k,r0 mov.l @r0,r0 jsr @r0 - nop + mov.l @r4,r4 mova misc_string,r0 mov r0,r6 ! display string mov.l @(12,r15),r4 mov.l @(8,r15),r5 - mov #0xff,r7 mov.l draw_k,r0 mov.l @r0,r0 jsr @r0 - nop + mov #0xff,r7 ! increment / decrement mov.l @(8,r15),r0 add #24,r0 @@ -102,67 +104,98 @@ general_1: ! assume the stack may be fux0red mov.l stack_addr,r15 ! save and display registers - add #-66,r15 - add #-66,r15 - add #-66,r15 - add #-66,r15 + add #-128,r15 ! 264 bytes for regs + add #-128,r15 ! only get a signed 8-bit immediate + add #-8,r15 ! that makes 264 sts.l pr,@-r15 mov.l r0,@-r15 - mov.l r1,@-r15 +! do regdump display mova regdump,r0 jsr @r0 - nop + mov.l r1,@-r15 ! These extra 12 make 276, but the first 264 bytes is the dump area +! get expevt code to put at bottom of regdump stack area + mov.l expevt,r0 +! don't need temporary pr, r0, and r1 at this position on stack anymore after regdump runs add #12,r15 - add #66,r15 - add #66,r15 - add #66,r15 - add #66,r15 + mov.l @r0,r1 + mov.l exception_id,r0 ! "EXPT" ID (no null-term) + mov.l r1,@-r15 ! overwrite temporary stack-stored pr with expevt code + mov.l r0,@-r15 ! overwrite temporary stack-stored r0 with "EXPT" (first data out in transmitted dump) +! send regdump to host with expevt and ID +! using a syscall will automatically check if dctool console is enabled or not + mov #1,r4 ! write is dcload syscall 1 + mov #1,r5 ! stdout is file descriptor 1 + mov.l stack_addr,r6 ! address to dump + mov.l dump_size,r7 ! dump size + mov.l dcloadsyscall_k,r0 + mov.l @r0,r0 ! get dump function call hardcoded in dcload-crt0.s + jsr @r0 + sub r7,r6 ! stack_addr -= dump_size +! reset stack + mov.l stack_addr,r15 ! display exception identifier string mov.l expevt,r4 - mov.l @r4,r4 mov.l exc_to_string_k,r0 mov.l @r0,r0 jsr @r0 - nop + mov.l @r4,r4 mov #0,r4 - mov #24,r5 mov r0,r6 mov #0xff,r7 mov.l draw_k,r0 mov.l @r0,r0 jsr @r0 - nop + mov #24,r5 ! display "EXPEVT" mov #0,r4 - mov #48,r5 mova expevt_string,r0 mov r0,r6 mov #0xff,r7 mov.l draw_k,r0 mov.l @r0,r0 jsr @r0 - nop + mov #48,r5 ! convert expevt to string mov.l expevt,r4 - mov.l @r4,r4 mova misc_string,r0 mov r0,r5 mov.l uint_to_string_k,r0 mov.l @r0,r0 jsr @r0 - nop + mov.l @r4,r4 ! display expevt mov #84,r4 extu.b r4,r4 - mov #48,r5 mova misc_string,r0 mov r0,r6 mov #0xff,r7 mov.l draw_k,r0 mov.l @r0,r0 jsr @r0 - nop + mov #48,r5 +! call dcload's exit via syscall interface to terminate console if it's running + mov.l dcloadsyscall_k,r0 + mov.l @r0,r0 + jsr @r0 + mov #15,r4 ! dcload's exit syscall is syscall 15 +! Let's add a few seconds delay here to be able to read the screen +! ...or at least take a photo of it + mov #0,r0 + mov.l timeout_1second,r1 +#if (EXCEPTION_SECONDS > 60) || (EXCEPTION_SECONDS < 0) + mov #15,r2 +#else + mov #EXCEPTION_SECONDS,r2 +#endif + mul.l r1,r2 + sts MACL,r1 +wait_for_a_bit: +! This is a 3-cycle loop + cmp/eq r1,r0 + bf/s wait_for_a_bit + add #1,r0 ! return to bootloader +return_to_loader: mov.l entry_addr,r0 jmp @r0 nop @@ -171,6 +204,19 @@ stack_addr: .long 0x8d000000 exc_to_string_k: .long 0x8c00401c +timeout_1second: + .long 66666666 +dump_size: +! numbytes to dump + .long 272 +exception_id: +! "EXPT" (no null termination) + .long 0x54505845 +dcloadsyscall_k: + .long 0x8c004008 + +! regdump will be aligned to 4 bytes just by virtue of how all the above variables +! are aligned to 4 bytes and are all longs. regdump: ! save registers for display @@ -351,39 +397,34 @@ regdump: mov.l setup_video_k,r0 mov.l @r0,r0 mov #0,r4 - mov #0x1f,r5 jsr @r0 - nop + mov #0x1f,r5 ! display 1st set of labels mov.l labels1_k,r4 - mov #16,r5 mov #0,r6 mov #72,r7 mov.l disp_addr,r0 jsr @r0 - nop + mov #16,r5 ! display 2nd set of labels mov.l labels2_k,r4 - mov #16,r5 mov #160,r6 extu.b r6,r6 mov #72,r7 mov.l disp_addr,r0 jsr @r0 - nop + mov #16,r5 ! display 3rd set of labels mov.l labels3_k,r4 - mov #17,r5 mov #160,r6 extu.b r6,r6 shll r6 mov #48,r7 mov.l disp_addr,r0 jsr @r0 - nop + mov #17,r5 ! display 4th set of labels mov.l labels4_k,r4 - mov #17,r5 mov #160,r6 extu.b r6,r6 mov r6,r7 @@ -392,23 +433,21 @@ regdump: mov #48,r7 mov.l disp_addr,r0 jsr @r0 - nop + mov #17,r5 ! display 1st set of values mov r15,r0 add #16,r0 mov r0,r4 - mov #16,r5 mov #52,r6 mov #72,r7 mov.l val_addr,r0 jsr @r0 - nop + mov #16,r5 ! display 2nd set of values mov r15,r0 add #16,r0 add #64,r0 mov r0,r4 - mov #16,r5 mov #52,r6 mov #160,r7 extu.b r7,r7 @@ -416,7 +455,7 @@ regdump: mov #72,r7 mov.l val_addr,r0 jsr @r0 - nop + mov #16,r5 ! display 3rd set of values mov r15,r0 add #16,r0 @@ -424,7 +463,6 @@ regdump: extu.b r1,r1 add r1,r0 mov r0,r4 - mov #17,r5 mov #52,r6 mov #160,r7 extu.b r7,r7 @@ -433,7 +471,7 @@ regdump: mov #48,r7 mov.l val_addr,r0 jsr @r0 - nop + mov #17,r5 ! display 4th set of values mov r15,r0 add #16,r0 @@ -441,7 +479,6 @@ regdump: extu.b r1,r1 add r1,r0 mov r0,r4 - mov #17,r5 mov #52,r6 mov #160,r7 extu.b r7,r7 @@ -452,7 +489,7 @@ regdump: mov #48,r7 mov.l val_addr,r0 jsr @r0 - nop + mov #17,r5 ! return lds.l @r15+,pr rts @@ -495,6 +532,9 @@ misc_string: ! VBR + 0x400 general_2: +! Do not put a branch instruction as the first instruction of an exception routine. +! This is mentioned explicitly in various available SH4 hardware documents (as of late 2019/early 2020, anyways). + nop ! So please do not remove this nop. bra general_1 nop .align 2 @@ -576,5 +616,6 @@ labels4: ! VBR + 0x600 interrupt: + nop ! would rather not have a return as the first instruction given a branch shouldn't be there rte nop diff --git a/target-src/dcload/perfctr.c b/target-src/dcload/perfctr.c index c1308db..dcb07de 100644 --- a/target-src/dcload/perfctr.c +++ b/target-src/dcload/perfctr.c @@ -99,7 +99,7 @@ static const unsigned int pmcr2_regl = PMCTR2L_REG; // out_array should be an array consisting of 2x unsigned ints. void PMCR_Read(int which, volatile unsigned int *out_array) { - // if pmcr is not enabled, this function will just return 0 + // if pmcr is disabled, it will just return 0 // little endian (big endian would need to flip [0] and [1]) @@ -112,7 +112,7 @@ void PMCR_Read(int which, volatile unsigned int *out_array) // // One thing that would be nice is if SH4 had the movi20s instruction to make // absolute addresses in 3 cycles, but only the SH2A has that... :( - if( (which == 1) && (pmcr_enabled & 0x1) ) + if(which == 1) { // counter 1 // out_array[1] = *((volatile unsigned int*)PMCTR1H_REG) & 0xffff; @@ -129,7 +129,7 @@ void PMCR_Read(int which, volatile unsigned int *out_array) : "r1", "r2" ); } - else if( (which == 2) && (pmcr_enabled & 0x2) ) + else if(which == 2) { // counter 2 // out_array[1] = *((volatile unsigned int*)PMCTR2H_REG) & 0xffff; @@ -146,11 +146,6 @@ void PMCR_Read(int which, volatile unsigned int *out_array) : "r1", "r2" ); } - else if(!pmcr_enabled) - { - out_array[1] = 0; - out_array[0] = 0; - } else // Invalid { out_array[1] = 0xffff; diff --git a/target-src/dcload/startup_support.c b/target-src/dcload/startup_support.c new file mode 100644 index 0000000..906d400 --- /dev/null +++ b/target-src/dcload/startup_support.c @@ -0,0 +1,197 @@ +// This file just contains some C code that is required by dcload-crt0.s and +// startup routines. Based on the DreamHAL startup_support.c, but specially +// adapted and simplified for dcload to use. +// +// DreamHAL: https://github.com/Moopthehedgehog/DreamHAL/ +// +// --Moopthehedgehog + +#include "dcload.h" +#include + +// dcload-crt0.s needs this to set FPSCR since GCC deprecated __set_fpscr and +// __get_fpscr and replaced them with builtins. +// +// void __builtin_sh_set_fpscr(uint32_t val) doesn't affect SZ, PR, and FR, +// unlike the old void __set_fpscr(uint32_t val) macro. +// +// uint32_t __builtin_sh_get_fpscr(void), on the other hand, behaves the same as +// the old uint32_t __get_fpscr(void) macro. +// +// Also: the old macros were in libgcc, and the new ones are not (yay!). +// + +#if __GNUC__ <= 4 + +void __call_builtin_sh_set_fpscr(unsigned int value) +{ + __set_fpscr(value); +} + +#else + +void __call_builtin_sh_set_fpscr(unsigned int value) +{ + __builtin_sh_set_fpscr(value); +} + +#endif + + +// These get set by STARTUP_Init_Video() for use only by STARTUP_Set_Video() +static volatile uint32_t cable_mode = 0; +static volatile uint32_t video_region = 0; + +// Video mode is automatically determined based on cable type and console region +// This sets up everything related to Dreamcast video modes. +// The framebuffer address will always be 0xa5000000 after this runs. +void STARTUP_Init_Video(unsigned char fbuffer_color_mode) +{ + // Set cable type to hardware pin setting + // Need to read port 8 and 9 data (bits 8 & 9 in PDTRA), so set them as input + // direction via PCTRA (necessary per SH7750 hardware manual): + *(volatile uint32_t*)0xff80002c = ( (*(volatile uint32_t*)0xff80002c) & 0xfff0ffff ) | 0x000a0000; + + // According to the BootROM, cable data is on PORT8/9 GPIO pins. + // Read them and then write them to somewhere in AICA memory (refer to notes + // section for an explanation and a theory as to why this might be necessary): + cable_mode = (uint32_t)( (*(volatile uint16_t*)0xff800030) & 0x300 ); + *(volatile uint32_t*)0xa0702c00 = ( (*(volatile uint32_t*)0xa0702c00) & 0xfffffcff ) | cable_mode; + // Per the SH7750 manual, there are 16 data regs, hence a 16-bit read should + // be used on PDTRA. + + // Store video output region (0 = NTSC, 1 = PAL) + video_region = (*(uint8_t*)0x8c000074) - 0x30; + + // Reset graphics subsystem (PVR2), but keep the graphics memory bus on ..or + // else things will hang when writing to graphics memory since it got disabled! + *(volatile uint32_t*)0xa05f8008 = 0x00000003; + // Re-enable PVR, TA + *(volatile uint32_t*)0xa05f8008 = 0x00000000; + + STARTUP_Set_Video(fbuffer_color_mode); +} + +// The framebuffer address will always be 0xa5000000 after this runs. +void STARTUP_Set_Video(unsigned char fbuffer_color_mode) +{ + uint32_t horiz_active_area = 640; + uint32_t vert_active_area = 480; + // {RGB0555, RGB565} = 2Bpp, {RGB888} = 3Bpp, {RGB0888} = 4Bpp + uint32_t bpp_mode_size = fbuffer_color_mode + 1 + (0x1 ^ ((fbuffer_color_mode & 0x1) | (fbuffer_color_mode >> 1))); // Add another 1 only if 0b00 + + if(!cable_mode) // VGA 640x480 @ 60Hz + { + // Set registers the same way that the BootROM does + *(volatile uint32_t*)0xa05f80e8 = 0x00160008; + *(volatile uint32_t*)0xa05f8044 = 0x00800000 | (fbuffer_color_mode << 2); + + *(volatile uint32_t*)0xa05f804c = (horiz_active_area * bpp_mode_size) / 8; // for PVR to know active area width + *(volatile uint32_t*)0xa05f8040 = 0x00000000; // Border color in RGB0888 format + *(volatile uint32_t*)0xa05f805c = (1 << 20) | ((vert_active_area - 1) << 10) | (((horiz_active_area * bpp_mode_size) / 4) - 1); // progressive scan has a 1 since no lines are skipped + *(volatile uint32_t*)0xa05f80ec = 0x000000a8; + *(volatile uint32_t*)0xa05f80f0 = 0x00280028; + *(volatile uint32_t*)0xa05f80c8 = 0x03450000; + *(volatile uint32_t*)0xa05f80cc = 0x00150208; + *(volatile uint32_t*)0xa05f80d0 = 0x00000100; + *(volatile uint32_t*)0xa05f80d4 = 0x007e0345; + *(volatile uint32_t*)0xa05f80d8 = 0x020c0359; + *(volatile uint32_t*)0xa05f80dc = 0x00280208; + *(volatile uint32_t*)0xa05f80e0 = 0x03f1933f; + + uint32_t scan_area_size = horiz_active_area * vert_active_area; + uint32_t scan_area_size_bytes = scan_area_size * bpp_mode_size; // This will always be divisible by 4 + + // Reset framebuffer address + *(volatile uint32_t*)0xa05f8050 = 0x00000000; // BootROM sets this to 0x00200000 (framebuffer base is 0xa5000000 + this) + *(volatile uint32_t*)0xa05f8054 = 0x00000000; // Same for progressive, resetting the offset gets us 2MB VRAM back after BootROM is done with it + + // zero out framebuffer area + for(uint32_t pixel_or_two = 0; pixel_or_two < scan_area_size_bytes; pixel_or_two += 4) + { + *(uint32_t*)(0xa5000000 + pixel_or_two) = 0; + } + + // re-enable video + *(volatile uint32_t*)0xa05f80e8 &= ~8; + *(volatile uint32_t*)0xa05f8044 |= 1; + } + else if(!video_region) // NTSC (480i) + { + // Set registers the same way that the BootROM does + *(volatile uint32_t*)0xa05f80e8 = 0x00160008; + *(volatile uint32_t*)0xa05f8044 = 0x00000000 | (fbuffer_color_mode << 2); + + *(volatile uint32_t*)0xa05f804c = (horiz_active_area * bpp_mode_size) / 8; // for PVR to know active area width + *(volatile uint32_t*)0xa05f8040 = 0x00000000; // Border color in RGB0888 format + *(volatile uint32_t*)0xa05f805c = ((((horiz_active_area * bpp_mode_size) / 4) + 1) << 20) | (((vert_active_area / 2) - 1) << 10) | (((horiz_active_area * bpp_mode_size) / 4) - 1); + *(volatile uint32_t*)0xa05f80ec = 0x000000a4; + *(volatile uint32_t*)0xa05f80f0 = 0x00120012; + *(volatile uint32_t*)0xa05f80c8 = 0x03450000; + *(volatile uint32_t*)0xa05f80cc = 0x00150104; + *(volatile uint32_t*)0xa05f80d0 = 0x00000150; + *(volatile uint32_t*)0xa05f80d4 = 0x007e0345; + *(volatile uint32_t*)0xa05f80d8 = 0x020c0359; + *(volatile uint32_t*)0xa05f80dc = 0x00240204; + *(volatile uint32_t*)0xa05f80e0 = 0x07d6c63f; + + uint32_t scan_area_size = horiz_active_area * vert_active_area; + uint32_t scan_area_size_bytes = scan_area_size * bpp_mode_size; // This will always be divisible by 4 + + // Reset framebuffer address + *(volatile uint32_t*)0xa05f8050 = 0x00000000; // BootROM sets this to 0x00200000 (framebuffer base is 0xa5000000 + this) + *(volatile uint32_t*)0xa05f8054 = horiz_active_area * bpp_mode_size; // This is for interlaced, resetting the offset gets us 2MB VRAM back after BootROM is done with it + + // zero out framebuffer area + for(uint32_t pixel_or_two = 0; pixel_or_two < scan_area_size_bytes; pixel_or_two += 4) + { + *(uint32_t*)(0xa5000000 + pixel_or_two) = 0; + } + + // re-enable video + *(volatile uint32_t*)0xa05f80e8 &= ~8; + *(volatile uint32_t*)0xa05f8044 |= 1; + } + else // PAL (576i) + { + #ifdef PAL_EXTRA_LINES + // Interlaced PAL can actually have 528 active vertical lines on the Dreamcast (48 more than NTSC!) + // In theory a developer could hide a secret message for PAL players in this area + vert_active_area += 48; + #endif + + // Set registers the same way that the BootROM does + *(volatile uint32_t*)0xa05f80e8 = 0x00160008; + *(volatile uint32_t*)0xa05f8044 = 0x00000000 | (fbuffer_color_mode << 2); + + *(volatile uint32_t*)0xa05f804c = (horiz_active_area * bpp_mode_size) / 8; // for PVR to know active area width + *(volatile uint32_t*)0xa05f8040 = 0x00000000; // Border color in RGB0888 format + *(volatile uint32_t*)0xa05f805c = ((((horiz_active_area * bpp_mode_size) / 4) + 1) << 20) | (((vert_active_area / 2) - 1) << 10) | (((horiz_active_area * bpp_mode_size) / 4) - 1); + *(volatile uint32_t*)0xa05f80ec = 0x000000ae; + *(volatile uint32_t*)0xa05f80f0 = 0x002e002d; + *(volatile uint32_t*)0xa05f80c8 = 0x034b0000; + *(volatile uint32_t*)0xa05f80cc = 0x00150136; + *(volatile uint32_t*)0xa05f80d0 = 0x00000190; + *(volatile uint32_t*)0xa05f80d4 = 0x008d034b; + *(volatile uint32_t*)0xa05f80d8 = 0x0270035f; + *(volatile uint32_t*)0xa05f80dc = 0x002c026c; + *(volatile uint32_t*)0xa05f80e0 = 0x07d6a53f; + + uint32_t scan_area_size = horiz_active_area * vert_active_area; + uint32_t scan_area_size_bytes = scan_area_size * bpp_mode_size; // This will always be divisible by 4 + + // Reset framebuffer address + *(volatile uint32_t*)0xa05f8050 = 0x00000000; // BootROM sets this to 0x00200000 (framebuffer base is 0xa5000000 + this) + *(volatile uint32_t*)0xa05f8054 = horiz_active_area * bpp_mode_size; // This is for interlaced, resetting the offset gets us 2MB VRAM back after BootROM is done with it + + // zero out framebuffer area + for(uint32_t pixel_or_two = 0; pixel_or_two < scan_area_size_bytes; pixel_or_two += 4) + { + *(uint32_t*)(0xa5000000 + pixel_or_two) = 0; + } + + // re-enable video + *(volatile uint32_t*)0xa05f80e8 &= ~8; + *(volatile uint32_t*)0xa05f8044 |= 1; + } +} \ No newline at end of file diff --git a/target-src/dcload/video.h b/target-src/dcload/video.h index 520d63b..935d44f 100644 --- a/target-src/dcload/video.h +++ b/target-src/dcload/video.h @@ -3,8 +3,6 @@ void draw_string(int x, int y, const char *string, int colour); void clrscr(int colour); -void init_video(int cabletype, int pixelmode); -int check_cable(void); unsigned char *get_font_address(void); #endif diff --git a/target-src/dcload/video.s b/target-src/dcload/video.s index 6ebb6a1..e30cdea 100644 --- a/target-src/dcload/video.s +++ b/target-src/dcload/video.s @@ -1,8 +1,8 @@ - ! Video routines from Vide example + ! Video routines from Video example ! - .globl _draw_string, _clrscr, _init_video, _check_cable + .globl _draw_string, _clrscr .globl _get_font_address .text @@ -114,7 +114,7 @@ decided: mov #24,r2 ! char is 24 lines high drawy: - ! Each pixel line is stored as 1½ bytes, so we'll load + ! Each pixel line is stored as 1.5 bytes, so we'll load ! 3 bytes into r4 and draw two lines in one go mov.b @r1+,r4 shll8 r4 @@ -183,154 +183,6 @@ vrambase: clrcount: .long 640*480 - - - ! Set up video registers to the desired - ! video mode (only 640*480 supported right now) - ! - ! Note: This function does not currently initialize - ! all registers, but assume that the boot ROM - ! has set up reasonable defaults for syncs etc. - ! - ! TODO: PAL - - ! r4 = cabletype (0=VGA, 2=RGB, 3=Composite) - ! r5 = pixel mode (0=RGB555, 1=RGB565, 3=RGB888) -_init_video: - ! Look up bytes per pixel as shift value - mov #3,r1 - and r5,r1 - mova bppshifttab,r0 - mov.b @(r0,r1),r5 - ! Get video HW address - mov.l videobase,r0 - mov #0,r2 - mov.l r2,@(8,r0) - add #0x40,r0 - ! Set border colour - mov #0,r2 - mov.l r2,@r0 - ! Set pixel clock and colour mode - shll2 r1 - mov #240/2,r3 ! Non-VGA screen has 240 display lines - shll r3 - mov #2,r2 - tst r2,r4 - bf/s khz15 - add #1,r1 - shll r3 ! Double # of display lines for VGA - ! Set double pixel clock - mov #1,r2 - rotr r2 - shlr8 r2 - or r2,r1 -khz15: - mov.l r1,@(4,r0) - ! Set video base address - mov #0,r1 - mov.l r1,@(0x10,r0) - ! Video base address for short fields should be offset by one line - mov #640/16,r1 - shll2 r1 - shll2 r1 - shld r5,r1 - mov.l r1,@(0x14,r0) - ! Set screen size and modulo, and interlace flag - mov.l r4,@-r15 - mov #1,r2 - shll8 r2 - mov #640/16,r1 - shll2 r1 - shld r5,r1 - mov #2,r5 - tst r5,r4 - bt/s nonlace ! VGA => no interlace - mov #1,r4 - add r1,r4 ! add one line to offset => display every other line - add #0x50,r2 ! enable LACE -nonlace: - shll8 r4 - shll2 r4 - add r3,r4 - add #-1,r4 - shll8 r4 - shll2 r4 - add r1,r4 - add #-1,r4 - mov.l r4,@(0x1c,r0) - mov.l @r15+,r4 - add #0x7c,r0 - mov.l r2,@(0x14,r0) - ! Set vertical pos and border - mov #0x12,r1 - mov r1,r2 - shll16 r1 - or r2,r1 - mov.l r1,@(0x34,r0) - add r3,r1 - mov.l r1,@(0x20,r0) - ! Horizontal pos - mov.w hpos,r1 - mov.l r1,@(0x30,r0) - - ! Select RGB/CVBS - mov.l cvbsbase,r1 - mov r4,r0 - and #3,r0 - !rotr r4 - !bf/s rgbmode - !mov #0,r0 - !mov #3,r0 -!rgbmode: - shll8 r0 - mov.l r0,@r1 - - rts - nop - - .align 4 -videobase: - .long 0xa05f8000 -cvbsbase: - .long 0xa0702c00 -bppshifttab: - .byte 1,1,0,2 -hpos: - .word 0xa4 - - - - ! Check type of A/V cable connected - ! - ! 0 = VGA - ! 1 = --- - ! 2 = RGB - ! 3 = Composite - -_check_cable: - ! set PORT8 and PORT9 to input - mov.l porta,r0 - mov.l pctra_clr,r2 - mov.l @r0,r1 - mov.l pctra_set,r3 - and r2,r1 - or r3,r1 - mov.l r1,@r0 - ! read PORT8 and PORT9 - mov.w @(4,r0),r0 - shlr8 r0 - rts - and #3,r0 - - .align 4 -porta: - .long 0xff80002c -pctra_clr: - .long 0xfff0ffff -pctra_set: - .long 0x000a0000 - - ! Return base address of ROM font ! From 1a58522c6437e36e46876b9ccc351ff10168f7bc Mon Sep 17 00:00:00 2001 From: Andress Barajas Date: Fri, 31 May 2024 12:16:47 -0700 Subject: [PATCH 2/2] Fix compile errors --- example-src/dcload-syscalls.c | 2 +- target-src/dcload/dcload-crt0.s | 1 + target-src/dcload/exception.s | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/example-src/dcload-syscalls.c b/example-src/dcload-syscalls.c index d715f2d..66c85fa 100644 --- a/example-src/dcload-syscalls.c +++ b/example-src/dcload-syscalls.c @@ -17,7 +17,7 @@ int read (int file, void *buf, size_t len) return -1; } -int lseek (int filedes, off_t offset, int dir) +off_t lseek (int filedes, off_t offset, int dir) { if (*DCLOADMAGICADDR == DCLOADMAGICVALUE) return dcloadsyscall(pclseeknr, filedes, offset, dir); diff --git a/target-src/dcload/dcload-crt0.s b/target-src/dcload/dcload-crt0.s index 9b77ad3..4e89880 100644 --- a/target-src/dcload/dcload-crt0.s +++ b/target-src/dcload/dcload-crt0.s @@ -110,6 +110,7 @@ start_l: add #4,r0 cmp/hi r0,r1 ! This was cmp/ge before, which would always write 4 bytes beyond the end... bt start_l +no_bss: mov.l set_fpscr_k, r1 jsr @r1 diff --git a/target-src/dcload/exception.s b/target-src/dcload/exception.s index ddd39db..faccd46 100644 --- a/target-src/dcload/exception.s +++ b/target-src/dcload/exception.s @@ -177,7 +177,7 @@ general_1: mov.l dcloadsyscall_k,r0 mov.l @r0,r0 jsr @r0 - mov #15,r4 ! dcload's exit syscall is syscall 15 + mov #15,r4 ! dcload's exit syscall is syscall 15 ! Let's add a few seconds delay here to be able to read the screen ! ...or at least take a photo of it mov #0,r0