From 47b48f51b352d8763a5606cb61153d3e8067ad34 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 16 Jul 2024 18:04:30 -0400 Subject: [PATCH] riven_hgr: work on bootloader --- games/riven_hgr/Makefile | 2 +- games/riven_hgr/proboothd.s | 267 ++++++++++++++++++++++++++++++++ utils/prodos-utils/prodos_raw.c | 146 +++++++++++++++++ 3 files changed, 414 insertions(+), 1 deletion(-) create mode 100644 games/riven_hgr/proboothd.s create mode 100644 utils/prodos-utils/prodos_raw.c diff --git a/games/riven_hgr/Makefile b/games/riven_hgr/Makefile index ec36b4ca..287ba97d 100644 --- a/games/riven_hgr/Makefile +++ b/games/riven_hgr/Makefile @@ -382,7 +382,7 @@ submit: riven_disk00.dsk riven_disk01.dsk \ riven_hgr.2mg: PROBOOTHD disk01_files/LEVEL_ARRIVAL $(PRODOSDIR)/mkprodosfs riven_hgr.2mg -n Riven -b 65535 -2 - $(PRODOS_RAW) riven_hgr.2mg 0 0 PROBOOTHD + $(PRODOS_RAW) riven_hgr.2mg 0 PROBOOTHD 0 0 ### diff --git a/games/riven_hgr/proboothd.s b/games/riven_hgr/proboothd.s new file mode 100644 index 00000000..beea7fc0 --- /dev/null +++ b/games/riven_hgr/proboothd.s @@ -0,0 +1,267 @@ +;license:BSD-3-Clause + +; based on minimal open/read binary file in ProDOS filesystem +; from 4cade +; +;copyright (c) Peter Ferrie 2016-2019 + +.include "hardware.inc" + +PROBOOTENTRY = $2000 + +; zpage usage, arbitrary selection except for the "ProDOS constant" ones + command = $42 ; ProDOS constant + UNIT = $43 ; ProDOS constant + ADRLO = $44 ; ProDOS constant + ADRHI = $45 ; ProDOS constant + BLOKLO = $46 ; ProDOS constant + BLOKHI = $47 ; ProDOS constant + + A2L = $3e + A2H = $3f + sizehi = $53 + + + SCRN2P2 = $f87b ; shifts top nibble to bottom + + dirbuf = $1e00 ;for size-optimisation + +; start of boot sector, presumably how many sectors to load +; 512 bytes on prodos/hard-disk(???) + +.byte 1 + +proboot_start: + txa + pha ; save slot for later + + ; init. is all this necessary? + ; originally "4cade.init.machine.a" + + cld ; clear direction flag + sta $C082 ; read rom / no write (language card) + sta PRIMARYCHARSET ; turn off mouse text + sta EIGHTYCOLOFF ; disable 80-col mode + sta CLR80COL + sta READMAINMEM ; make sure not using aux mem + sta WRITEMAINMEM + sta SETSTDZP + + ; more init + ; originally "4cade.init.screen.a" + + ; initializes and clears screen using ROM routines + + jsr INIT_TEXT ; setup text mode + jsr HOME ; clear screen + jsr SETNORM ; normal text + jsr SETKBD ; keyboard input + jsr SETVID ; video output + + ; set up disk stuff? + + pla ; restore slot + sta UNIT ; save for later + + tax + ; X = boot slot x16 + + ; Y = 0 + ; 4cade calls a print-title routine here that exits with Y=0 + + ldy #0 + + ; set up ProDOS shim + + ; from IIgs smartport firmware manual + + ; prodos entry point is $CX00+($CXFF) + ; so if slot 7, $C700 + value in $C7ff (say, A) so $C70A + ; smartport entry point is $CX00+(CXFF)+3 + + +setup_loop: + txa + jsr SCRN2P2 ; shift top nibble of A to bottom + and #7 + ora #$c0 + sta $be30, Y ; ???? + sta slot_smc+2 + sta entry_smc+2 ; set up smartport/prodos entry point + +slot_smc: + lda $cfff + sta entry_smc+1 ; set up rest of smartport/prodos entry + + lda fakeMLI_e-$100, Y + sta $be00+fakeMLI_e-fakeMLI, Y + iny + bne setup_loop ; ????? + + ; Y is 0 here +; ldy #0 + sty ADRLO + stx $bf30 ; ????? + sty $200 ; ????? + +opendir: + ; read volume directory key block + ldx #2 + + ; include volume directory header in count + +firstent: + lda #>dirbuf ; load volume block to ADDRH/L (dirbuf/$1e00) + sta ADRHI + sta A2H + jsr seekread + + + lda #4 ; start at filename offset + sta A2L +nextent: + ldy #0 + + ; match name lengths before attempting to match names + ; first byte, bottom nibble is length + + lda (A2L), Y + and #$0f + tax + inx + +try_again: + cmp filename, Y + beq filename_char_match + + ; move to next directory in this block +not_found: + clc + lda A2L + adc #$27 + sta A2L + bcc no_cross_page + + ; there can be only one page crossed, + ; so we can increment instead of adc + + inc A2H +no_cross_page: + cmp #$ff ; 4+($27*$0d) + bne nextent + + ; read next directory block when we reach the end of this block + + ldx dirbuf+2 + ldy dirbuf+3 + bcs firstent + +filename_char_match: + iny ; point to next char + lda (A2L), Y ; grab value + dex ; countdown filename length + bne try_again ; if not full match, keep going + + + stx $ff ; set address $FF in zero page to zero? + + ; bytes $11 and $12 in the file entry are the "key pointer" + + ldy #$11 + lda (A2L), Y + tax + iny + lda (A2L), Y + tay + + + ; seedling files = less than 512 bytes, contents are simply key block + ; storage type is $1 + ; sapling files = 512B - 128k + ; key block has low bytes of addrss in 0..255 and high in 256..512 + ; storage type is $2 + ; tree files = 128k - 16M + + + ; read the 512-byte block at key pointer into memory + ; will only work for a "sapling" file? + +readfile: + jsr seekread + + inc ADRHI ; point destination past it (so at $2000) + inc ADRHI + + ; fetch contents of file? + ; just keep reading 512-byte blocks until done? + ; this means file will be at $2000? + +blockind: + ldy $ff ; use $ff as block index? + inc $ff ; + + ldx dirbuf, Y ; low byte of block# + lda dirbuf+256, Y ; high byte of block# + tay + + bne readfile ; if high byte!=0, read another block + + txa ; if high byte=0 and low_byte=0, done + bne readfile + +readdone: + jmp PROBOOTENTRY ; would be $2000 if sapling + + ;================================ + ; seek read + ;================================ + ; Y:X = block number to load (???) + ; A = page to load to? + +seekread: + stx BLOKLO + sty BLOKHI + lda #1 + sta command + lda ADRHI + pha +entry_smc: + jsr $d1d1 + pla + sta ADRHI + rts + +fakeMLI: + bne retcall +readblk: + dey + dey + sty ADRHI + tay + jsr $bf00+seekread-fakeMLI +retcall: + pla + tax + inx + inx + inx + txa + pha +;-: + rts +fakeMLI_e: + + +filename: + ; expects PASCAL-string filename + ; first byte size (max 15) + .byte 7,"SEASONS" + +;.if (* > $9f7) +; .error "Bootloader is too large" +;.endif + +;*=$9f8 +;!byte $D3,$C1,$CE,$A0,$C9,$CE,$C3,$AE +; S A N I N C . +; diff --git a/utils/prodos-utils/prodos_raw.c b/utils/prodos-utils/prodos_raw.c new file mode 100644 index 00000000..5e4e6c88 --- /dev/null +++ b/utils/prodos-utils/prodos_raw.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include +#include + +#include + +/* usage: dos33_raw track sector file */ +static void usage(char *exe_name) { + printf("Usage:\n"); + printf("\t%s disk_image track sector file start count [max_track]\n\n",exe_name); + exit(1); +} + +static int dos33_sector_map[16]={ + 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15 +}; + +static int goto_dos_track_sector(int fd, int track, int sector) { + + int result,translated_sector; + + translated_sector=dos33_sector_map[sector%16]; + + result=lseek(fd,(translated_sector*256)+(track*16*256),SEEK_SET); + +// printf("going to: T=%d S=%d (%d)\n",track,sector,translated_sector); + + return result; +} + +int main(int argc, char **argv) { + + unsigned int track,sector,start,count,total,max_track,filesize; + unsigned int max_sector,check_max=0; + int disk_image_fd; + int file_fd; + unsigned char buffer[256]; + int result,read_result; + struct stat statbuf; + + if (argc<7) { + usage(argv[0]); + } + + track=atoi(argv[2]); + sector=atoi(argv[3]); + start=atoi(argv[5]); + count=atoi(argv[6]); + + if (argc>7) { + max_track=atoi(argv[7]); + check_max=1; + } + + /* check filesize using stat */ + result=stat(argv[4], &statbuf); + if (result<0) { + fprintf(stderr,"Error stating %s: %s\n", + argv[4],strerror(errno)); + exit(1); + } + filesize=statbuf.st_size; + + if (count==0) { + count=(filesize/256); + if ((filesize%256)!=0) count++; + } + + /* sanity check we aren't going off the last track */ + if (check_max) { + max_sector=((track*16)+sector+count); + if (max_sector >= max_track*16) { + fprintf(stderr,"Error, %d exceeds max_sector of %d\n", + max_sector,max_track*16); + exit(1); + } + } + + if (track>34) { + fprintf(stderr,"Warning! Unusual track number %d\n",track); + } + + if (sector>15) { + fprintf(stderr,"Warning! Unusual sector number %d\n",sector); + } + + disk_image_fd=open(argv[1],O_RDWR); + if (disk_image_fd<0) { + fprintf(stderr,"Error opening %s: %s\n", + argv[1],strerror(errno)); + exit(1); + } + + file_fd=open(argv[4],O_RDONLY); + if (file_fd<0) { + fprintf(stderr,"Error opening %s: %s\n", + argv[4],strerror(errno)); + exit(1); + } + + result=lseek(file_fd,(start*256),SEEK_SET); + if (result<0) { + fprintf(stderr,"Error skipping: %s\n",strerror(errno)); + exit(1); + } + + + total=0; + /* write until out of space */ + while(1) { + if (total>=count) break; + + read_result=read(file_fd,buffer,256); + if (read_result<0) break; /* error */ + if (read_result==0) break; /* done */ + + result=goto_dos_track_sector(disk_image_fd,track,sector); + if (result<0) { + fprintf(stderr,"Error seeking: %s\n",strerror(errno)); + exit(1); + } + + result=write(disk_image_fd,buffer,read_result); + if (result<0) { + fprintf(stderr,"Error writing image: %s\n", + strerror(errno)); + break; + } + total++; + sector++; + if (sector==16) { + sector=0; + track++; + } + } + + close(file_fd); + close(disk_image_fd); + + fprintf(stderr,"Wrote %d sectors\n",count); + + return 0; +}