]> cloudbase.mooo.com Git - z180-stamp.git/blobdiff - avr/cmd_loadcpm3.c
rewrite of cmd_cpu/do_cpu_freq
[z180-stamp.git] / avr / cmd_loadcpm3.c
index a2436f23b0490d5f3f839329f0747c9a13ec0eb2..ee336dabd365752346c1ebc42554b7796d43da2f 100644 (file)
@@ -1,25 +1,39 @@
 /*
- * (C) Copyright 2015 Leo C. <erbl259-lmu@yahoo.de>
+ * (C) Copyright 2015,2016,2018 Leo C. <erbl259-lmu@yahoo.de>
  *
- * SPDX-License-Identifier:    GPL-2.0+
+ * SPDX-License-Identifier:    GPL-2.0
  */
 
-#include "common.h"
-#include <stdlib.h>
+/*
+ * See CP/M 3 System Manual, Appendix D: CPM3.SYS File Format
+ */
+
+#include "cmd_loadcpm3.h"
 #include <ctype.h>
-#include <string.h>
-#include <stdbool.h>
 
-#include "command.h"
 #include "env.h"
 #include "ff.h"
+#include "eval_arg.h"
 #include "con-utils.h"
 #include "z80-if.h"
 #include "debug.h"
+#include "errnum.h"
 
 
 #define RS             128             /* CP/M record size */
 
+#define FSIZE_t DWORD
+
+static FRESULT read_record(FIL *fp, uint8_t *buffer)
+{
+       unsigned int br;                /* bytes read */
+
+       FRESULT res = f_read(fp, buffer, RS, &br);
+       if (br != RS)
+               return EEOF;
+       return res;
+}
+
 /*
  *     Load Routine
  *
  *                     len  = Length in pages of module to read
  *
  */
-int load(FIL *File, uint32_t addr, uint8_t len)
+ERRNUM 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;
-               }
+               FRESULT res = read_record(File, buffer);
+               if (res)
+                       return res;
 
-               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
-                       my_puts_P(PSTR("Bus timeout\n"));
-                       return 2;
-               }
+               if (!(z80_bus_cmd(Request) & ZST_ACQUIRED))
+                       return EBUSTO;
                z80_write_block(buffer, addr, RS);
                z80_bus_cmd(Release);
                //debug("## written: 0x%.4X\n", addr);
        }
 
-       return 0;
+       return ESUCCESS;
 }
 
 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
 
-command_ret_t do_loadcpm3(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+command_ret_t do_loadcpm3(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, 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, banked_base;
+       uint32_t common_base = 0;
+       uint32_t banked_base;
        char *fname;
        FIL File;
-       /* TODO: put CONFIG_CPM3_SYSFILE in flash */
-       char default_fname[] = CONFIG_CPM3_SYSFILE;
-       unsigned int br;                                        /* bytes read */
+       char default_fname[strlen_P(PSTR(CONFIG_CPM3_SYSFILE)) + 1];
        uint8_t buffer[RS];
-       int res;
-
-       (void) cmdtp; (void) flag;
+       FRESULT res;
 
 
-       common_base = getenv_ulong(PSTR(ENV_CPM3_COMMON_BASE), 16,
-                                               CONFIG_CPM3_COMMON_BASE);
+       //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 = strtoul(argv[3], NULL, 16);
+               banked_base = eval_arg(argv[3], NULL);
        if (argc > 2)
-               common_base = strtoul(argv[2], NULL, 16);
+               common_base = eval_arg(argv[2], NULL);
 
-       fname = getenv_char(PSTR(ENV_CPM3_SYSFILE));
+       fname = getenv_str(PSTR(ENV_CPM3_SYSFILE));
+       if (fname == NULL || *fname == '\0') {
+               strcpy_P(default_fname, PSTR(CONFIG_CPM3_SYSFILE));
+               fname = default_fname;
+       }
        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;
-       }
+       if (res)
+               goto out;
 
        printf_P(PSTR("Loading: '%s'...\n"), fname);
 
        /* read the load record */
-       res = f_read(&File, buffer, RS, &br);
-       if (res || br != RS)
+       res = read_record(&File, buffer);
+       if (res)
                goto out;
 
        mem_top = buffer[0] << 8;
@@ -113,8 +119,8 @@ command_ret_t do_loadcpm3(cmd_tbl_t *cmdtp, int flag, int argc, char * const arg
        osentry_addr = buffer[4] + (buffer[5] << 8);
 
        /* read display info */
-       res = f_read(&File, buffer, RS, &br);
-       if (res || br != RS)
+       res = read_record(&File, buffer);
+       if (res)
                goto out;
 
        /* print the info */
@@ -123,6 +129,27 @@ command_ret_t do_loadcpm3(cmd_tbl_t *cmdtp, int flag, int argc, char * const arg
        *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);
+               unsigned int br;                                        /* bytes read */
+               if ((res = f_lseek(&File, common_base_ofs)) ||
+                               (res = f_read(&File, buffer, 2, &br)) ||
+                               (res = f_lseek(&File, cur_pos)))
+                       goto out;
+               if (br != 2) {
+                       res = EEOF;
+                       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 */
@@ -135,38 +162,36 @@ command_ret_t do_loadcpm3(cmd_tbl_t *cmdtp, int flag, int argc, char * const arg
 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;
+       if (res)
+               cmd_error(CMD_RET_FAILURE, res, PSTR("%s"), fname);
+
+       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);
                        }
-                       setenv_hex(PSTR(ENV_STARTADDRESS), osentry_addr);
+                       z80_bus_cmd(Release);
+                       if (banked_base + osentry_addr > 0xffff)
+                               osentry_addr = 0;
                }
-               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;
+               setenv_hex(PSTR(ENV_STARTADDRESS), osentry_addr);
        }
+       printf_P(PSTR("Loaded: Resident: "));
+       if (res_len != 0)
+               printf_P(PSTR("%.5lX-%.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("%.5lX-%.5lX\n"),
+               (banked_base + bank_top) - bank_len*256,
+               (banked_base + bank_top) - 1);
+       else
+               printf_P(PSTR(" -  \n"));
+
+       return CMD_RET_SUCCESS;
 }