1 /****************************************************************************
2 * *
3 * Third Year Project *
4 * *
5 * An IBM PC Emulator *
6 * For Unix and X Windows *
7 * *
8 * By David Hedley *
9 * *
10 * *
11 * This program is Copyrighted. Consult the file COPYRIGHT for more details *
12 * *
13 ****************************************************************************/
14
15 /* This is HARDWARE.C It contains stuff about the PC hardware (chips etc) */
16
17 #include "global.h"
18
19 #include <stdio.h>
20 #include <sys/time.h>
21 #include <signal.h>
22
23 #include "hardware.h"
24 #include "cpu.h"
25 #include "vgahard.h"
26
27 #ifdef DEBUGGER
28 # include "debugger.h"
29 #endif
30
31 static double ticks_per_second = TICKSPERSEC;
32 static struct itimerval timer;
33
34 static volatile int disable_int;
35 static volatile int timer_blocked = 1;
36
37 #define PORT60SIZE 5
38
39 static BYTE port60buffer[PORT60SIZE];
40 static int port60start, port60end;
41
42 static unsigned PIC_inservice;
43 static unsigned PIC_irq;
44 static unsigned PIC_mask = ~(PIC_TIMER|PIC_KEYBOARD);
45
46 static unsigned timer_tmp;
47
48 static unsigned VGA_status;
49
PIC_interrupt(void)50 static void PIC_interrupt(void)
51 {
52 if (PIC_inservice)
53 {
54 D2(printf("PIC still blocked\n"););
55 return;
56 }
57
58 if (PIC_irq & ~PIC_mask & PIC_TIMER)
59 {
60 D2(printf("INTR: timer\n"););
61 PIC_inservice = PIC_TIMER;
62 PIC_irq &= ~PIC_TIMER;
63 if (IF)
64 int_pending = 8;
65 else
66 {
67 D2(printf("INTR blocked: IF disabled\n"););
68 int_blocked = 8;
69 }
70 }
71 else if (PIC_irq & ~PIC_mask & PIC_KEYBOARD)
72 {
73 D2(printf("INTR: keyboard\n"););
74 PIC_inservice = PIC_KEYBOARD;
75 PIC_irq &= ~PIC_KEYBOARD;
76 if (IF)
77 int_pending = 9;
78 else
79 {
80 D2(printf("INTR blocked: IF disabled\n"););
81 int_blocked = 9;
82 }
83 }
84 }
85
86
PIC_flagint(unsigned interrupt)87 static void PIC_flagint(unsigned interrupt)
88 {
89 disable();
90 D2(printf("IRQ %02X\n", interrupt););
91 PIC_irq |= interrupt;
92 enable();
93 }
94
95
PIC_EOI(void)96 void PIC_EOI(void)
97 {
98 disable();
99
100 if (PIC_inservice & PIC_KEYBOARD)
101 {
102 if (++port60start >= PORT60SIZE)
103 port60start = 0;
104
105 if (port60start != port60end)
106 PIC_irq |= PIC_KEYBOARD;
107 }
108
109
110 PIC_inservice = 0;
111 PIC_interrupt();
112 enable();
113 }
114
115
port60_buffer_ok(int count)116 int port60_buffer_ok(int count)
117 {
118 int tmp = port60end;
119
120 for (; count > 0; count--)
121 {
122 if (++tmp >= PORT60SIZE)
123 tmp = 0;
124
125 if (tmp == port60start)
126 return FALSE;
127 }
128
129 return TRUE;
130 }
131
132
put_scancode(BYTE * code,int count)133 void put_scancode(BYTE *code, int count)
134 {
135 for (; count > 0; count--)
136 {
137 port60buffer[port60end] = *code++;
138
139 if (++port60end >= PORT60SIZE)
140 port60end = 0;
141 }
142
143 PIC_flagint(PIC_KEYBOARD);
144
145 D2(
146 {
147 int tmp;
148
149 printf("INT9 signalled\n");
150 printf("Port60 buffer: ");
151
152 tmp = port60start;
153 while (tmp != port60end)
154 {
155 printf("%02X ", port60buffer[tmp]);
156 if (++tmp >= PORT60SIZE)
157 tmp = 0;
158 }
159 printf("\n");
160 }
161 )
162 }
163
164
read_port60(void)165 static BYTE read_port60(void)
166 {
167 BYTE ret;
168 static BYTE lastread = 0;
169
170 disable();
171
172 if (port60start == port60end)
173 ret = lastread;
174 else
175 lastread = ret = port60buffer[port60start];
176
177 enable();
178
179 return ret;
180 }
181
182 #define TIMER_MULT 4
183
184 static volatile int int8_counter = TIMER_MULT;
185
timer_handler(int sig)186 static int timer_handler(int sig)
187 {
188
189 #ifdef DEBUGGER
190 if (in_debug)
191 return 0;
192 #endif
193
194 if (disable_int)
195 {
196 D2(printf("Timer called when disabled\n"););
197 timer_blocked++;
198 return 0;
199 }
200
201 disable();
202
203 vga_interrupt();
204
205 timer_tmp++;
206
207 if (--int8_counter == 0)
208 {
209 PIC_flagint(PIC_TIMER);
210 int8_counter = TIMER_MULT;
211 }
212
213 PIC_interrupt();
214
215 enable();
216 return 0;
217 }
218
219
220 #ifndef SA_RESTART
221 #define SA_RESTART 0
222 #endif
223
init_timer(void)224 void init_timer(void)
225 {
226 struct sigaction sa;
227
228 sa.sa_handler = (void *)timer_handler;
229 sa.sa_flags = SA_RESTART;
230 sigemptyset(&sa.sa_mask);
231
232 sigaction(SIGALRM, &sa, NULL);
233
234 timer.it_interval.tv_sec = timer.it_value.tv_sec = 0;
235 timer.it_interval.tv_usec = timer.it_value.tv_usec =
236 (long)(1000000.0 /((float)TIMER_MULT*TICKSPERSEC));
237
238 D2(printf("Set timer to %ld microseconds\n", timer.it_interval.tv_usec););
239 setitimer(ITIMER_REAL, &timer, NULL);
240 }
241
242
stoptimer(void)243 void stoptimer(void)
244 {
245 timer.it_interval.tv_sec = timer.it_value.tv_sec =
246 timer.it_interval.tv_usec = timer.it_value.tv_usec = 0;
247 setitimer(ITIMER_REAL, &timer, NULL);
248 signal(SIGALRM, SIG_IGN);
249 }
250
251
starttimer(void)252 void starttimer(void)
253 {
254 init_timer();
255 }
256
257
disable(void)258 void disable(void)
259 {
260 if (disable_int == 0)
261 timer_blocked = 0;
262 disable_int++;
263 }
264
265
enable(void)266 void enable(void)
267 {
268 if (disable_int > 0)
269 disable_int--;
270
271 if (disable_int == 0)
272 while (timer_blocked > 0)
273 {
274 timer_blocked--;
275 timer_handler(SIGALRM);
276 }
277 }
278
279
280 static int PIT_toggle = 1;
281
read_port(unsigned port)282 BYTE read_port(unsigned port)
283 {
284 BYTE val;
285 static unsigned timer_tmp;
286
287 switch(port)
288 {
289 case 0x21:
290 val = PIC_mask;
291 break;
292 case 0x40:
293 case 0x41:
294 case 0x42:
295 disable();
296 if ((PIT_toggle = !PIT_toggle) == 0)
297 val = timer_tmp & 0xff;
298 else
299 {
300 val = (timer_tmp & 0xff00) >> 8;
301 timer_tmp++;
302 }
303 enable();
304 break;
305 case 0x60:
306 val = read_port60();
307 break;
308 case 0x61:
309 val = 0xd0;
310 break;
311 case 0x3da:
312 val = VGA_status;
313 VGA_status ^= 0x9;
314 break;
315 default:
316 val = 0;
317 break;
318 }
319
320 D(printf("Reading 0x%02X from port 0x%04X\n", val, port););
321 return val;
322 }
323
324
write_port(unsigned port,BYTE value)325 void write_port(unsigned port, BYTE value)
326 {
327 switch(port)
328 {
329 case 0x20:
330 if (value == 0x20)
331 {
332 PIC_EOI();
333 return;
334 }
335 break;
336 case 0x21:
337 disable();
338 PIC_mask = value;
339 enable();
340 break;
341 case 0x43:
342 PIT_toggle = 1;
343 break;
344 default:
345 break;
346 }
347 D(printf("Writing 0x%02X to port 0x%04X\n", value, port););
348
349 }
350
351
352