1 /*
2 Hatari - vdi.c
3
4 This file is distributed under the GNU General Public License, version 2
5 or at your option any later version. Read the file gpl.txt for details.
6
7 VDI (Virtual Device Interface) (Trap #2)
8
9 To get higher resolutions on the Desktop, we intercept the VDI/Line-A calls
10 and set elements in their structures to the higher width/height/cel/planes.
11 We need to intercept the initial Line-A call (which we force into the TOS on
12 boot-up) and also the init calls to the VDI.
13 */
14 const char VDI_fileid[] = "Hatari vdi.c : " __DATE__ " " __TIME__;
15
16 #include "main.h"
17 #include "configuration.h"
18 #include "file.h"
19 #include "gemdos.h"
20 #include "inffile.h"
21 #include "m68000.h"
22 #include "options.h"
23 #include "screen.h"
24 #include "stMemory.h"
25 #include "tos.h"
26 #include "vdi.h"
27 #include "video.h"
28
29 #define DEBUG 0
30
31 Uint32 VDI_OldPC; /* When call Trap#2, store off PC */
32
33 bool bVdiAesIntercept = false; /* Set to true to trace VDI & AES calls */
34 bool bUseVDIRes = false; /* Set to true (if want VDI), or false (ie for games) */
35 /* defaults */
36 int VDIRes = 0; /* 0,1 or 2 (low, medium, high) */
37 int VDIWidth = 640; /* 640x480, 800x600 or 1024x768 */
38 int VDIHeight = 480;
39 int VDIPlanes = 4;
40
41 static Uint32 LineABase; /* Line-A structure */
42 static Uint32 FontBase; /* Font base, used for 16-pixel high font */
43
44 /* Last VDI opcode & vectors */
45 static Uint16 VDIOpCode;
46 static Uint32 VDIControl;
47 static Uint32 VDIIntin;
48 static Uint32 VDIPtsin;
49 static Uint32 VDIIntout;
50 static Uint32 VDIPtsout;
51 #if ENABLE_TRACING
52 /* Last AES opcode & vectors */
53 static Uint32 AESControl;
54 static Uint32 AESGlobal;
55 static Uint32 AESIntin;
56 static Uint32 AESIntout;
57 static Uint32 AESAddrin;
58 static Uint32 AESAddrout;
59 static Uint16 AESOpCode;
60 #endif
61
62
63 /*-----------------------------------------------------------------------*/
64 /**
65 * Called to reset VDI variables on reset.
66 */
VDI_Reset(void)67 void VDI_Reset(void)
68 {
69 /* no VDI calls in progress */
70 VDI_OldPC = 0;
71 }
72
73 /*-----------------------------------------------------------------------*/
74 /**
75 * Limit width and height to VDI screen size in bytes, retaining their ratio.
76 * Return true if limiting was done.
77 */
VDI_ByteLimit(int * width,int * height,int planes)78 static bool VDI_ByteLimit(int *width, int *height, int planes)
79 {
80 double ratio;
81 int size;
82
83 size = (*width)*(*height)*planes/8;
84 if (size <= MAX_VDI_BYTES)
85 return false;
86
87 ratio = sqrt(MAX_VDI_BYTES) / sqrt(size);
88 *width = (*width) * ratio;
89 *height = (*height) * ratio;
90 if (*width < MIN_VDI_WIDTH || *height < MIN_VDI_HEIGHT)
91 {
92 *width = MIN_VDI_WIDTH;
93 *height = MIN_VDI_HEIGHT;
94 Log_Printf(LOG_WARN, "Bad VDI screen ratio / too small size -> use smallest valid size.\n");
95 }
96 else
97 Log_Printf(LOG_WARN, "VDI screen size limited to <= %dKB\n", MAX_VDI_BYTES/1024);
98 return true;
99 }
100
101 /*-----------------------------------------------------------------------*/
102 /**
103 * Set Width/Height/BitDepth according to passed GEMCOLOR_2/4/16.
104 * Align size when necessary.
105 */
VDI_SetResolution(int GEMColor,int WidthRequest,int HeightRequest)106 void VDI_SetResolution(int GEMColor, int WidthRequest, int HeightRequest)
107 {
108 int w = WidthRequest;
109 int h = HeightRequest;
110
111 /* Color depth */
112 switch (GEMColor)
113 {
114 case GEMCOLOR_2:
115 VDIRes = 2;
116 VDIPlanes = 1;
117 break;
118 case GEMCOLOR_4:
119 VDIRes = 1;
120 VDIPlanes = 2;
121 break;
122 case GEMCOLOR_16:
123 VDIRes = 0;
124 VDIPlanes = 4;
125 break;
126 }
127 /* screen size in bytes needs to be below limit */
128 VDI_ByteLimit(&w, &h, VDIPlanes);
129
130 #if DEBUG
131 printf("%s v0x%04x, RAM=%dkB\n", bIsEmuTOS ? "EmuTOS" : "TOS", TosVersion, ConfigureParams.Memory.STRamSize_KB);
132 #endif
133 /* width needs to be aligned to 16 bytes */
134 VDIWidth = Opt_ValueAlignMinMax(w, 128/VDIPlanes, MIN_VDI_WIDTH, MAX_VDI_WIDTH);
135
136 /* height needs to be multiple of cell height (either 8 or 16) */
137 VDIHeight = Opt_ValueAlignMinMax(h, 16, MIN_VDI_HEIGHT, MAX_VDI_HEIGHT);
138
139 if (w != VDIWidth || h != VDIHeight)
140 {
141 Log_Printf(LOG_WARN, "VDI screen: request = %dx%d@%d, result = %dx%d@%d\n",
142 WidthRequest, HeightRequest, VDIPlanes, VDIWidth, VDIHeight, VDIPlanes);
143 }
144 else
145 {
146 Log_Printf(LOG_DEBUG, "VDI screen: %dx%d@%d\n",
147 VDIWidth, VDIHeight, VDIPlanes);
148 }
149 if (bUseVDIRes)
150 {
151 /* INF file overriding so that (re-)boot uses correct bit-depth */
152 INF_SetVdiMode(VDIRes);
153 }
154 }
155
156
157 #if ENABLE_TRACING
158
159 /*-----------------------------------------------------------------------*/
160
161 /* AES opcodes which have string args */
162 static const struct {
163 int code; /* AES opcode */
164 int count; /* number of char * args _first_ in addrin[] */
165 } AESStrings[] = {
166 { 0x0D, 1 }, /* appl_find() */
167 { 0x12, 1 }, /* appl_search() */
168 { 0x23, 1 }, /* menu_register() */
169 { 0x34, 1 }, /* form_alert() */
170 { 0x51, 1 }, /* scrp_write() */
171 { 0x5A, 2 }, /* fsel_input() */
172 { 0x5B, 3 }, /* fsel_exinput() */
173 { 0x6E, 1 }, /* rsrc_load() */
174 { 0x7C, 1 } /* shell_find() */
175 };
176
177 /* AES opcode -> function name mapping */
178 static const char* AESName_10[] = {
179 "appl_init", /* (0x0A) */
180 "appl_read", /* (0x0B) */
181 "appl_write", /* (0x0C) */
182 "appl_find", /* (0x0D) */
183 "appl_tplay", /* (0x0E) */
184 "appl_trecord", /* (0x0F) */
185 NULL, /* (0x10) */
186 NULL, /* (0x11) */
187 "appl_search", /* (0x12) */
188 "appl_exit", /* (0x13) */
189 "evnt_keybd", /* (0x14) */
190 "evnt_button", /* (0x15) */
191 "evnt_mesag", /* (0x16) */
192 "evnt_mesag", /* (0x17) */
193 "evnt_timer", /* (0x18) */
194 "evnt_multi", /* (0x19) */
195 "evnt_dclick", /* (0x1A) */
196 NULL, /* (0x1b) */
197 NULL, /* (0x1c) */
198 NULL, /* (0x1d) */
199 "menu_bar", /* (0x1E) */
200 "menu_icheck", /* (0x1F) */
201 "menu_ienable", /* (0x20) */
202 "menu_tnormal", /* (0x21) */
203 "menu_text", /* (0x22) */
204 "menu_register", /* (0x23) */
205 "menu_popup", /* (0x24) */
206 "menu_attach", /* (0x25) */
207 "menu_istart", /* (0x26) */
208 "menu_settings", /* (0x27) */
209 "objc_add", /* (0x28) */
210 "objc_delete", /* (0x29) */
211 "objc_draw", /* (0x2A) */
212 "objc_find", /* (0x2B) */
213 "objc_offset", /* (0x2C) */
214 "objc_order", /* (0x2D) */
215 "objc_edit", /* (0x2E) */
216 "objc_change", /* (0x2F) */
217 "objc_sysvar", /* (0x30) */
218 NULL, /* (0x31) */
219 "form_do", /* (0x32) */
220 "form_dial", /* (0x33) */
221 "form_alert", /* (0x34) */
222 "form_error", /* (0x35) */
223 "form_center", /* (0x36) */
224 "form_keybd", /* (0x37) */
225 "form_button", /* (0x38) */
226 NULL, /* (0x39) */
227 NULL, /* (0x3a) */
228 NULL, /* (0x3b) */
229 NULL, /* (0x3c) */
230 NULL, /* (0x3d) */
231 NULL, /* (0x3e) */
232 NULL, /* (0x3f) */
233 NULL, /* (0x40) */
234 NULL, /* (0x41) */
235 NULL, /* (0x42) */
236 NULL, /* (0x43) */
237 NULL, /* (0x44) */
238 NULL, /* (0x45) */
239 "graf_rubberbox", /* (0x46) */
240 "graf_dragbox", /* (0x47) */
241 "graf_movebox", /* (0x48) */
242 "graf_growbox", /* (0x49) */
243 "graf_shrinkbox", /* (0x4A) */
244 "graf_watchbox", /* (0x4B) */
245 "graf_slidebox", /* (0x4C) */
246 "graf_handle", /* (0x4D) */
247 "graf_mouse", /* (0x4E) */
248 "graf_mkstate", /* (0x4F) */
249 "scrp_read", /* (0x50) */
250 "scrp_write", /* (0x51) */
251 NULL, /* (0x52) */
252 NULL, /* (0x53) */
253 NULL, /* (0x54) */
254 NULL, /* (0x55) */
255 NULL, /* (0x56) */
256 NULL, /* (0x57) */
257 NULL, /* (0x58) */
258 NULL, /* (0x59) */
259 "fsel_input", /* (0x5A) */
260 "fsel_exinput", /* (0x5B) */
261 NULL, /* (0x5c) */
262 NULL, /* (0x5d) */
263 NULL, /* (0x5e) */
264 NULL, /* (0x5f) */
265 NULL, /* (0x60) */
266 NULL, /* (0x61) */
267 NULL, /* (0x62) */
268 NULL, /* (0x63) */
269 "wind_create", /* (0x64) */
270 "wind_open", /* (0x65) */
271 "wind_close", /* (0x66) */
272 "wind_delete", /* (0x67) */
273 "wind_get", /* (0x68) */
274 "wind_set", /* (0x69) */
275 "wind_find", /* (0x6A) */
276 "wind_update", /* (0x6B) */
277 "wind_calc", /* (0x6C) */
278 "wind_new", /* (0x6D) */
279 "rsrc_load", /* (0x6E) */
280 "rsrc_free", /* (0x6F) */
281 "rsrc_gaddr", /* (0x70) */
282 "rsrc_saddr", /* (0x71) */
283 "rsrc_obfix", /* (0x72) */
284 "rsrc_rcfix", /* (0x73) */
285 NULL, /* (0x74) */
286 NULL, /* (0x75) */
287 NULL, /* (0x76) */
288 NULL, /* (0x77) */
289 "shel_read", /* (0x78) */
290 "shel_write", /* (0x79) */
291 "shel_get", /* (0x7A) */
292 "shel_put", /* (0x7B) */
293 "shel_find", /* (0x7C) */
294 "shel_envrn", /* (0x7D) */
295 NULL, /* (0x7e) */
296 NULL, /* (0x7f) */
297 NULL, /* (0x80) */
298 NULL, /* (0x81) */
299 "appl_getinfo" /* (0x82) */
300 };
301
302 /**
303 * Map AES call opcode to an AES function name
304 */
AES_Opcode2Name(Uint16 opcode)305 static const char* AES_Opcode2Name(Uint16 opcode)
306 {
307 int code = opcode - 10;
308 if (code >= 0 && code < ARRAY_SIZE(AESName_10) && AESName_10[code])
309 return AESName_10[code];
310 else
311 return "???";
312 }
313
314 /**
315 * Output AES call info, including some of args
316 */
AES_OpcodeInfo(FILE * fp,Uint16 opcode)317 static void AES_OpcodeInfo(FILE *fp, Uint16 opcode)
318 {
319 int code = opcode - 10;
320 fprintf(fp, "AES call %3hd ", opcode);
321 if (code >= 0 && code < ARRAY_SIZE(AESName_10) && AESName_10[code])
322 {
323 bool first = true;
324 int i, items;
325
326 fprintf(fp, "%s(", AESName_10[code]);
327
328 items = 0;
329 /* there are so few of these that linear search is fine */
330 for (i = 0; i < ARRAY_SIZE(AESStrings); i++)
331 {
332 /* something that can be shown? */
333 if (AESStrings[i].code == opcode)
334 {
335 items = AESStrings[i].count;
336 break;
337 }
338 }
339 /* addrin array size in longs enough for items? */
340 if (items > 0 && items <= STMemory_ReadWord(AESControl+SIZE_WORD*3))
341 {
342 const char *str;
343 fputs("addrin: ", fp);
344 for (i = 0; i < items; i++)
345 {
346 if (first)
347 first = false;
348 else
349 fputs(", ", fp);
350 str = (const char *)STMemory_STAddrToPointer(STMemory_ReadLong(AESAddrin+SIZE_LONG*i));
351 fprintf(fp, "\"%s\"", str);
352 }
353 }
354 /* intin array size in words */
355 items = STMemory_ReadWord(AESControl+SIZE_WORD*1);
356 if (items > 0)
357 {
358 if (!first)
359 {
360 fputs(", ", fp);
361 first = true;
362 }
363 fputs("intin: ", fp);
364 for (i = 0; i < items; i++)
365 {
366 if (first)
367 first = false;
368 else
369 fputs(",", fp);
370 fprintf(fp, "0x%x", STMemory_ReadWord(AESIntin+SIZE_WORD*i));
371 }
372 }
373 fputs(")\n", fp);
374 }
375 else
376 fputs("???\n", fp);
377 fflush(fp);
378 }
379
380 /**
381 * If opcodes argument is set, show AES opcode/function name table,
382 * otherwise AES vectors information.
383 */
AES_Info(FILE * fp,Uint32 bShowOpcodes)384 void AES_Info(FILE *fp, Uint32 bShowOpcodes)
385 {
386 Uint16 opcode;
387
388 if (bShowOpcodes)
389 {
390 for (opcode = 10; opcode < 0x86; opcode++)
391 {
392 fprintf(fp, "%02x %-16s", opcode, AES_Opcode2Name(opcode));
393 if ((opcode-9) % 4 == 0) fputs("\n", fp);
394 }
395 return;
396 }
397 if (!bVdiAesIntercept)
398 {
399 fputs("VDI/AES interception isn't enabled!\n", fp);
400 return;
401 }
402 if (!AESControl)
403 {
404 fputs("No traced AES calls!\n", fp);
405 return;
406 }
407 opcode = STMemory_ReadWord(AESControl);
408 if (opcode != AESOpCode)
409 {
410 fputs("AES parameter block contents changed since last call!\n", fp);
411 return;
412 }
413
414 fputs("Latest AES Parameter block:\n", fp);
415 fprintf(fp, "- Opcode: %3hd (%s)\n",
416 opcode, AES_Opcode2Name(opcode));
417
418 fprintf(fp, "- Control: %#8x\n", AESControl);
419 fprintf(fp, "- Global: %#8x, %d bytes\n",
420 AESGlobal, 2+2+2+4+4+4+4+4+4);
421 fprintf(fp, "- Intin: %#8x, %d words\n",
422 AESIntin, STMemory_ReadWord(AESControl+2*1));
423 fprintf(fp, "- Intout: %#8x, %d words\n",
424 AESIntout, STMemory_ReadWord(AESControl+2*2));
425 fprintf(fp, "- Addrin: %#8x, %d longs\n",
426 AESAddrin, STMemory_ReadWord(AESControl+2*3));
427 fprintf(fp, "- Addrout: %#8x, %d longs\n",
428 AESAddrout, STMemory_ReadWord(AESControl+2*4));
429 }
430
431
432 /*-----------------------------------------------------------------------*/
433
434 /**
435 * Map VDI call opcode/sub-opcode to a VDI function name
436 */
VDI_Opcode2Name(Uint16 opcode,Uint16 subcode)437 static const char* VDI_Opcode2Name(Uint16 opcode, Uint16 subcode)
438 {
439 static const char* names_0[] = {
440 "???",
441 "v_opnwk",
442 "v_clswk",
443 "v_clrwk",
444 "v_updwk",
445 "", /* 5: lots of sub opcodes */
446 "v_pline",
447 "v_pmarker",
448 "v_gtext",
449 "v_fillarea", /* sub-opcode 13: v_bez_fill with GDOS */
450 "v_cellarray",
451 "", /* 11: lots of sub opcodes */
452 "vst_height",
453 "vst_rotation",
454 "vs_color",
455 "vsl_type",
456 "vsl_width",
457 "vsl_color",
458 "vsm_type",
459 "vsm_height",
460 "vsm_color",
461 "vst_font",
462 "vst_color",
463 "vsf_interior",
464 "vsf_style",
465 "vsf_color",
466 "vq_color",
467 "vq_cellarray",
468 "vrq/sm_locator",
469 "vrq/sm_valuator",
470 "vrq/sm_choice",
471 "vrq/sm_string",
472 "vswr_mode",
473 "vsin_mode",
474 "???", /* 34 */
475 "vql_attributes",
476 "vqm_attributes",
477 "vqf_attributes",
478 "vqt_attributes",
479 "vst_alignment"
480 };
481 static const char* names_100[] = {
482 "v_opnvwk",
483 "v_clsvwk",
484 "vq_extnd",
485 "v_contourfill",
486 "vsf_perimeter",
487 "v_get_pixel",
488 "vst_effects",
489 "vst_point",
490 "vsl_ends",
491 "vro_cpyfm",
492 "vr_trnfm",
493 "vsc_form",
494 "vsf_udpat",
495 "vsl_udsty",
496 "vr_recfl",
497 "vqin_mode",
498 "vqt_extent",
499 "vqt_width",
500 "vex_timv",
501 "vst_load_fonts",
502 "vst_unload_fonts",
503 "vrt_cpyfm",
504 "v_show_c",
505 "v_hide_c",
506 "vq_mouse",
507 "vex_butv",
508 "vex_motv",
509 "vex_curv",
510 "vq_key_s",
511 "vs_clip",
512 "vqt_name",
513 "vqt_fontinfo"
514 /* 131-233: no known opcodes
515 * 234-255: (Speedo) GDOS opcodes
516 */
517 };
518 static const char* names_opcode5[] = {
519 "<no subcode>",
520 "vq_chcells",
521 "v_exit_cur",
522 "v_enter_cur",
523 "v_curup",
524 "v_curdown",
525 "v_curright",
526 "v_curleft",
527 "v_curhome",
528 "v_eeos",
529 "v_eeol",
530 "vs_curaddress",
531 "v_curtext",
532 "v_rvon",
533 "v_rvoff",
534 "vq_curaddress",
535 "vq_tabstatus",
536 "v_hardcopy",
537 "v_dspcur",
538 "v_rmcur",
539 "v_form_adv",
540 "v_output_window",
541 "v_clear_disp_list",
542 "v_bit_image",
543 "vq_scan",
544 "v_alpha_text"
545 };
546 static const char* names_opcode5_98[] = {
547 "v_meta_extents",
548 "v_write_meta",
549 "vm_filename",
550 "???",
551 "v_fontinit"
552 };
553 static const char* names_opcode11[] = {
554 "<no subcode>",
555 "v_bar",
556 "v_arc",
557 "v_pieslice",
558 "v_circle",
559 "v_ellipse",
560 "v_ellarc",
561 "v_ellpie",
562 "v_rbox",
563 "v_rfbox",
564 "v_justified"
565 };
566
567 if (opcode == 5)
568 {
569 if (subcode < ARRAY_SIZE(names_opcode5)) {
570 return names_opcode5[subcode];
571 }
572 if (subcode >= 98) {
573 subcode -= 98;
574 if (subcode < ARRAY_SIZE(names_opcode5_98)) {
575 return names_opcode5_98[subcode];
576 }
577 }
578 }
579 else if (opcode == 11)
580 {
581 if (subcode < ARRAY_SIZE(names_opcode11)) {
582 return names_opcode11[subcode];
583 }
584 }
585 else if (opcode < ARRAY_SIZE(names_0))
586 {
587 return names_0[opcode];
588 }
589 else if (opcode >= 100)
590 {
591 opcode -= 100;
592 if (opcode < ARRAY_SIZE(names_100))
593 {
594 return names_100[opcode];
595 }
596 }
597 return "GDOS?";
598 }
599
600 /**
601 * If opcodes argument is set, show VDI opcode/function name table,
602 * otherwise VDI vectors information.
603 */
VDI_Info(FILE * fp,Uint32 bShowOpcodes)604 void VDI_Info(FILE *fp, Uint32 bShowOpcodes)
605 {
606 Uint16 opcode, subcode;
607
608 if (bShowOpcodes)
609 {
610 Uint16 opcode;
611 for (opcode = 0; opcode < 0x84; )
612 {
613 if (opcode == 0x28)
614 {
615 fputs("--- GDOS calls? ---\n", fp);
616 opcode = 0x64;
617 }
618 fprintf(fp, "%02x %-16s",
619 opcode, VDI_Opcode2Name(opcode, 0));
620 if (++opcode % 4 == 0) fputs("\n", fp);
621 }
622 return;
623 }
624 if (!bVdiAesIntercept)
625 {
626 fputs("VDI/AES interception isn't enabled!\n", fp);
627 return;
628 }
629 if (!VDIControl)
630 {
631 fputs("No traced VDI calls!\n", fp);
632 return;
633 }
634 opcode = STMemory_ReadWord(VDIControl);
635 if (opcode != VDIOpCode)
636 {
637 fputs("VDI parameter block contents changed since last call!\n", fp);
638 return;
639 }
640
641 fputs("Latest VDI Parameter block:\n", fp);
642 subcode = STMemory_ReadWord(VDIControl+2*5);
643 fprintf(fp, "- Opcode/Subcode: %hd/%hd (%s)\n",
644 opcode, subcode, VDI_Opcode2Name(opcode, subcode));
645 fprintf(fp, "- Device handle: %d\n",
646 STMemory_ReadWord(VDIControl+2*6));
647 fprintf(fp, "- Control: %#8x\n", VDIControl);
648 fprintf(fp, "- Ptsin: %#8x, %d co-ordinate word pairs\n",
649 VDIPtsin, STMemory_ReadWord(VDIControl+2*1));
650 fprintf(fp, "- Ptsout: %#8x, %d co-ordinate word pairs\n",
651 VDIPtsout, STMemory_ReadWord(VDIControl+2*2));
652 fprintf(fp, "- Intin: %#8x, %d words\n",
653 VDIIntin, STMemory_ReadWord(VDIControl+2*3));
654 fprintf(fp, "- Intout: %#8x, %d words\n",
655 VDIIntout, STMemory_ReadWord(VDIControl+2*4));
656 }
657
658 #else /* !ENABLE_TRACING */
AES_Info(FILE * fp,Uint32 bShowOpcodes)659 void AES_Info(FILE *fp, Uint32 bShowOpcodes)
660 {
661 fputs("Hatari isn't configured with ENABLE_TRACING\n", fp);
662 }
VDI_Info(FILE * fp,Uint32 bShowOpcodes)663 void VDI_Info(FILE *fp, Uint32 bShowOpcodes)
664 {
665 fputs("Hatari isn't configured with ENABLE_TRACING\n", fp);
666 }
667 #endif /* !ENABLE_TRACING */
668
669
670 /*-----------------------------------------------------------------------*/
671 /**
672 * Return true for only VDI opcodes that need to be handled at Trap exit.
673 */
VDI_isWorkstationOpen(Uint16 opcode)674 static inline bool VDI_isWorkstationOpen(Uint16 opcode)
675 {
676 if (opcode == 1 || opcode == 100)
677 return true;
678 else
679 return false;
680 }
681
682 /**
683 * Check whether this is VDI/AES call and see if we need to re-direct
684 * it to our own routines. Return true if VDI_Complete() function
685 * needs to be called on OS call exit, otherwise return false.
686 *
687 * We enter here with Trap #2, so D0 tells which OS call it is (VDI/AES)
688 * and D1 is pointer to VDI/AES vectors, i.e. Control, Intin, Ptsin etc...
689 */
VDI_AES_Entry(void)690 bool VDI_AES_Entry(void)
691 {
692 Uint16 call = Regs[REG_D0];
693 Uint32 TablePtr = Regs[REG_D1];
694
695 #if ENABLE_TRACING
696 /* AES call? */
697 if (call == 0xC8)
698 {
699 if ( !STMemory_CheckAreaType ( TablePtr, 24, ABFLAG_RAM ) )
700 {
701 Log_Printf(LOG_WARN, "AES call failed due to invalid parameter block address 0x%x+%i\n", TablePtr, 24);
702 return false;
703 }
704 /* store values for debugger "info aes" command */
705 AESControl = STMemory_ReadLong(TablePtr);
706 AESGlobal = STMemory_ReadLong(TablePtr+4);
707 AESIntin = STMemory_ReadLong(TablePtr+8);
708 AESIntout = STMemory_ReadLong(TablePtr+12);
709 AESAddrin = STMemory_ReadLong(TablePtr+16);
710 AESAddrout = STMemory_ReadLong(TablePtr+20);
711 AESOpCode = STMemory_ReadWord(AESControl);
712 if (LOG_TRACE_LEVEL(TRACE_OS_AES))
713 {
714 AES_OpcodeInfo(TraceFile, AESOpCode);
715 }
716 /* using same special opcode trick doesn't work for
717 * both VDI & AES as AES functions can be called
718 * recursively and VDI calls happen inside AES calls.
719 */
720 return false;
721 }
722 #endif
723
724 /* VDI call? */
725 if (call == 0x73)
726 {
727 if ( !STMemory_CheckAreaType ( TablePtr, 20, ABFLAG_RAM ) )
728 {
729 Log_Printf(LOG_WARN, "VDI call failed due to invalid parameter block address 0x%x+%i\n", TablePtr, 20);
730 return false;
731 }
732 /* store values for extended VDI resolution handling
733 * and debugger "info vdi" command
734 */
735 VDIControl = STMemory_ReadLong(TablePtr);
736 VDIIntin = STMemory_ReadLong(TablePtr+4);
737 VDIPtsin = STMemory_ReadLong(TablePtr+8);
738 VDIIntout = STMemory_ReadLong(TablePtr+12);
739 VDIPtsout = STMemory_ReadLong(TablePtr+16);
740 VDIOpCode = STMemory_ReadWord(VDIControl);
741 #if ENABLE_TRACING
742 {
743 Uint16 subcode = STMemory_ReadWord(VDIControl+2*5);
744 LOG_TRACE(TRACE_OS_VDI, "VDI call %3hd/%3hd (%s)\n",
745 VDIOpCode, subcode,
746 VDI_Opcode2Name(VDIOpCode, subcode));
747 }
748 #endif
749 /* Only workstation open needs to be handled at trap return */
750 return bUseVDIRes && VDI_isWorkstationOpen(VDIOpCode);
751 }
752
753 LOG_TRACE((TRACE_OS_VDI|TRACE_OS_AES), "Trap #2 with D0 = 0x%hX\n", call);
754 return false;
755 }
756
757
758 /*-----------------------------------------------------------------------*/
759 /**
760 * Modify Line-A structure for our VDI resolutions
761 */
VDI_LineA(Uint32 linea,Uint32 fontbase)762 void VDI_LineA(Uint32 linea, Uint32 fontbase)
763 {
764 Uint32 fontadr, font1, font2;
765
766 LineABase = linea;
767 FontBase = fontbase;
768
769 if (bUseVDIRes)
770 {
771 int cel_ht, cel_wd;
772
773 fontadr = STMemory_ReadLong(linea-0x1cc); /* def_font */
774 if (fontadr == 0)
775 {
776 /* get 8x8 font header */
777 font1 = STMemory_ReadLong(fontbase + 4);
778 /* get 8x16 font header */
779 font2 = STMemory_ReadLong(fontbase + 8);
780 /* remove DEFAULT flag from 8x8 font */
781 STMemory_WriteWord(font1 + 66, STMemory_ReadWord(font1 + 66) & ~0x01);
782 /* remove DEFAULT flag from 8x16 font */
783 STMemory_WriteWord(font2 + 66, STMemory_ReadWord(font2 + 66) & ~0x01);
784 /* choose new font */
785 if (VDIHeight >= 400)
786 {
787 fontadr = font2;
788 } else
789 {
790 fontadr = font1;
791 }
792 /* make this new default font */
793 STMemory_WriteLong(linea-0x1cc, fontadr);
794 /* set DEFAULT flag for chosen font */
795 STMemory_WriteWord(fontadr + 66, STMemory_ReadWord(fontadr + 66) | 0x01);
796 }
797 cel_wd = STMemory_ReadWord(fontadr + 52);
798 cel_ht = STMemory_ReadWord(fontadr + 82);
799 if (cel_wd <= 0)
800 {
801 Log_Printf(LOG_WARN, "VDI Line-A init failed due to bad cell width!\n");
802 return;
803 }
804 if (cel_ht <= 0)
805 {
806 Log_Printf(LOG_WARN, "VDI Line-A init failed due to bad cell height!\n");
807 return;
808 }
809
810 STMemory_WriteWord(linea-46, cel_ht); /* v_cel_ht */
811 STMemory_WriteWord(linea-44, (VDIWidth/cel_wd)-1); /* v_cel_mx (cols-1) */
812 STMemory_WriteWord(linea-42, (VDIHeight/cel_ht)-1); /* v_cel_my (rows-1) */
813 STMemory_WriteWord(linea-40, cel_ht*((VDIWidth*VDIPlanes)/8)); /* v_cel_wr */
814
815 STMemory_WriteLong(linea-22, STMemory_ReadLong(fontadr + 76)); /* v_fnt_ad */
816 STMemory_WriteWord(linea-18, STMemory_ReadWord(fontadr + 38)); /* v_fnt_nd */
817 STMemory_WriteWord(linea-16, STMemory_ReadWord(fontadr + 36)); /* v_fnt_st */
818 STMemory_WriteWord(linea-14, STMemory_ReadWord(fontadr + 80)); /* v_fnt_wd */
819 STMemory_WriteWord(linea-12, VDIWidth); /* v_rez_hz */
820 STMemory_WriteLong(linea-10, STMemory_ReadLong(fontadr + 72)); /* v_off_ad */
821 STMemory_WriteWord(linea-4, VDIHeight); /* v_rez_vt */
822 STMemory_WriteWord(linea-2, (VDIWidth*VDIPlanes)/8); /* bytes_lin */
823 STMemory_WriteWord(linea+0, VDIPlanes); /* planes */
824 STMemory_WriteWord(linea+2, (VDIWidth*VDIPlanes)/8); /* width */
825 }
826 }
827
828
829 /*-----------------------------------------------------------------------*/
830 /**
831 * This is called on completion of a VDI Trap workstation open,
832 * to modify the return structure for extended resolutions.
833 */
VDI_Complete(void)834 void VDI_Complete(void)
835 {
836 /* right opcode? */
837 assert(VDI_isWorkstationOpen(VDIOpCode));
838 /* not changed between entry and completion? */
839 assert(VDIOpCode == STMemory_ReadWord(VDIControl));
840
841 STMemory_WriteWord(VDIIntout, VDIWidth-1); /* IntOut[0] Width-1 */
842 STMemory_WriteWord(VDIIntout+1*2, VDIHeight-1); /* IntOut[1] Height-1 */
843 STMemory_WriteWord(VDIIntout+13*2, 1 << VDIPlanes); /* IntOut[13] #colors */
844 STMemory_WriteWord(VDIIntout+39*2, 512); /* IntOut[39] #available colors */
845
846 STMemory_WriteWord(LineABase-0x15a*2, VDIWidth-1); /* WKXRez */
847 STMemory_WriteWord(LineABase-0x159*2, VDIHeight-1); /* WKYRez */
848
849 VDI_LineA(LineABase, FontBase); /* And modify Line-A structure accordingly */
850 }
851