From: Leo C Date: Thu, 9 Jun 2016 00:20:50 +0000 (+0200) Subject: New command: cfboot - boot from cf card. X-Git-Tag: hexrel-6.8~5 X-Git-Url: http://cloudbase.mooo.com/gitweb/z180-stamp.git/commitdiff_plain/a2907f2e2b2725679d6b3b8d3231f3d94c325014 New command: cfboot - boot from cf card. --- diff --git a/avr/Tupfile b/avr/Tupfile index 9f95376..0eb910a 100644 --- a/avr/Tupfile +++ b/avr/Tupfile @@ -22,7 +22,7 @@ SRC += ../time/system_time.c ../time/set_system_time.c ASRC += ../time/system_tick.S -SRC_Z = ../z180/hdrom.c +SRC_Z = ../z180/hdrom.c ../z180/cfboot.c #TARGETS = $(PROG).elf @@ -110,8 +110,8 @@ LDFLAGS += -Wl,--cref !SIZE = |> ^ SIZE^ $(SIZE) %f |> : foreach $(ASRC) |> !as |> {objs} -: foreach $(SRC) | ../z180/hdrom.h |> !cc |> {objs} -: $(SRC_Z) |> !cc -D'const=const __flash' |> {objs} +: foreach $(SRC) | ../z180/hdrom.h ../z180/cfboot.h |> !cc |> {objs} +: foreach $(SRC_Z) |> !cc -D'const=const __flash' |> {objs} : {objs} |> !LINK |> $(PROG).elf : $(PROG).elf |> !OBJCOPY |> %B.hex diff --git a/avr/cmd_boot.c b/avr/cmd_boot.c index 73f2cf3..b00d062 100644 --- a/avr/cmd_boot.c +++ b/avr/cmd_boot.c @@ -20,6 +20,7 @@ #include "cli.h" /* run_command() */ #include "env.h" #include "con-utils.h" +#include "getopt-min.h" #include "z80-if.h" #include "z180-serv.h" /* restart_z180_serv() */ #include "debug.h" @@ -27,28 +28,34 @@ /* ugly hack to get Z180 loadfile into flash memory */ #define const const FLASH #include "../z180/hdrom.h" +#include "../z180/cfboot.h" #undef const -static void z80_load_mem(void) +static void z80_load_mem(int_fast8_t verbosity, + const FLASH unsigned char data[], + const FLASH unsigned long *sections, + const FLASH unsigned long address[], + const FLASH unsigned long length_of_sections[]) { - unsigned sec = 0; - uint32_t sec_base = hdrom_start; - - printf_P(PSTR("Loading Z180 memory... \n")); - - while (sec < hdrom_sections) { - printf_P(PSTR(" From: 0x%.5lX to: 0x%.5lX (%5li bytes)\n"), - hdrom_address[sec], - hdrom_address[sec]+hdrom_length_of_sections[sec] - 1, - hdrom_length_of_sections[sec]); - - z80_write_block_P((const FLASH unsigned char *) &hdrom[sec_base], /* src */ - hdrom_address[sec], /* dest */ - hdrom_length_of_sections[sec]); /* len */ - sec_base+=hdrom_length_of_sections[sec]; - sec++; + uint32_t sec_base = 0; + + if (verbosity > 1) + printf_P(PSTR("Loading Z180 memory... \n")); + + for (unsigned sec = 0; sec < *sections; sec++) { + if (verbosity > 0) { + printf_P(PSTR(" From: 0x%.5lX to: 0x%.5lX (%5li bytes)\n"), + address[sec], + address[sec]+length_of_sections[sec] - 1, + length_of_sections[sec]); + } + + z80_write_block_P((const FLASH unsigned char *) &data[sec_base], /* src */ + address[sec], /* dest */ + length_of_sections[sec]); /* len */ + sec_base += length_of_sections[sec]; } } @@ -64,13 +71,206 @@ command_ret_t do_loadf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] my_puts_P(PSTR("Bus timeout\n")); return CMD_RET_FAILURE; } - z80_load_mem(); + z80_load_mem(2, hdrom, + &hdrom_sections, + hdrom_address, + hdrom_length_of_sections); + z80_bus_cmd(Release); return CMD_RET_SUCCESS; } +void print_vars(char *title) +{ + uint8_t buf[5]; + zstate_t state = z80_bus_state(); + + if((state & ZST_ACQUIRED) == 0) + z80_bus_cmd(Request); + + z80_read_block(buf, 9, sizeof buf); + + if((state & ZST_ACQUIRED) == 0) + z80_bus_cmd(Release); + + printf_P(PSTR("%s: stage: %d, flag: 0x%.02x, result: %d, IDE stat/error: 0x%.02x/0x%.02x\n"), + title, buf[0], buf[1], buf[2], buf[3], buf[4]); +} + + +/* + * bootcf [options] + * + * -a address (100h) + * -s start sector (0) + * -c sector count (7) + * -i Partition id (52) + * -n load only + * -t timeout (10000) + * -v verbose + */ + +command_ret_t do_bootcf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct { + uint8_t jr[2]; + uint16_t loadaddr; + uint8_t sec_start; + uint8_t sec_cnt; + uint8_t part_id; + uint16_t timeout; + uint8_t stop_stage; + } boot_param; + + struct { + uint8_t stop_stage; + uint8_t done; + uint8_t result; + uint8_t ide_stat; + uint8_t ide_error; + } boot_res; + + int_fast8_t verbosity = 0; + uint8_t stages; + uint32_t val; + + (void) cmdtp; (void) flag; + + /* get default values */ + memcpy_P(&boot_param, cfboot, sizeof boot_param); + stages = boot_param.stop_stage; + + /* reset getopt() */ + optind = 0; + + int opt; + while ((opt = getopt(argc, argv, PSTR("vna:s:c:t:i:"))) != -1) { + switch (opt) { + case 'v': + verbosity++; + break; + case 'n': + if (boot_param.stop_stage > 0) + boot_param.stop_stage--; + break; + case 'a': + val = strtoul(optarg, NULL, 16); + if (val < 0x100 || val > 0xFE00) { + printf_P(PSTR("Address out of range: 0x%.4lX\n"), val); + return CMD_RET_FAILURE; + } + boot_param.loadaddr = val; + break; + case 's': + val = strtoul(optarg, NULL, 16); + if (val > 255) { + printf_P(PSTR("Start sector out of range: 0x%lX\n"), val); + return CMD_RET_FAILURE; + } + boot_param.sec_start = val; + break; + case 'c': + val = strtoul(optarg, NULL, 16); + if (val > 127) { + printf_P(PSTR("Sector count out of range: 0x%lX\n"), val); + return CMD_RET_FAILURE; + } + boot_param.sec_cnt = val; + break; + case 't': + val = strtoul(optarg, NULL, 10); + if (val < 0x1 || val > 0xFFFF) { + printf_P(PSTR("Timeout value out of range: 0x%lX\n"), val); + return CMD_RET_FAILURE; + } + boot_param.loadaddr = val; + break; + case 'i': + val = strtoul(optarg, NULL, 16); + if (val < 0x01 || val > 0xFF) { + printf_P(PSTR("Partition id out of range: 0x%lX\n"), val); + return CMD_RET_FAILURE; + } + boot_param.part_id = val; + break; + default: /* '?' */ + return CMD_RET_USAGE; + } + } + + /* remaining arguments */ + argc -= optind; + if (argc) { + my_puts_P(PSTR("Argument error!\n")); + return CMD_RET_USAGE; + } + + if ((val = (uint32_t) boot_param.loadaddr + boot_param.sec_cnt * 512) >= 0xFF00) { + printf_P(PSTR("Top address out of range: 0x%.4lX\n"), val); + return CMD_RET_FAILURE; + } + + + + if (z80_bus_state() & ZST_RUNNING) { + my_puts_P(PSTR("CPU is allready running!\n")); + return CMD_RET_FAILURE; + } + if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) { + my_puts_P(PSTR("Bus timeout\n")); + return CMD_RET_FAILURE; + } + z80_load_mem(verbosity, cfboot, + &cfboot_sections, + cfboot_address, + cfboot_length_of_sections); + + z80_write_block((const uint8_t *) &boot_param, + cfboot_address[0], sizeof boot_param); + z80_bus_cmd(Release); + + if (boot_param.stop_stage == 0) { + printf_P(PSTR("Bootloader loaded at: 0x%.4X\n"), (uint16_t) cfboot_address[0]); + } else { + printf_P(PSTR("Executing %d of %d Bootloader stages...\n"), + boot_param.stop_stage, stages); + + z80_bus_cmd(Run); + z80_bus_cmd(Release); + + clear_ctrlc(); /* forget any previous Control C */ + for (boot_res.done = 0; boot_res.done != 0xFF;) { + _delay_ms(8); + /* check for ctrl-c to abort... */ + if (had_ctrlc() || ctrlc()) { + break; + } + z80_bus_cmd(Request); + z80_read_block((uint8_t *) &boot_res, + cfboot_address[0]+sizeof boot_param - 1, sizeof boot_res); + z80_bus_cmd(Release); + } + + if (boot_res.done != 0xFF) { + z80_bus_cmd(Reset); + my_puts_P(PSTR("Abort\n")); + } else { + if (boot_param.stop_stage == stages) { + my_puts_P(PSTR("Booting...\n")); + } else { + z80_bus_cmd(Reset); + printf_P(PSTR("Bootloader stopped at stage %d, result: %d, IDE stat/error: 0x%.02x/0x%.02x\n"), + boot_param.stop_stage - boot_res.stop_stage, + boot_res.result, boot_res.ide_stat, boot_res.ide_error); + } + } + } + + return CMD_RET_SUCCESS; +} + command_ret_t do_busreq_pulse(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { uint16_t count=1; diff --git a/avr/command_tbl.c b/avr/command_tbl.c index 944c1c4..7ebc008 100644 --- a/avr/command_tbl.c +++ b/avr/command_tbl.c @@ -16,6 +16,7 @@ extern command_ret_t do_env_default(cmd_tbl_t *, int, int, char * const []); extern command_ret_t do_env_set(cmd_tbl_t *, int, int, char * const []); extern command_ret_t do_env_save(cmd_tbl_t *, int, int, char * const []); extern command_ret_t do_loadf(cmd_tbl_t *, int, int, char * const []); +extern command_ret_t do_bootcf(cmd_tbl_t *, int, int, char * const []); extern command_ret_t do_loadcpm3(cmd_tbl_t *, int, int, char * const []); extern command_ret_t do_loadihex(cmd_tbl_t *, int, int, char * const []); #if defined(CONFIG_CMD_LOADB) @@ -156,6 +157,27 @@ CMD_TBL_ITEM( "load srec_cat prepared image from controller flash", "" ), +CMD_TBL_ITEM( + bootcf, CONFIG_SYS_MAXARGS, 0, do_bootcf, + "boot from cf card", + "[options]\n" + " Load a number of sectors from the first CP/M partition and jump to\n" + " the load address.\n" + " -a ADDRESS\n" + " Load and start address (default 100 hex)\n" + " -s NUM\n" + " First sector of partition to load (0..255, default 0)\n" + " -c NUM\n" + " Number of sectors to load (1..127, default 7)\n" + " -i NUM\n" + " Partition type to look for (default 52 hex)\n" + " -n\n" + " Load only, do not execute\n" + " -t NUM\n" + " Timeout for IDE commands (1..65535, default 10000)\n" + " -v verbose\n" + " TODO: be verbose" +), CMD_TBL_ITEM( loadcpm3, 3, 0, do_loadcpm3, "load CPM3.SYS file", @@ -364,7 +386,7 @@ CMD_TBL_ITEM( detach, 2, 1, do_attach, "detach file from CP/M drive", "dsk]\n" - " - same as attach -d dsk" + " - alias for 'attach -d dsk'" ), CMD_TBL_ITEM( diff --git a/z180/Makefile b/z180/Makefile index c6727b9..159371f 100644 --- a/z180/Makefile +++ b/z180/Makefile @@ -89,7 +89,7 @@ hdrom.hex : $(OBJ) @#$(cpm-link) ld80 -o $@ -ms $(@:.hex=.map) -P $(LN_PROG) -D $(LN_DATA) $^ -%.rel %lst: %.180 +%.rel %.lst: %.180 @$(cpm-asm) hdrom.map: hdrom.hex diff --git a/z180/Tupfile b/z180/Tupfile index 50ede98..c7d79fb 100644 --- a/z180/Tupfile +++ b/z180/Tupfile @@ -1,6 +1,7 @@ include_rules PROG = hdrom +CFBOOT = cfboot SRC = init.180 SRC += ddtz.180 @@ -48,6 +49,9 @@ rm -f ${OUTPUT}; exit ${ERROR} \ : $(PROG).hex |> srec_cat -o %o -c_array %B -C_COMpressed -include %f -Intel |> $(PROG).c | $(PROG).h +: $(CFBOOT).180 |> $(AS) -%B/HFS |> %B.hex | %B.lst +: $(CFBOOT).hex |> srec_cat -o %o -c_array %B -C_COMpressed -include %f -Intel |> $(CFBOOT).c | $(CFBOOT).h + #COMMAND="$(AS) -%B/$(AS_OPT)"; \ diff --git a/z180/cfboot.180 b/z180/cfboot.180 new file mode 100644 index 0000000..d8c39fd --- /dev/null +++ b/z180/cfboot.180 @@ -0,0 +1,351 @@ + TITLE 'CF cold boot loader' + + ; Port Address Equates + + include config.inc + include z180reg.inc + + ; IDE Task File Register Definitions + +IDEDat equ IDEBASE+0 ; Data Register +IDEErr equ IDEBASE+1 ; Error Register +IDEFeat equ IDEBASE+1 ; Feature Register +IDESCnt equ IDEBASE+2 ; Sector Count +IDESNum equ IDEBASE+3 ; Sector Number +IDECLo equ IDEBASE+4 ; Cylinder Low +IDECHi equ IDEBASE+5 ; Cylinder High +IDESDH equ IDEBASE+6 ; Drive and Head +IDECmd equ IDEBASE+7 ; Command / Status + + ; IDE Hard disk commands: + +CmdNOP equ 00h ; NOP Command +CmdHome equ 10h ; Recalibrate +CmdRd equ 20h ; Read Sector +CmdWr equ 30h ; Write Sector +CmdId equ 0ECh ; Read ID +CmdSF equ 0EFh ; Set Feature + + ; Partition Table Structures + +PTYPE equ 4 +PSTART equ 8 +PSIZE equ 12 + + ; Partition table id + ; (see http://www.win.tue.nl/~aeb/partitions/partition_types-1.html) + +PARTID1_FAT16 equ 00EH +PARTID2_FAT16 equ 006H +PARTID_CPM equ 052H + + +DEBUG equ false ; not used +DO_WAIT_NBSY equ false +RUN_TPA equ false + + if RUN_TPA +base equ 0100h + else +base equ 0 + endif + +;------------------------------------------------------------------------------- + + aseg + + org base + + jr start + +para: equ $ +loadaddr: dw base+100h +sec_start: db 0 +sec_cnt: db 7 +part_id: db PARTID_CPM +timeout: dw 10000 +stop_stage: db number_of_stages +done: db 0 +result: db 0 +ide_result: db 0,0 + +o_part_id equ part_id - para +o_stop_stage equ stop_stage - para +o_done equ done - para +o_result equ result - para + +;------------------------------------------------------------------------------- + +start: + ld sp,stack + pop ix + pop de +loop: + pop hl + push de + push hl + exx + ld hl,(loadaddr) + ret +continue: + exx + ld (ix+o_result),a + or a + jr nz,stop + dec (ix+o_stop_stage) + jr nz,loop +stop: + in a,(Idecmd) ;2 + ld l,a ;1 + in a,(IdeErr) ;2 + ld h,a ;1 + ld (ide_result),hl ;3 9 + dec (ix+o_done) + halt + +;------------------------------------------------------------------------------- + +chk_to: + xor a ; +to_l: + dec a + ex (sp),hl + ex (sp),hl + jr nz,to_l ; + dec hl ; 4 + ld a,h ; 4 + or l ; 4 + ret nz ; 10/5 + ccf ; 3 + ret ; 9 + + if base = 0 + if 044h-$ > 0 + rept 044h-$ + db 0 + endm + endif + endif + +part_start: +; dw 0 +; dw 0 ; part_start is 4 byte long, but stack gets free +stack: + dw para + dw continue +stages: + if DO_WAIT_NBSY + dw s_wait_not_bsy + endif + dw s_wait_rdy + dw s_check_io + dw s_set_xfermode8 + dw s_read_parttbl + dw s_check_signature + dw s_find_partition + dw s_read_sectors + dw s_go +number_of_stages equ ($-stages)/2 + + if DO_WAIT_NBSY +;------------------------------------------------------------------------------- +; Wait while device is busy with time out +; return: +; a = 0 if ok +; a = ff in timeout +; destroys hl + +s_wait_not_bsy: + ld hl,(timeout) +wnb_l: + in a,(IdeCmd) + rla + jr nc,wnb_e + call chk_to + jr nc,wnb_l +wnb_e: + sbc a,a + ret + endif + +;------------------------------------------------------------------------------- +; Wait for ready signal with time out +; return: +; a = 0 if ok +; a = ff in timeout +; destroys hl + +s_wait_rdy: +wait_rdy_to: + ld hl,(timeout) +wrdy_l: + in a,(IdeCmd) + xor 01000000b + and 11000000b ; clears carry + jr z,wrdy_e + call chk_to + jr nc,wrdy_l +wrdy_e: + sbc a,a + ret + +;------------------------------------------------------------------------------- + +s_check_io: + ld a,0E0h ; unit 0, lba mode + out (IdeSDH),a ; + + xor a ; execute NOP command + call do_ide_cmd ; should return error + ret c + xor 1 + ret nz + ld a,CmdHome ; execute RECALIBRATE command + jr do_ide_cmd + +;------------------------------------------------------------------------------- + +s_set_xfermode8: + ld a,1 ; Enable 8-bit data transfer. + out (IDEFeat),a + ld a,CmdSF ; Set feature command + +; fall thru +; jr do_ide_cmd + +;------------------------------------------------------------------------------- + +do_ide_cmd: + out (IdeCmd),a ; + call wait_rdy_to + ret c + in a,(IdeCmd) + and 10001001b ; + ret + +;------------------------------------------------------------------------------- + +s_check_signature: +; ld hl,(loadaddr) + inc h ; Point to last byte of MBR + inc h + dec hl + ld a,0aah + cp (hl) ; Test, if it has a valid MBR + ret nz + dec hl + cpl ; a=055h + sub (hl) ; + ret ; should be 0 + +;------------------------------------------------------------------------------- +; Read partition table (lbr) + +s_read_parttbl: +; ld hl,(loadaddr) + ld bc,1*256 + 0 ; sector 0 (lba) + ld e,c + ld d,c + jr read_sectors + +;------------------------------------------------------------------------------- +; Find CP/M paartition +; Look for first CP/M partition +; and save partition offset + +s_find_partition: +; ld hl,(loadaddr) + ld de,512-2-64+PTYPE ; Point to partition type of first first partition table entry + add hl,de + ld de,16 + ld b,4 ; Max # of partition table entries +ploop: + ld a,(ix+o_part_id) + sub (HL) ; Test for CP/M Partition + jr nz,pnext + ld bc,4 + add hl,bc ; Point to partition start (lba) + ld de,part_start + ldir + ret ;a=0 +pnext: + add hl,de + djnz ploop + ret + + +;------------------------------------------------------------------------------- +; Read sec_count sectors, beginning at part_start+sec_start + +s_read_sectors: +; ld hl,(loadaddr) + push hl + ld bc,(sec_start) ;b=sec_count, c=sec_start + ld e,c + ld d,0 + ld hl,(part_start) ;add partition offset to sector number + add hl,de + ld a,(part_start+2) + adc a,d ;d=0 + ld c,a + ex de,hl + pop hl + +; fall thru + +;------------------------------------------------------------------------------- +; Read a number of sectors +; hl: memory address +; cde: sector number (24 bit) +; b: sector count + +read_sectors: + ld a,e ; lba 0..7 + out (IdeSNum),a + ld a,d ; lba 0..7 + out (IdeClo),a + ld a,c ; lba 0..7 + out (IdeCHi),a + ld a,b ; number of sectors to read + out (IdeSCnt),a ; set sector count + + ld a,CmdRd + out (IdeCmd),a ; command: read sector data + ld d,b + ld bc,IdeDat ; I/O address +wdrq: + in a,(IdeCmd) ; wait for DRQ to become active + bit 3,a + jr z,wdrq + inir ; read 512 data bytes (2 x 256) + inir +wnb: ; wait while busy + in a,(IdeCmd) ; + rlca + jr c,wnb + rrca ; restore status + bit 0,a + jr nz,err_out + dec d + jr nz,wdrq +err_out: + and 10001001b ; Busy, DRQ, or Error? + ret ; return 0, if everything is ok + +;------------------------------------------------------------------------------- + +s_go: +; ld hl,(loadaddr) + dec (ix+o_done) + jp (hl) + + +;------------------------------------------------------------------------------- + if base = 0 + if $ > 100h + .printx Error: Program to large to fit in page 0! + db "Stop + endif + endif + + end diff --git a/z180/config.inc b/z180/config.inc index 4421478..bea6e05 100644 --- a/z180/config.inc +++ b/z180/config.inc @@ -3,8 +3,6 @@ FALSE equ 0 TRUE equ NOT FALSE -DEBUG equ true - banked equ true ;----------------------------------------------------- @@ -159,6 +157,8 @@ AVRINT5 equ 4Fh AVRINT6 equ 5Fh ;PMSG equ 80h +IDEBASE equ 60h + ;----------------------------------------------------- ; Definition of (logical) top 2 memory pages