From e779f8a1e4563511bb112aad525f1d7da7b104ee Mon Sep 17 00:00:00 2001 From: David Given Date: Sat, 9 Dec 2017 23:50:17 +0100 Subject: [PATCH] The boot loader now works (probably). --- Kernel/platform-nc200/Makefile | 5 +- Kernel/platform-nc200/autoprg.s | 142 +++++++++++++++++++++++------- Kernel/platform-nc200/bootblock.s | 6 ++ 3 files changed, 117 insertions(+), 36 deletions(-) diff --git a/Kernel/platform-nc200/Makefile b/Kernel/platform-nc200/Makefile index b178d2b2..f0b91c45 100644 --- a/Kernel/platform-nc200/Makefile +++ b/Kernel/platform-nc200/Makefile @@ -3,8 +3,9 @@ bootfloppy.img: bootblock.img autoprg.bin cp bootblock.img bootfloppy.img truncate bootfloppy.img --size 7680 mcopy -i bootfloppy.img autoprg.bin ::auto.prg - mcopy -i bootfloppy.img big ::bank80.img - mcopy -i bootfloppy.img big ::bank81.img + #mcopy -i bootfloppy.img kernel1 ::load4000.80 + #mcopy -i bootfloppy.img kernel2 ::load4000.81 + #echo -n | mcopy -i bootfloppy.img - ::call4000.80 bootblock.img: bootblock.s sdasz80 -fflopzws bootblock.rel bootblock.s diff --git a/Kernel/platform-nc200/autoprg.s b/Kernel/platform-nc200/autoprg.s index 4637848a..5e9d0ffd 100644 --- a/Kernel/platform-nc200/autoprg.s +++ b/Kernel/platform-nc200/autoprg.s @@ -1,5 +1,18 @@ .globl entry +; This is a simple bootstrap loader which uses the Amstrad's built-in software to +; load files off disk. It first searches for LOAD????.?? files, where the first +; field is a hex address and the second is a bank ID, and loads them all. Then it +; searches for a CALL????.?? file, pages in the bank, and calls that address. +; The paged in bank is always at 0x4000. Typically you'll want something like: +; +; LOAD4000.80 +; LOAD4000.81 +; CALL4000.80 +; +; If there are multiple CALL????.?? files, it will pick one at random and ignore +; the rest. + ; Amstrad kernel entrypoints kmreadchar = 0xb9b3 @@ -7,7 +20,10 @@ textout = 0xb81e txtclearwindow = 0xb824 txtoutput = 0xb833 -; Ranger FDD entrypoints +; Ranger FDD entrypoints. I have no idea whether these are consistent between ROM +; versions, if there are different ROM versions, but I've found at least two +; machines with these values. Unfortunately the Ranger software doesn't expose +; things like read_sector via a system call. r_finish = 0xf34b r_set_dta = 0xf391 @@ -30,7 +46,7 @@ update_watchdog_timer = 0xcc78 ; 0x8000-0xbfff: Kernel workspace ; 0xc000-0xffff: Ranger floppy disk routines ; - ; The only bank we can change while still keeping the Amstral kernel running + ; The only bank we can change while still keeping the Amstrad kernel running ; from is the one at 0x4000. So we need to relocate ourself into the transient ; data area at 0xa000 to allow this. This is 4kB wide. @@ -41,11 +57,12 @@ entry: ldir jp start start: + ld (.data.entry_stack), sp call txtclearwindow ld hl, #.str.hello call textout - ld hl, #.str.pattern + ld hl, #.str.load_pattern ld a, #0xff call r_find_first filename_loop: @@ -55,6 +72,7 @@ filename_loop: call textout ld a, #' ' call txtoutput + call parse_filename call load_file call r_find_next @@ -70,30 +88,53 @@ really_failed: call textout pop af call print_hex_i8 - jp press_any_key +press_any_key_and_exit: + call press_any_key +exit: + ld sp, (.data.entry_stack) + ret finished: ld a, (.data.found_a_file) or a - jr z, no_files + jr z, no_bank_files + + ld hl, #.str.call_pattern + ld a, #0xff + call r_find_first + jr c, no_boot_file + call parse_filename + + push af + ld hl, #.str.booting + call textout + pop af + call print_hex_i8 + call r_finish - jp press_any_key -no_files: - ld hl, #.str.nofiles + ld sp, (.data.entry_stack) + ld hl, (.data.destination) + jp (hl) + +no_bank_files: + ld hl, #.str.no_bank_files +textout_and_exit: call textout - jp press_any_key + jr press_any_key_and_exit +no_boot_file: + ld hl, #.str.no_boot_file + jr textout_and_exit nl: ld hl, #.str.nl jp textout +; Assumes that the dta contains a dirent for a file and that .data.destination +; is set correctly; reads it all in. load_file: ld a, #1 ld (.data.found_a_file), a - ld hl, #0x4000 - ld (.data.destination), hl - ld iy, (.data.dta) ld l, 0x1c(iy) ; start cluster in dirent ld h, 0x1d(iy) @@ -117,7 +158,7 @@ cluster_loop: add hl, de ld (.data.destination), hl call read_sector - jr c, really_failed + jp c, really_failed call update_watchdog_timer ld hl, (.data.destination) @@ -133,25 +174,58 @@ cluster_loop: jr nc, cluster_loop jp nl -.data.found_a_file: - .db 0 -.data.destination: - .dw 0 - -.str.hello: - .ascii "Loading..." -.str.nl: - .ascii "\r\n" - .db 0 - -.str.nofiles: - .ascii "No files to load!" - .db 0 - -.str.pattern: - .ascii "BANK??.IMG" - .db 0 +; Assumes that the dta contains the dirent for the current file. +parse_filename: + ld iy, (.data.dta) -.str.error: - .ascii "\r\nError: " - .db 0 \ No newline at end of file + ld d, 6(iy) + ld e, 7(iy) + call parse_hex + ld (.data.destination+0), a + + ld d, 4(iy) + ld e, 5(iy) + call parse_hex + ld (.data.destination+1), a + + ld d, 9(iy) + ld e, 10(iy) + call parse_hex + ld (0xb001), a ; tell the OS that we're changing banks + out (0x11), a ; actually change banks + ret + +; Takes a hex number in D, E and reads it into A. +parse_hex: + ld a,d + call parse_hex_digit + add a,a + add a,a + add a,a + add a,a + ld d,a + ld a,e + call parse_hex_digit + or d + ret + +parse_hex_digit: + sub a, #'0' + cp #10 + ret c + sub a, #'A'-'0'-10 + ret + +.data.entry_stack: .dw 0 +.data.found_a_file: .db 0 +.data.destination: .dw 0 + +.str.hello: .ascii "Loading..." ; falls through +.str.nl: .asciz "\r\n" + +.str.no_bank_files: .asciz "No files to load!" +.str.no_boot_file: .asciz "No boot configuration!" +.str.load_pattern: .asciz "LOAD????.??" +.str.call_pattern: .asciz "CALL????.??" +.str.error: .asciz "\r\nError: " +.str.booting: .asciz "Starting bank " diff --git a/Kernel/platform-nc200/bootblock.s b/Kernel/platform-nc200/bootblock.s index a4ff529a..3afe3fba 100644 --- a/Kernel/platform-nc200/bootblock.s +++ b/Kernel/platform-nc200/bootblock.s @@ -43,6 +43,12 @@ .org 0x01fe .db 0x55, 0xaa +; We mark bad blocks in the cluster map because the Amstrad floppy disk routines +; have a bug in it which means that in bootable disks it's unable to read clusters +; which span tracks --- it applies the reserved sector offset *after* it calculates +; track/head/sector, which means that it thinks that some clusters occupy sectors +; 9 and 10 of a track, which doesn't work. We mark these as being inaccessible. +; ; The FAT entries for two cylinders (four physical tracks). ; That's 18*4 = 72 sectors = 0x12 clusters. But we are offset left ; by one sector, so clusters 0 and 5 span two tracks (and are inaccessible). -- 2.34.1