]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/cmd_loadcpm3.c
cmd_attach.c, cmd_boot.c, cmd_loadcpm3.c: use cmd_error()
[z180-stamp.git] / avr / cmd_loadcpm3.c
1 /*
2 * (C) Copyright 2015,2016,2018 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0
5 */
6
7 /*
8 * See CP/M 3 System Manual, Appendix D: CPM3.SYS File Format
9 */
10
11 #include "cmd_loadcpm3.h"
12 #include <ctype.h>
13
14 #include "env.h"
15 #include "ff.h"
16 #include "eval_arg.h"
17 #include "con-utils.h"
18 #include "z80-if.h"
19 #include "debug.h"
20 #include "errnum.h"
21
22
23 #define RS 128 /* CP/M record size */
24
25 #define FSIZE_t DWORD
26
27 static FRESULT read_record(FIL *fp, uint8_t *buffer)
28 {
29 unsigned int br; /* bytes read */
30
31 FRESULT res = f_read(fp, buffer, RS, &br);
32 if (br != RS)
33 return EEOF;
34 return res;
35 }
36
37 /*
38 * Load Routine
39 *
40 * Input: addr = Page Address of load top
41 * len = Length in pages of module to read
42 *
43 */
44 ERRNUM load(FIL *File, uint32_t addr, uint8_t len)
45 {
46 uint8_t buffer[RS];
47
48 len *= 2; /* length in records of module */
49 //debug("## load: addr: 0x%.4X, records: 0x%.4X, (%u)\n", addr, len, len);
50
51 for (; len; len--) {
52 addr -= RS;
53 FRESULT res = read_record(File, buffer);
54 if (res)
55 return res;
56
57 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED))
58 return EBUSTO;
59 z80_write_block(buffer, addr, RS);
60 z80_bus_cmd(Release);
61 //debug("## written: 0x%.4X\n", addr);
62 }
63
64 return ESUCCESS;
65 }
66
67 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
68
69 command_ret_t do_loadcpm3(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
70 {
71 uint16_t mem_top;
72 uint8_t res_len;
73 uint16_t bank_top;
74 uint8_t bank_len;
75 uint16_t osentry_addr = 0;
76 uint32_t common_base = 0;
77 uint32_t banked_base;
78 char *fname;
79 FIL File;
80 char default_fname[strlen_P(PSTR(CONFIG_CPM3_SYSFILE)) + 1];
81 uint8_t buffer[RS];
82 FRESULT res;
83
84
85 //common_base = getenv_ulong(PSTR(ENV_CPM3_COMMON_BASE), 16,
86 // CONFIG_CPM3_COMMON_BASE);
87 banked_base = getenv_ulong(PSTR(ENV_CPM3_BANKED_BASE), 16,
88 CONFIG_CPM3_BANKED_BASE);
89
90 if (argc > 3)
91 banked_base = eval_arg(argv[3], NULL);
92 if (argc > 2)
93 common_base = eval_arg(argv[2], NULL);
94
95 fname = getenv_str(PSTR(ENV_CPM3_SYSFILE));
96 if (fname == NULL || *fname == '\0') {
97 strcpy_P(default_fname, PSTR(CONFIG_CPM3_SYSFILE));
98 fname = default_fname;
99 }
100 if (argc > 1) {
101 fname = argv[1];
102 }
103
104 res = f_open(&File, fname, FA_READ );
105 if (res)
106 goto out;
107
108 printf_P(PSTR("Loading: '%s'...\n"), fname);
109
110 /* read the load record */
111 res = read_record(&File, buffer);
112 if (res)
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];
119 osentry_addr = buffer[4] + (buffer[5] << 8);
120
121 /* read display info */
122 res = read_record(&File, buffer);
123 if (res)
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
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 unsigned int br; /* bytes read */
139 if ((res = f_lseek(&File, common_base_ofs)) ||
140 (res = f_read(&File, buffer, 2, &br)) ||
141 (res = f_lseek(&File, cur_pos)))
142 goto out;
143 if (br != 2) {
144 res = EEOF;
145 goto out;
146 }
147 common_base = (uint16_t) buffer[0] + (buffer[1] << 8);
148 setenv_hex(PSTR(ENV_CPM3_COMMON_BASE), common_base);
149 }
150
151 setenv_hex(PSTR(ENV_CPM3_SCB), mem_top - ((res_len - (6 - 1)) << 8) + common_base);
152
153 /* Main System Load */
154
155 /* Load Common Portion of System */
156 if ((res = load(&File, common_base + mem_top, res_len)) != 0)
157 goto out;
158
159 /* Load Banked Portion of System */
160 res = load(&File, banked_base + bank_top, bank_len);
161
162 out:
163 f_close(&File);
164
165 if (res)
166 cmd_error(CMD_RET_FAILURE, res, PSTR("%s"), fname);
167
168 if (res_len != 0) {
169 if (osentry_addr + common_base > 0xffff) {
170 z80_bus_cmd(Request);
171 if (z80_read(osentry_addr + common_base) == 0xc3) {
172 osentry_addr = z80_read(osentry_addr+common_base+1) +
173 (z80_read(osentry_addr + common_base+2) << 8);
174 }
175 z80_bus_cmd(Release);
176 if (banked_base + osentry_addr > 0xffff)
177 osentry_addr = 0;
178 }
179 setenv_hex(PSTR(ENV_STARTADDRESS), osentry_addr);
180 }
181 printf_P(PSTR("Loaded: Resident: "));
182 if (res_len != 0)
183 printf_P(PSTR("%.5lX-%.5lX, "),
184 (common_base + mem_top) - res_len*256,
185 (common_base + mem_top) - 1);
186 else
187 printf_P(PSTR(" - "));
188 printf_P(PSTR("Banked: "));
189 if (bank_len != 0)
190 printf_P(PSTR("%.5lX-%.5lX\n"),
191 (banked_base + bank_top) - bank_len*256,
192 (banked_base + bank_top) - 1);
193 else
194 printf_P(PSTR(" - \n"));
195
196 return CMD_RET_SUCCESS;
197 }