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