1 /*PC1640 video emulation.
2 Mostly standard EGA, but with CGA & Hercules emulation*/
3 #include <stdlib.h>
4 #include "ibm.h"
5 #include "device.h"
6 #include "io.h"
7 #include "mem.h"
8 #include "rom.h"
9 #include "timer.h"
10 #include "video.h"
11 #include "vid_cga.h"
12 #include "vid_ega.h"
13 #include "vid_pc1640.h"
14
15 typedef struct pc1640_t
16 {
17 mem_mapping_t cga_mapping;
18 mem_mapping_t ega_mapping;
19
20 cga_t cga;
21 ega_t ega;
22
23 rom_t bios_rom;
24
25 int cga_enabled;
26 int dispontime, dispofftime, vidtime;
27 } pc1640_t;
28
pc1640_out(uint16_t addr,uint8_t val,void * p)29 void pc1640_out(uint16_t addr, uint8_t val, void *p)
30 {
31 pc1640_t *pc1640 = (pc1640_t *)p;
32
33 switch (addr)
34 {
35 case 0x3db:
36 pc1640->cga_enabled = val & 0x40;
37 if (pc1640->cga_enabled)
38 {
39 mem_mapping_enable(&pc1640->cga_mapping);
40 mem_mapping_disable(&pc1640->ega_mapping);
41 }
42 else
43 {
44 mem_mapping_disable(&pc1640->cga_mapping);
45 switch (pc1640->ega.gdcreg[6] & 0xc)
46 {
47 case 0x0: /*128k at A0000*/
48 mem_mapping_set_addr(&pc1640->ega_mapping, 0xa0000, 0x20000);
49 break;
50 case 0x4: /*64k at A0000*/
51 mem_mapping_set_addr(&pc1640->ega_mapping, 0xa0000, 0x10000);
52 break;
53 case 0x8: /*32k at B0000*/
54 mem_mapping_set_addr(&pc1640->ega_mapping, 0xb0000, 0x08000);
55 break;
56 case 0xC: /*32k at B8000*/
57 mem_mapping_set_addr(&pc1640->ega_mapping, 0xb8000, 0x08000);
58 break;
59 }
60 }
61 pclog("3DB write %02X\n", val);
62 return;
63 }
64 if (pc1640->cga_enabled) cga_out(addr, val, &pc1640->cga);
65 else ega_out(addr, val, &pc1640->ega);
66 }
67
pc1640_in(uint16_t addr,void * p)68 uint8_t pc1640_in(uint16_t addr, void *p)
69 {
70 pc1640_t *pc1640 = (pc1640_t *)p;
71
72 switch (addr)
73 {
74 }
75
76 if (pc1640->cga_enabled) return cga_in(addr, &pc1640->cga);
77 else return ega_in(addr, &pc1640->ega);
78 }
79
pc1640_recalctimings(pc1640_t * pc1640)80 void pc1640_recalctimings(pc1640_t *pc1640)
81 {
82 cga_recalctimings(&pc1640->cga);
83 ega_recalctimings(&pc1640->ega);
84 if (pc1640->cga_enabled)
85 {
86 pc1640->dispontime = pc1640->cga.dispontime;
87 pc1640->dispofftime = pc1640->cga.dispofftime;
88 }
89 else
90 {
91 pc1640->dispontime = pc1640->ega.dispontime;
92 pc1640->dispofftime = pc1640->ega.dispofftime;
93 }
94 }
95
pc1640_poll(void * p)96 void pc1640_poll(void *p)
97 {
98 pc1640_t *pc1640 = (pc1640_t *)p;
99 if (pc1640->cga_enabled)
100 {
101 pc1640->cga.vidtime = pc1640->vidtime;
102 cga_poll(&pc1640->cga);
103 pc1640->vidtime = pc1640->cga.vidtime;
104 }
105 else
106 {
107 pc1640->ega.vidtime = pc1640->vidtime;
108 ega_poll(&pc1640->ega);
109 pc1640->vidtime = pc1640->ega.vidtime;
110 }
111 }
112
pc1640_init()113 void *pc1640_init()
114 {
115 pc1640_t *pc1640 = malloc(sizeof(pc1640_t));
116 cga_t *cga = &pc1640->cga;
117 ega_t *ega = &pc1640->ega;
118 memset(pc1640, 0, sizeof(pc1640_t));
119
120 rom_init(&pc1640->bios_rom, "pc1640/40100", 0xc0000, 0x8000, 0x7fff, 0, 0);
121
122 ega_init(&pc1640->ega, 9, 0);
123 pc1640->cga.vram = pc1640->ega.vram;
124 pc1640->cga_enabled = 1;
125 cga_init(&pc1640->cga);
126
127 timer_add(pc1640_poll, &pc1640->vidtime, TIMER_ALWAYS_ENABLED, pc1640);
128 mem_mapping_add(&pc1640->cga_mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga);
129 mem_mapping_add(&pc1640->ega_mapping, 0, 0, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega);
130 io_sethandler(0x03a0, 0x0040, pc1640_in, NULL, NULL, pc1640_out, NULL, NULL, pc1640);
131 return pc1640;
132 }
133
pc1640_close(void * p)134 void pc1640_close(void *p)
135 {
136 pc1640_t *pc1640 = (pc1640_t *)p;
137
138 free(pc1640->ega.vram);
139 free(pc1640);
140 }
141
pc1640_speed_changed(void * p)142 void pc1640_speed_changed(void *p)
143 {
144 pc1640_t *pc1640 = (pc1640_t *)p;
145
146 pc1640_recalctimings(pc1640);
147 }
148
149 device_t pc1640_device =
150 {
151 "Amstrad PC1640 (video)",
152 0,
153 pc1640_init,
154 pc1640_close,
155 NULL,
156 pc1640_speed_changed,
157 NULL,
158 NULL
159 };
160