/* * (C) Copyright 2015,2016 Leo C. * * SPDX-License-Identifier: GPL-2.0 */ /* * See CP/M 3 System Manual, Appendix D: CPM3.SYS File Format */ #include "common.h" #include #include #include #include "command.h" #include "env.h" #include "ff.h" #include "eval_arg.h" #include "con-utils.h" #include "z80-if.h" #include "debug.h" #define RS 128 /* CP/M record size */ #define FSIZE_t DWORD /* * Load Routine * * Input: addr = Page Address of load top * len = Length in pages of module to read * */ int load(FIL *File, uint32_t addr, uint8_t len) { uint8_t buffer[RS]; unsigned int br; /* bytes read */ int res; len *= 2; /* length in records of module */ //debug("## load: addr: 0x%.4X, records: 0x%.4X, (%u)\n", addr, len, len); for (; len; len--) { addr -= RS; res = f_read(File, buffer, RS, &br); if (res || br != RS) { return 1; } if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) { my_puts_P(PSTR("Bus timeout\n")); return 2; } z80_write_block(buffer, addr, RS); z80_bus_cmd(Release); //debug("## written: 0x%.4X\n", addr); } return 0; } #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" command_ret_t do_loadcpm3(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { uint16_t mem_top; uint8_t res_len; uint16_t bank_top; uint8_t bank_len; uint16_t osentry_addr = 0; uint32_t common_base = 0; uint32_t banked_base; char *fname; FIL File; char default_fname[] = CONFIG_CPM3_SYSFILE; unsigned int br; /* bytes read */ uint8_t buffer[RS]; int res; (void) cmdtp; (void) flag; //common_base = getenv_ulong(PSTR(ENV_CPM3_COMMON_BASE), 16, // CONFIG_CPM3_COMMON_BASE); banked_base = getenv_ulong(PSTR(ENV_CPM3_BANKED_BASE), 16, CONFIG_CPM3_BANKED_BASE); if (argc > 3) banked_base = eval_arg(argv[3], NULL); if (argc > 2) common_base = eval_arg(argv[2], NULL); fname = getenv_str(PSTR(ENV_CPM3_SYSFILE)); if (argc > 1) { fname = argv[1]; } if (fname == NULL || *fname == '\0') fname = default_fname; res = f_open(&File, fname, FA_READ ); if (res) { printf_P(PSTR("Error: failed to open '%s'\n"), fname); return CMD_RET_FAILURE; } printf_P(PSTR("Loading: '%s'...\n"), fname); /* read the load record */ res = f_read(&File, buffer, RS, &br); if (res || br != RS) goto out; mem_top = buffer[0] << 8; res_len = buffer[1]; bank_top = buffer[2] << 8; bank_len = buffer[3]; osentry_addr = buffer[4] + (buffer[5] << 8); /* read display info */ res = f_read(&File, buffer, RS, &br); if (res || br != RS) goto out; /* print the info */ buffer[RS-1] = '$'; uint8_t *p = memchr(buffer, '$', RS); *p = '\0'; my_puts((char *)buffer); if (common_base == 0) { /* read common base * http://www.seasip.info/Cpm/scb.html */ FSIZE_t common_base_ofs = ((res_len - 6) << 8) + 2*RS + RS-7; FSIZE_t cur_pos = f_tell(&File); if ((res = f_lseek(&File, common_base_ofs)) || (res = f_read(&File, buffer, 2, &br)) || (br != 2) || (res = f_lseek(&File, cur_pos))) goto out; common_base = (uint16_t) buffer[0] + (buffer[1] << 8); setenv_hex(PSTR(ENV_CPM3_COMMON_BASE), common_base); } setenv_hex(PSTR(ENV_CPM3_SCB), mem_top - ((res_len - (6 - 1)) << 8) + common_base); /* Main System Load */ /* Load Common Portion of System */ if ((res = load(&File, common_base + mem_top, res_len)) != 0) goto out; /* Load Banked Portion of System */ res = load(&File, banked_base + bank_top, bank_len); out: f_close(&File); if (res) { printf_P(PSTR("Error: failed to read '%s'\n"), fname); return CMD_RET_FAILURE; } else { if (res_len != 0) { if (osentry_addr + common_base > 0xffff) { z80_bus_cmd(Request); if (z80_read(osentry_addr + common_base) == 0xc3) { osentry_addr = z80_read(osentry_addr+common_base+1) + (z80_read(osentry_addr + common_base+2) << 8); } z80_bus_cmd(Release); if (banked_base + osentry_addr > 0xffff) osentry_addr = 0; } setenv_hex(PSTR(ENV_STARTADDRESS), osentry_addr); } printf_P(PSTR("Loaded: Resident: ")); if (res_len != 0) printf_P(PSTR("0x%.5lX-0x%.5lX, "), (common_base + mem_top) - res_len*256, (common_base + mem_top) - 1); else printf_P(PSTR(" - ")); printf_P(PSTR("Banked: ")); if (bank_len != 0) printf_P(PSTR("0x%.5lX-0x%.5lX\n"), (banked_base + bank_top) - bank_len*256, (banked_base + bank_top) - 1); else printf_P(PSTR(" - \n")); return CMD_RET_SUCCESS; } }