fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/dos/dos.c *
7 * Created: 2012-12-30 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2012-2017 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include "main.h"
24#include "dos.h"
25#include "dosmem.h"
26#include "int.h"
27
28#include <cpu/e8086/e8086.h>
29
30#include <ctype.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34
35
36#define DEBUG_MEM 0
37
38
39static
40unsigned char sim_get_mem8 (void *ext, unsigned long addr)
41{
42 dos_t *sim = ext;
43
44#if DEBUG_MEM
45 if (addr < 0x60) {
46 fprintf (stderr, "get 8: %04lX\n", addr);
47 }
48#endif
49
50 if (addr < sim->mem_cnt) {
51 return (sim->mem[addr]);
52 }
53
54 return (0);
55}
56
57static
58unsigned short sim_get_mem16 (void *ext, unsigned long addr)
59{
60 unsigned short val;
61 dos_t *sim = ext;
62
63#if DEBUG_MEM
64 if (addr < 0x60) {
65 fprintf (stderr, "get 16: %04lX\n", addr);
66 }
67#endif
68
69 if ((addr + 1) < sim->mem_cnt) {
70 return (((unsigned) sim->mem[addr + 1] << 8) | sim->mem[addr]);
71 }
72
73 val = (sim_get_mem8 (sim, addr + 1) << 8) | sim_get_mem8 (sim, addr);
74
75 return (val);
76}
77
78static
79void sim_set_mem8 (void *ext, unsigned long addr, unsigned char val)
80{
81 dos_t *sim = ext;
82
83#if DEBUG_MEM
84 if (addr < 0x60) {
85 fprintf (stderr, "set 8: %04lX\n", addr);
86 }
87#endif
88
89 if (addr < sim->mem_cnt) {
90 sim->mem[addr] = val;
91 }
92}
93
94static
95void sim_set_mem16 (void *ext, unsigned long addr, unsigned short val)
96{
97 dos_t *sim = ext;
98
99#if DEBUG_MEM
100 if (addr < 0x60) {
101 fprintf (stderr, "set 16: %04lX\n", addr);
102 }
103#endif
104
105 if (addr < sim->mem_cnt) {
106 sim->mem[addr] = val & 0xff;
107 }
108
109 if ((addr + 1) < sim->mem_cnt) {
110 sim->mem[addr + 1] = (val >> 8) & 0xff;
111 }
112}
113
114static
115unsigned char sim_get_port8 (void *ext, unsigned long addr)
116{
117 if (addr == 0x21) {
118 return (0);
119 }
120
121 fprintf (stderr, "unknown port8 read: %04lX\n", addr);
122 exit (1);
123
124 return (0);
125}
126
127static
128unsigned short sim_get_port16 (void *ext, unsigned long addr)
129{
130 fprintf (stderr, "unknown port16 read: %04lX\n", addr);
131 exit (1);
132
133 return (0);
134}
135
136static
137void sim_set_port8 (void *ext, unsigned long addr, unsigned char val)
138{
139 fprintf (stderr, "unknown port8 write: %04lX <- %02X\n", addr, val);
140 exit (1);
141}
142
143static
144void sim_set_port16 (void *ext, unsigned long addr, unsigned short val)
145{
146 fprintf (stderr, "unknown port16 write: %04lX <- %04X\n", addr, val);
147 exit (1);
148}
149
150unsigned char sim_get_uint8 (dos_t *sim, unsigned short seg, unsigned short ofs)
151{
152 unsigned long addr;
153
154 addr = ((unsigned long) seg << 4) + ofs;
155
156 return (sim_get_mem8 (sim, addr));
157}
158
159unsigned short sim_get_uint16 (dos_t *sim, unsigned short seg, unsigned short ofs)
160{
161 unsigned long addr;
162
163 addr = ((unsigned long) seg << 4) + ofs;
164
165 return (sim_get_mem16 (sim, addr));
166}
167
168void sim_set_uint8 (dos_t *sim, unsigned short seg, unsigned short ofs, unsigned char val)
169{
170 unsigned long addr;
171
172 addr = ((unsigned long) seg << 4) + ofs;
173
174 sim_set_mem8 (sim, addr, val);
175}
176
177void sim_set_uint16 (dos_t *sim, unsigned short seg, unsigned short ofs, unsigned short val)
178{
179 unsigned long addr;
180
181 addr = ((unsigned long) seg << 4) + ofs;
182
183 sim_set_mem16 (sim, addr, val);
184}
185
186int sim_get_asciiz (dos_t *sim, unsigned short seg, unsigned short ofs, char *dst, unsigned max)
187{
188 unsigned i;
189
190 for (i = 0; i < max; i++) {
191 if ((dst[i] = sim_get_uint8 (sim, seg, ofs)) == 0) {
192 break;
193 }
194
195 ofs = (ofs + 1) & 0xffff;
196 }
197
198 if (i >= max) {
199 return (1);
200 }
201
202 dst[i] = 0;
203
204 return (0);
205}
206
207void sim_print_state_cpu (dos_t *sim, FILE *fp)
208{
209 e8086_t *c;
210
211 c = &sim->cpu;
212
213 fprintf (fp,
214 "%04X:%04X AX=%04X BX=%04X CX=%04X DX=%04X "
215 "BP=%04X SI=%04X:%04X DI=%04X:%04X "
216 "SP=%04X:%04X F=%04X",
217 e86_get_cs (c), e86_get_ip (c),
218 e86_get_ax (c), e86_get_bx (c), e86_get_cx (c), e86_get_dx (c),
219 e86_get_bp (c),
220 e86_get_ds (c), e86_get_si (c),
221 e86_get_es (c), e86_get_di (c),
222 e86_get_ss (c), e86_get_sp (c),
223 c->flg
224 );
225
226 fprintf (fp,
227 "[%c%c%c%c%c%c%c%c]",
228 e86_get_if (c) ? 'I' : '-',
229 e86_get_df (c) ? 'D' : '-',
230 e86_get_of (c) ? 'O' : '-',
231 e86_get_sf (c) ? 'S' : '-',
232 e86_get_zf (c) ? 'Z' : '-',
233 e86_get_af (c) ? 'A' : '-',
234 e86_get_pf (c) ? 'P' : '-',
235 e86_get_cf (c) ? 'C' : '-'
236 );
237
238 if (e86_get_halt (c)) {
239 fprintf (fp, " HALT=1");
240 }
241
242 fputc ('\n', fp);
243
244 fflush (fp);
245}
246
247int sim_set_drive (dos_t *sim, unsigned drive, const char *path)
248{
249 unsigned n;
250
251 if (drive >= sim->drive_cnt) {
252 return (1);
253 }
254
255 if (sim->drive[drive] != NULL) {
256 free (sim->drive[drive]);
257 }
258
259 n = strlen (path);
260
261 if ((sim->drive[drive] = malloc (n + 1)) == NULL) {
262 return (1);
263 }
264
265 strcpy (sim->drive[drive], path);
266
267 return (0);
268}
269
270int sim_init_env (dos_t *sim, const char *prog, const unsigned char *env, unsigned envcnt)
271{
272 unsigned i, n;
273 unsigned para;
274
275 n = envcnt + 4 + strlen (prog);
276
277 para = (n + 15) >> 4;
278 para += 1;
279
280 sim->env = sim_mem_alloc (sim, para, para);
281
282 if (sim->env == 0) {
283 return (1);
284 }
285
286 for (i = 0; i < envcnt; i++) {
287 sim_set_uint8 (sim, sim->env, i, env[i]);
288 }
289
290 sim_set_uint16 (sim, sim->env, envcnt + 0, 0);
291 sim_set_uint16 (sim, sim->env, envcnt + 2, 0x0001);
292
293 i = 0;
294 while (prog[i] != 0) {
295 sim_set_uint8 (sim, sim->env, envcnt + 4 + i, prog[i]);
296 i += 1;
297 }
298
299 sim_set_uint8 (sim, sim->env, envcnt + 4 + i, 0);
300
301 return (0);
302}
303
304void sim_init_psp (dos_t *sim)
305{
306 unsigned i;
307
308 for (i = 0; i < 256; i++) {
309 sim_set_uint8 (sim, sim->psp, i, 0);
310 }
311
312 sim_set_uint16 (sim, sim->psp, 0x0000, 0x20cd);
313 sim_set_uint16 (sim, sim->psp, 0x0002, sim->psp + sim_get_uint16 (sim, sim->psp - 1, 3));
314 sim_set_uint16 (sim, sim->psp, 0x002c, sim->env);
315}
316
317int sim_init_args (dos_t *sim, const char **argv)
318{
319 unsigned i;
320 unsigned char c;
321 int ispath;
322 const char *s;
323
324 i = 0;
325
326 while (*argv != NULL) {
327 s = *argv;
328
329 if (i > 0) {
330 sim_set_uint8 (sim, sim->psp, 0x81 + i, ' ');
331
332 if ((i += 1) > 127) {
333 return (1);
334 }
335 }
336
337 ispath = 0;
338
339 while (*s != 0) {
340 while (*s == '%') {
341 s += 1;
342
343 if (*s == '%') {
344 break;
345 }
346
347 ispath = !ispath;
348 }
349
350 c = *s;
351
352 if (ispath) {
353 if (c == '/') {
354 c = '\\';
355 }
356 }
357
358 sim_set_uint8 (sim, sim->psp, 0x81 + i, c);
359
360 s += 1;
361
362 if ((i += 1) > 127) {
363 return (1);
364 }
365 }
366
367 argv += 1;
368 }
369
370 sim_set_uint8 (sim, sim->psp, 0x80, i);
371
372 return (0);
373}
374
375static
376int sim_init_mem (dos_t *sim, unsigned kb)
377{
378 unsigned i;
379
380 sim->mem_cnt = 1024UL * kb;
381 sim->mem = malloc (sim->mem_cnt);
382
383 if (sim->mem == NULL) {
384 return (1);
385 }
386
387 sim->env = 0;
388 sim->psp = 0;
389
390 memset (sim->mem, 0, sim->mem_cnt);
391
392 sim->mem_start = 0x60;
393
394 sim_set_uint8 (sim, sim->mem_start, 0, 0x5a);
395 sim_set_uint16 (sim, sim->mem_start, 1, 0);
396 sim_set_uint16 (sim, sim->mem_start, 3, (sim->mem_cnt >> 4) - sim->mem_start - 1);
397
398 sim->mem[0x510] = 0xcf;
399
400 for (i = 0; i < 256; i++) {
401 sim_set_uint16 (sim, 0, 4 * i + 0, 0x0010);
402 sim_set_uint16 (sim, 0, 4 * i + 2, 0x0050);
403 }
404
405 sim_set_uint16 (sim, 0x40, 0x13, kb);
406
407 return (0);
408}
409
410int sim_init (dos_t *sim, unsigned kb)
411{
412 unsigned i;
413
414 if (sim_init_mem (sim, kb)) {
415 return (1);
416 }
417
418 e86_init (&sim->cpu);
419
420 e86_set_prt (&sim->cpu, sim, sim_get_port8, sim_set_port8, sim_get_port16, sim_set_port16);
421 e86_set_mem (&sim->cpu, sim, sim_get_mem8, sim_set_mem8, sim_get_mem16, sim_set_mem16);
422 e86_set_ram (&sim->cpu, sim->mem, sim->mem_cnt);
423
424 sim->cpu.op_ext = sim;
425 sim->cpu.op_int = (void *) sim_int;
426
427 e86_reset (&sim->cpu);
428
429 sim->cpu.state = 0;
430
431 sim->log_int = 0;
432 sim->cur_drive = 2;
433
434 sim->file_cnt = DOS_FILES_MAX;
435
436 for (i = 0; i < sim->file_cnt; i++) {
437 sim->file[i] = NULL;
438 }
439
440 sim->file[0] = stdin;
441 sim->file[1] = stdout;
442 sim->file[2] = stderr;
443
444 sim->drive_cnt = DOS_DRIVES_MAX;
445
446 for (i = 0; i < sim->drive_cnt; i++) {
447 sim->drive[i] = NULL;
448 }
449
450 sim_set_drive (sim, 2, ".");
451
452 sim->search_dir = NULL;
453 sim->search_dir_name = NULL;
454
455 return (0);
456}
457
458void sim_free (dos_t *sim)
459{
460 free (sim->mem);
461
462 e86_free (&sim->cpu);
463}
464
465void sim_run (dos_t *sim)
466{
467 while (1) {
468 e86_clock (&sim->cpu, 64);
469 }
470}