]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/cmd_loadcpm3.c
Get common_base from cpm3.sys file. Update default environment (BOOTCMD)
[z180-stamp.git] / avr / cmd_loadcpm3.c
CommitLineData
c0abd68b
L
1/*
2 * (C) Copyright 2015 Leo C. <erbl259-lmu@yahoo.de>
3 *
b51d2360
L
4 * SPDX-License-Identifier: GPL-2.0
5 */
6
7/*
8 * See CP/M 3 System Manual, Appendix D: CPM3.SYS File Format
c0abd68b
L
9 */
10
11#include "common.h"
12#include <stdlib.h>
13#include <ctype.h>
14#include <string.h>
15#include <stdbool.h>
16
17#include "command.h"
18#include "env.h"
19#include "ff.h"
20#include "con-utils.h"
21#include "z80-if.h"
22#include "debug.h"
23
24
25#define RS 128 /* CP/M record size */
26
b51d2360
L
27#define FSIZE_t DWORD
28
c0abd68b
L
29/*
30 * Load Routine
31 *
32 * Input: addr = Page Address of load top
33 * len = Length in pages of module to read
34 *
35 */
057817cb 36int load(FIL *File, uint32_t addr, uint8_t len)
c0abd68b
L
37{
38 uint8_t buffer[RS];
39 unsigned int br; /* bytes read */
40 int res;
41
42 len *= 2; /* length in records of module */
43 //debug("## load: addr: 0x%.4X, records: 0x%.4X, (%u)\n", addr, len, len);
44
45 for (; len; len--) {
46 addr -= RS;
47 res = f_read(File, buffer, RS, &br);
48 if (res || br != RS) {
49 return 1;
50 }
51
52 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
53 my_puts_P(PSTR("Bus timeout\n"));
54 return 2;
55 }
56 z80_write_block(buffer, addr, RS);
57 z80_bus_cmd(Release);
58 //debug("## written: 0x%.4X\n", addr);
59 }
60
61 return 0;
62}
63
ad9bc17c 64#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
c0abd68b
L
65
66command_ret_t do_loadcpm3(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
67{
68 uint16_t mem_top;
69 uint8_t res_len;
70 uint16_t bank_top;
71 uint8_t bank_len;
057817cb 72 uint16_t osentry_addr = 0;
b51d2360
L
73 uint32_t common_base = 0;
74 uint32_t banked_base;
c0abd68b 75 char *fname;
c0abd68b 76 FIL File;
057817cb 77 char default_fname[] = CONFIG_CPM3_SYSFILE;
c0abd68b
L
78 unsigned int br; /* bytes read */
79 uint8_t buffer[RS];
80 int res;
81
82 (void) cmdtp; (void) flag;
83
84
b51d2360
L
85 //common_base = getenv_ulong(PSTR(ENV_CPM3_COMMON_BASE), 16,
86 // CONFIG_CPM3_COMMON_BASE);
057817cb
L
87 banked_base = getenv_ulong(PSTR(ENV_CPM3_BANKED_BASE), 16,
88 CONFIG_CPM3_BANKED_BASE);
c0abd68b 89
057817cb
L
90 if (argc > 3)
91 banked_base = strtoul(argv[3], NULL, 16);
92 if (argc > 2)
98aac4d0 93 common_base = strtoul(argv[2], NULL, 16);
c0abd68b 94
1b77fa4e 95 fname = getenv_char(PSTR(ENV_CPM3_SYSFILE));
98aac4d0
L
96 if (argc > 1) {
97 fname = argv[1];
c0abd68b 98 }
c0abd68b
L
99 if (fname == NULL || *fname == '\0')
100 fname = default_fname;
101
bbd45c46 102 res = f_open(&File, fname, FA_READ );
c0abd68b
L
103 if (res) {
104 printf_P(PSTR("Error: failed to open '%s'\n"), fname);
c0abd68b
L
105 return CMD_RET_FAILURE;
106 }
107
108 printf_P(PSTR("Loading: '%s'...\n"), fname);
109
110 /* read the load record */
111 res = f_read(&File, buffer, RS, &br);
112 if (res || br != RS)
113 goto out;
114
115 mem_top = buffer[0] << 8;
116 res_len = buffer[1];
117 bank_top = buffer[2] << 8;
118 bank_len = buffer[3];
057817cb 119 osentry_addr = buffer[4] + (buffer[5] << 8);
c0abd68b
L
120
121 /* read display info */
122 res = f_read(&File, buffer, RS, &br);
123 if (res || br != RS)
124 goto out;
125
126 /* print the info */
127 buffer[RS-1] = '$';
128 uint8_t *p = memchr(buffer, '$', RS);
129 *p = '\0';
130 my_puts((char *)buffer);
131
b51d2360
L
132 if (common_base == 0) {
133 /* read common base
134 * http://www.seasip.info/Cpm/scb.html
135 */
136 FSIZE_t common_base_ofs = ((res_len - 6) << 8) + 2*RS + RS-7;
137 FSIZE_t cur_pos = f_tell(&File);
138 if ((res = f_lseek(&File, common_base_ofs)) ||
139 (res = f_read(&File, buffer, 2, &br)) ||
140 (br != 2) ||
141 (res = f_lseek(&File, cur_pos)))
142 goto out;
143 common_base = (uint16_t) buffer[0] + (buffer[1] << 8);
144 setenv_hex(PSTR(ENV_CPM3_COMMON_BASE), common_base);
145 }
c0abd68b
L
146 /* Main System Load */
147
148 /* Load Common Portion of System */
057817cb 149 if ((res = load(&File, common_base + mem_top, res_len)) != 0)
c0abd68b
L
150 goto out;
151
152 /* Load Banked Portion of System */
057817cb 153 res = load(&File, banked_base + bank_top, bank_len);
c0abd68b
L
154
155out:
156 f_close(&File);
c0abd68b
L
157
158 if (res) {
159 printf_P(PSTR("Error: failed to read '%s'\n"), fname);
160 return CMD_RET_FAILURE;
161 } else {
057817cb
L
162 if (res_len != 0) {
163 if (osentry_addr + common_base > 0xffff) {
164 z80_bus_cmd(Request);
165 if (z80_read(osentry_addr + common_base) == 0xc3) {
166 osentry_addr = z80_read(osentry_addr+common_base+1) +
167 (z80_read(osentry_addr + common_base+2) << 8);
168 }
169 z80_bus_cmd(Release);
170 if (banked_base + osentry_addr > 0xffff)
171 osentry_addr = 0;
172 }
173 setenv_hex(PSTR(ENV_STARTADDRESS), osentry_addr);
174 }
c0abd68b
L
175 printf_P(PSTR("Loaded: Resident: "));
176 if (res_len != 0)
057817cb
L
177 printf_P(PSTR("0x%.5lX-0x%.5lX, "),
178 (common_base + mem_top) - res_len*256,
179 (common_base + mem_top) - 1);
c0abd68b
L
180 else
181 printf_P(PSTR(" - "));
182 printf_P(PSTR("Banked: "));
183 if (bank_len != 0)
057817cb
L
184 printf_P(PSTR("0x%.5lX-0x%.5lX\n"),
185 (banked_base + bank_top) - bank_len*256,
186 (banked_base + bank_top) - 1);
c0abd68b
L
187 else
188 printf_P(PSTR(" - \n"));
189
190 return CMD_RET_SUCCESS;
191 }
192}