|
|
1.1 root 1: /*
1.1.1.2 root 2: Hatari - bios.c
3:
4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
1.1 root 6:
7: Bios Handler (Trap #13)
8:
1.1.1.7 root 9: We intercept some Bios calls for debugging
1.1 root 10: */
1.1.1.8 root 11: const char Bios__fileid[] = "Hatari bios.c : " __DATE__ " " __TIME__;
1.1 root 12:
13: #include "main.h"
1.1.1.2 root 14: #include "configuration.h"
1.1 root 15: #include "floppy.h"
1.1.1.3 root 16: #include "log.h"
1.1 root 17: #include "m68000.h"
18: #include "printer.h"
19: #include "rs232.h"
20: #include "stMemory.h"
1.1.1.2 root 21: #include "bios.h"
1.1 root 22:
23:
24: /*-----------------------------------------------------------------------*/
1.1.1.6 root 25: /**
1.1.1.11 root 26: * Convert given BIOS CON: device character output to ASCII.
27: * Accepts one character at the time, parses VT52 escape codes
28: * and maps Atari characters to their closest ASCII equivalents.
29: *
30: * On host, TOS cursor forwards movement is done with spaces,
31: * backwards movement is delayed until next non-white character
32: * at which point output switches to next line. Other VT52
33: * escape sequences than cursor movement are ignored.
34: */
35: static void Bios_VT52(Uint8 value)
36: {
37:
38: static const Uint8 map_0_31[32] = {
39: '.', '.', '.', '.', '.', '.', '.', '.', /* 0x00 */
40: /* white space */
41: '\b','\t','\n','.','.','\r', '.', '.', /* 0x08 */
42: /* LED numbers */
43: '0', '1', '2', '3', '4', '5', '6', '7', /* 0x10 */
44: '8', '9', '.', '.', '.', '.', '.', '.' /* 0x18 */
45: };
46: static const Uint8 map_128_255[128] = {
47: /* accented characters */
48: 'C', 'U', 'e', 'a', 'a', 'a', 'a', 'c', /* 0x80 */
49: 'e', 'e', 'e', 'i', 'i', 'i', 'A', 'A', /* 0x88 */
50: 'E', 'a', 'A', 'o', 'o', 'o', 'u', 'u', /* 0x90 */
51: 'y', 'o', 'u', 'c', '.', 'Y', 'B', 'f', /* 0x98 */
52: 'a', 'i', 'o', 'u', 'n', 'N', 'a', 'o', /* 0xA0 */
53: '?', '.', '.', '.', '.', 'i', '<', '>', /* 0xA8 */
54: 'a', 'o', 'O', 'o', 'o', 'O', 'A', 'A', /* 0xB0 */
55: 'O', '"','\'', '.', '.', 'C', 'R', '.', /* 0xB8 */
56: 'j', 'J', '.', '.', '.', '.', '.', '.', /* 0xC0 */
57: '.', '.', '.', '.', '.', '.', '.', '.', /* 0xC8 */
58: '.', '.', '.', '.', '.', '.', '.', '.', /* 0xD0 */
59: '.', '.', '.', '.', '.', '.', '^', '.', /* 0xD8 */
60: '.', '.', '.', '.', '.', '.', '.', '.', /* 0xE0 */
61: '.', '.', '.', '.', '.', '.', '.', '.', /* 0xE8 */
62: '.', '.', '.', '.', '.', '.', '.', '.', /* 0xF0 */
63: '.', '.', '.', '.', '.', '.', '.', '.' /* 0xF8 */
64: };
65:
66: /* state machine to handle/ignore VT52 escape sequence */
67: static int escape_index;
68: static int escape_target;
69: static int hpos_host, hpos_tos;
70: static bool need_nl;
71: static enum {
72: ESCAPE_NONE, ESCAPE_POSITION
73: } escape_type;
74:
75: if (escape_target) {
76: if (++escape_index == 1) {
1.1.1.12! root 77: /* VT52 escape sequences */
1.1.1.11 root 78: switch(value) {
1.1.1.12! root 79: case 'E': /* clear screen+home -> newline */
! 80: fputs("\n", stderr);
! 81: hpos_host = 0;
! 82: break;
! 83: /* sequences with arguments */
1.1.1.11 root 84: case 'b': /* foreground color */
85: case 'c': /* background color */
86: escape_target = 2;
87: return;
88: case 'Y': /* cursor position */
89: escape_type = ESCAPE_POSITION;
90: escape_target = 3;
91: return;
92: }
93: } else if (escape_index < escape_target) {
94: return;
95: }
96: if (escape_type == ESCAPE_POSITION) {
97: /* last item gives horizontal position */
98: hpos_tos = value - ' ';
99: if (hpos_tos > 79) {
100: hpos_tos = 79;
101: } else if (hpos_tos < 0) {
102: hpos_tos = 0;
103: }
104: if (hpos_tos > hpos_host) {
105: fprintf(stderr, "%*s", hpos_tos - hpos_host, "");
106: hpos_host = hpos_tos;
107: } else if (hpos_tos < hpos_host) {
108: need_nl = true;
109: }
110: }
111: /* escape sequence end */
112: escape_target = 0;
113: return;
114: }
115: if (value == 27) {
116: /* escape sequence start */
117: escape_type = ESCAPE_NONE;
118: escape_target = 1;
119: escape_index = 0;
120: return;
121: }
122:
123: /* do newline & indent for backwards movement only when necessary */
124: if (need_nl) {
125: /* TOS cursor horizontal movement until host output */
126: switch (value) {
127: case ' ':
128: hpos_tos++;
129: return;
130: case '\b':
131: hpos_tos--;
132: return;
133: case '\t':
134: hpos_tos = (hpos_tos + 8) & 0xfff0;
135: return;
136: case '\r':
137: case '\n':
138: hpos_tos = 0;
139: break;
140: }
141: fputs("\n", stderr);
142: if (hpos_tos > 0 && hpos_tos < 80) {
143: fprintf(stderr, "%*s", hpos_tos, "");
144: hpos_host = hpos_tos;
145: } else {
146: hpos_host = 0;
147: }
148: need_nl = false;
149: }
150:
151: /* host cursor horizontal movement */
152: switch (value) {
153: case '\b':
154: hpos_host--;
155: break;
156: case '\t':
157: hpos_host = (hpos_host + 8) & 0xfff0;
158: break;
159: case '\r':
160: case '\n':
161: hpos_host = 0;
162: break;
163: default:
164: hpos_host++;
165: break;
166: }
167:
168: /* map normal characters to host console */
169: if (value < 32) {
170: fputc(map_0_31[value], stderr);
171: } else if (value > 127) {
172: fputc(map_128_255[value-128], stderr);
173: } else {
174: fputc(value, stderr);
175: }
176: }
177:
178:
179: /*-----------------------------------------------------------------------*/
180: /**
1.1.1.6 root 181: * BIOS Write character to device
182: * Call 3
183: */
1.1.1.12! root 184: static void Bios_Bconout(Uint32 Params)
1.1 root 185: {
1.1.1.3 root 186: Uint16 Dev;
1.1.1.11 root 187: Uint8 Char;
1.1 root 188:
1.1.1.12! root 189: Dev = STMemory_ReadWord(Params);
! 190: Char = STMemory_ReadWord(Params+SIZE_WORD);
1.1.1.2 root 191:
1.1.1.12! root 192: LOG_TRACE(TRACE_OS_BIOS, "BIOS 0x03 Bconout(%i, 0x%02hhX)\n", Dev, Char);
1.1 root 193:
1.1.1.11 root 194: if (Dev == 2) {
195: Bios_VT52(Char);
196: }
1.1 root 197: }
198:
1.1.1.2 root 199:
1.1 root 200: /*-----------------------------------------------------------------------*/
1.1.1.6 root 201: /**
202: * BIOS Read/Write disk sector
203: * Call 4
204: */
1.1.1.12! root 205: static void Bios_RWabs(Uint32 Params)
1.1 root 206: {
1.1.1.3 root 207: Uint32 pBuffer;
208: Uint16 RWFlag, Number, RecNo, Dev;
209:
210: /* Read details from stack */
1.1.1.12! root 211: RWFlag = STMemory_ReadWord(Params);
! 212: pBuffer = STMemory_ReadLong(Params+SIZE_WORD);
! 213: Number = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG);
! 214: RecNo = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG+SIZE_WORD);
! 215: Dev = STMemory_ReadWord(Params+SIZE_WORD+SIZE_LONG+SIZE_WORD+SIZE_WORD);
1.1 root 216:
1.1.1.12! root 217: LOG_TRACE(TRACE_OS_BIOS, "BIOS 0x04 Rwabs(%d,0x%lX,%d,%d,%i)\n",
! 218: RWFlag, STRAM_ADDR(pBuffer), Number, RecNo, Dev);
1.1 root 219: }
220:
1.1.1.2 root 221:
1.1 root 222: /*-----------------------------------------------------------------------*/
1.1.1.2 root 223:
1.1.1.12! root 224: #if ENABLE_TRACING
1.1.1.6 root 225: /**
1.1.1.12! root 226: * Map BIOS call opcode to BIOS function name
1.1.1.10 root 227: */
1.1.1.12! root 228: static const char* Bios_Call2Name(Uint16 opcode)
1.1.1.10 root 229: {
230: /* GCC uses substrings from above trace statements
231: * where they match, so having them again here
232: * wastes only a pointer & simplifies things
233: */
234: static const char* names[] = {
235: "Getmpb", "Bconstat","Bconin", "Bconout",
236: "Rwabs", "Setexc", "Tickcal","Getbpb",
237: "Bcostat","Mediach", "Drvmap", "Kbshift"
238: };
1.1.1.12! root 239: if (opcode < ARRAYSIZE(names) && names[opcode]) {
! 240: return names[opcode];
1.1.1.10 root 241: }
1.1.1.12! root 242: return "???";
1.1.1.10 root 243: }
244:
1.1.1.12! root 245: void Bios_Info(Uint32 dummy)
! 246: {
! 247: Uint16 opcode;
! 248: for (opcode = 0; opcode <= 0xB; ) {
! 249: fprintf(stderr, "%02x %-9s", opcode,
! 250: Bios_Call2Name(opcode));
! 251: if (++opcode % 6 == 0) {
! 252: fputs("\n", stderr);
! 253: }
! 254: }
! 255: }
! 256: #else /* !ENABLE_TRACING */
! 257: void Bios_Info(Uint32 bShowOpcodes)
! 258: {
! 259: fputs("Hatari isn't configured with ENABLE_TRACING\n", stderr);
! 260: }
! 261: #endif /* !ENABLE_TRACING */
! 262:
1.1.1.10 root 263:
264: /*-----------------------------------------------------------------------*/
265: /**
266: * Check Bios call and see if we need to re-direct to our own routines.
267: * Return true if we've handled the exception, else return false to let
268: * TOS attempt it
1.1.1.6 root 269: */
1.1.1.7 root 270: bool Bios(void)
1.1 root 271: {
1.1.1.3 root 272: Uint32 Params;
273: Uint16 BiosCall;
1.1 root 274:
1.1.1.3 root 275: /* Get call */
276: Params = Regs[REG_A7];
277: BiosCall = STMemory_ReadWord(Params);
1.1.1.12! root 278: Params += SIZE_WORD;
1.1.1.3 root 279:
280: /* Intercept? */
281: switch(BiosCall)
282: {
1.1.1.12! root 283: case 0x3:
! 284: Bios_Bconout(Params);
! 285: break;
! 286: case 0x4:
! 287: Bios_RWabs(Params);
! 288: break;
! 289:
! 290: case 0x0:
! 291: LOG_TRACE(TRACE_OS_BIOS, "BIOS 0x00 Getmpb(0x%X)\n",
! 292: STMemory_ReadLong(Params));
! 293: break;
! 294:
! 295: case 0x5:
! 296: LOG_TRACE(TRACE_OS_BIOS, "BIOS 0x05 Setexc(0x%hX, 0x%X)\n",
! 297: STMemory_ReadWord(Params),
! 298: STMemory_ReadLong(Params)+SIZE_WORD);
! 299: break;
! 300:
! 301: case 0x1:
! 302: case 0x2:
! 303: case 0x7:
! 304: case 0x8:
! 305: case 0x9:
! 306: case 0xB:
! 307: /* commands taking a single word */
! 308: LOG_TRACE(TRACE_OS_BIOS, "BIOS 0x%02hX %s(0x%hX)\n",
! 309: BiosCall, Bios_Call2Name(BiosCall),
! 310: STMemory_ReadWord(Params));
! 311: break;
! 312:
! 313: case 0x6:
! 314: case 0xA:
! 315: /* commands taking no args */
! 316: LOG_TRACE(TRACE_OS_BIOS, "BIOS 0x%02hX %s()\n",
! 317: BiosCall, Bios_Call2Name(BiosCall));
! 318: break;
! 319:
! 320: default:
! 321: Log_Printf(LOG_WARN, "Unknown BIOS call 0x%x!\n", BiosCall);
! 322: break;
1.1.1.3 root 323: }
1.1.1.12! root 324: return false;
1.1 root 325: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.