]> Git Repo - binutils.git/blob - sim/ppc/hw_pal.c
* config/sh/tm-sh.h (BELIEVE_PCC_PROMOTION): Define, so that
[binutils.git] / sim / ppc / hw_pal.c
1 /*  This file is part of the program psim.
2     
3     Copyright (C) 1994-1996, Andrew Cagney <[email protected]>
4     
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9     
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14     
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18     
19     */
20
21
22 #ifndef _HW_PAL_C_
23 #define _HW_PAL_C_
24
25 #ifndef STATIC_INLINE_HW_PAL
26 #define STATIC_INLINE_HW_PAL STATIC_INLINE
27 #endif
28
29 #include "device_table.h"
30
31 #include "cpu.h"
32
33 #include <stdio.h>
34 #include <fcntl.h>
35
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #else
39 #ifdef HAVE_STRINGS_H
40 #include <strings.h>
41 #endif
42 #endif
43
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47 #ifdef HAVE_STDLIB_H
48 #include <stdlib.h>
49 #endif
50
51 #if !defined(O_NDELAY) || !defined(F_GETFL) || !defined(F_SETFL)
52 #undef WITH_STDIO
53 #define WITH_STDIO DO_USE_STDIO
54 #endif
55
56 /* DEVICE
57    
58    pal - glue logic device containing assorted junk
59    
60    DESCRIPTION
61    
62    Typical hardware dependant hack.  This device allows the firmware
63    to gain access to all the things the firmware needs (but the OS
64    doesn't).
65
66    The pal contains the following registers.  Except for the interrupt
67    level register, each of the below is 8 bytes in size and must be
68    accessed using correct alignment.  For 16 and 32 bit accesses the
69    bytes not directed to the register are ignored:
70    
71    |0   reset register (write)
72    |4   processor id register (read)
73    |8   interrupt port (write)
74    |9   interrupt level (write)
75    |12  processor count register (read)
76    |16  tty input fifo register (read)
77    |20  tty input status register (read)
78    |24  tty output fifo register (write)
79    |28  tty output status register (read)
80
81    Reset register (write) halts the simulator exiting with the
82    value written.
83    
84    Processor id register (read) returns the processor number (0
85    .. N-1) of the processor performing the read.
86    
87    The interrupt registers should be accessed as a pair (using a 16 or
88    32 bit store).  The low byte specifies the interrupt port while the
89    high byte specifies the level to drive that port at.  By
90    convention, the pal's interrupt ports (int0, int1, ...) are wired
91    up to the corresponding processor's level sensative external
92    interrupt pin.  Eg: A two byte write to address 8 of 0x0102
93    (big-endian) will result in processor 2's external interrupt pin to
94    be asserted.
95
96    Processor count register (read) returns the total number of
97    processors active in the current simulation.
98
99    TTY input fifo register (read), if the TTY input status register
100    indicates a character is available by being nonzero, returns the
101    next available character from the pal's tty input port.
102
103    Similarly, the TTY output fifo register (write), if the TTY output
104    status register indicates the output fifo is not full by being
105    nonzero, outputs the character written to the tty's output port.
106
107    PROPERTIES
108    
109    reg = <address> <size> (required)
110
111    Specify the address (within the parent bus) that this device is to
112    live.
113
114    */
115
116
117 enum {
118   hw_pal_reset_register = 0x0,
119   hw_pal_cpu_nr_register = 0x4,
120   hw_pal_int_register = 0x8,
121   hw_pal_nr_cpu_register = 0xa,
122   hw_pal_read_fifo = 0x10,
123   hw_pal_read_status = 0x14,
124   hw_pal_write_fifo = 0x18,
125   hw_pal_write_status = 0x1a,
126   hw_pal_address_mask = 0x1f,
127 };
128
129
130 typedef struct _hw_pal_console_buffer {
131   char buffer;
132   int status;
133 } hw_pal_console_buffer;
134
135 typedef struct _hw_pal_device {
136   hw_pal_console_buffer input;
137   hw_pal_console_buffer output;
138 } hw_pal_device;
139
140
141 /* check the console for an available character */
142 static void
143 scan_hw_pal(hw_pal_device *hw_pal)
144 {
145   if (WITH_STDIO == DO_USE_STDIO) {
146     int c = getchar ();
147     if (c == EOF) {
148       hw_pal->input.buffer = 0;
149       hw_pal->input.status = 0;
150     } else {
151       hw_pal->input.buffer = c;
152       hw_pal->input.status = 1;
153     }
154
155   } else {
156 #if !defined(O_NDELAY) || !defined(F_GETFL) || !defined(F_SETFL)
157     error ("O_NDELAY, F_GETFL, or F_SETFL not defined");
158
159 #else
160     /* check for input */
161     int flags;
162     int status;
163     /* get the old status */
164     flags = fcntl(0, F_GETFL, 0);
165     if (flags == -1) {
166       perror("hw_pal");
167       return;
168     }
169     /* temp, disable blocking IO */
170     status = fcntl(0, F_SETFL, flags | O_NDELAY);
171     if (status == -1) {
172       perror("hw_pal");
173       return;
174     }
175     /* try for input */
176     status = read(0, &hw_pal->input.buffer, 1);
177     if (status == 1) {
178       hw_pal->input.status = 1;
179     }
180     else {
181       hw_pal->input.status = 0;
182     }
183     /* return to regular vewing */
184     flags = fcntl(0, F_SETFL, flags);
185     if (flags == -1) {
186       perror("hw_pal");
187       return;
188     }
189 #endif
190   }
191 }
192
193 /* write the character to the hw_pal */
194 static void
195 write_hw_pal(hw_pal_device *hw_pal,
196              char val)
197 {
198   if (WITH_STDIO == DO_USE_STDIO) {
199     putchar (val);
200
201   } else {
202     printf_filtered("%c", val) ;
203   }
204
205   hw_pal->output.buffer = val;
206   hw_pal->output.status = 1;
207 }
208
209
210 static unsigned
211 hw_pal_io_read_buffer_callback(device *me,
212                                void *dest,
213                                int space,
214                                unsigned_word addr,
215                                unsigned nr_bytes,
216                                cpu *processor,
217                                unsigned_word cia)
218 {
219   hw_pal_device *hw_pal = (hw_pal_device*)device_data(me);
220   unsigned_1 val;
221   switch (addr & hw_pal_address_mask) {
222   case hw_pal_cpu_nr_register:
223     val = cpu_nr(processor);
224     break;
225   case hw_pal_nr_cpu_register:
226     val = device_find_integer_property(me, "/openprom/options/smp");
227     break;
228   case hw_pal_read_fifo:
229     val = hw_pal->input.buffer;
230     break;
231   case hw_pal_read_status:
232     scan_hw_pal(hw_pal);
233     val = hw_pal->input.status;
234     break;
235   case hw_pal_write_fifo:
236     val = hw_pal->output.buffer;
237     break;
238   case hw_pal_write_status:
239     val = hw_pal->output.status;
240     break;
241   default:
242     val = 0;
243   }
244   memset(dest, 0, nr_bytes);
245   *(unsigned_1*)dest = val;
246   return nr_bytes;
247 }
248
249
250 static unsigned
251 hw_pal_io_write_buffer_callback(device *me,
252                                 const void *source,
253                                 int space,
254                                 unsigned_word addr,
255                                 unsigned nr_bytes,
256                                 cpu *processor,
257                                 unsigned_word cia)
258 {
259   hw_pal_device *hw_pal = (hw_pal_device*)device_data(me);
260   unsigned_1 *byte = (unsigned_1*)source;
261   
262   switch (addr & hw_pal_address_mask) {
263   case hw_pal_reset_register:
264     cpu_halt(processor, cia, was_exited, byte[0]);
265     break;
266   case hw_pal_int_register:
267     device_interrupt_event(me,
268                            byte[0], /*port*/
269                            (nr_bytes > 1 ? byte[1] : 0), /* val */
270                            processor, cia);
271     break;
272   case hw_pal_read_fifo:
273     hw_pal->input.buffer = byte[0];
274     break;
275   case hw_pal_read_status:
276     hw_pal->input.status = byte[0];
277     break;
278   case hw_pal_write_fifo:
279     write_hw_pal(hw_pal, byte[0]);
280     break;
281   case hw_pal_write_status:
282     hw_pal->output.status = byte[0];
283     break;
284   }
285   return nr_bytes;
286 }
287
288
289 /* instances of the hw_pal device */
290
291 static void
292 hw_pal_instance_delete_callback(device_instance *instance)
293 {
294   /* nothing to delete, the hw_pal is attached to the device */
295   return;
296 }
297
298 static int
299 hw_pal_instance_read_callback(device_instance *instance,
300                               void *buf,
301                               unsigned_word len)
302 {
303   char *buf_char = (char *)buf;
304   if (WITH_STDIO == DO_USE_STDIO) {
305     char *line = fgets (buf_char, len, stdin);
306     return ((!line) ? -1 : strlen (buf_char));
307
308   } else {
309     return read(0, buf_char, len);
310   }
311 }
312
313 static int
314 hw_pal_instance_write_callback(device_instance *instance,
315                                const void *buf,
316                                unsigned_word len)
317 {
318   int i;
319   const char *chp = buf;
320   hw_pal_device *hw_pal = device_instance_data(instance);
321   for (i = 0; i < len; i++)
322     write_hw_pal(hw_pal, chp[i]);
323
324   if (WITH_STDIO == DO_USE_STDIO) {
325     fflush (stdout);
326   }
327   return i;
328 }
329
330 static const device_instance_callbacks hw_pal_instance_callbacks = {
331   hw_pal_instance_delete_callback,
332   hw_pal_instance_read_callback,
333   hw_pal_instance_write_callback,
334 };
335
336 static device_instance *
337 hw_pal_create_instance(device *me,
338                        const char *path,
339                        const char *args)
340 {
341   return device_create_instance_from(me, NULL,
342                                      device_data(me),
343                                      path, args,
344                                      &hw_pal_instance_callbacks);
345 }
346
347 static const device_interrupt_port_descriptor hw_pal_interrupt_ports[] = {
348   { "int", 0, MAX_NR_PROCESSORS },
349   { NULL }
350 };
351
352
353 static device_callbacks const hw_pal_callbacks = {
354   { generic_device_init_address, },
355   { NULL, }, /* address */
356   { hw_pal_io_read_buffer_callback,
357       hw_pal_io_write_buffer_callback, },
358   { NULL, }, /* DMA */
359   { NULL, NULL, hw_pal_interrupt_ports }, /* interrupt */
360   { NULL, }, /* unit */
361   hw_pal_create_instance,
362 };
363
364
365 static void *
366 hw_pal_create(const char *name,
367               const device_unit *unit_address,
368               const char *args)
369 {
370   /* create the descriptor */
371   hw_pal_device *hw_pal = ZALLOC(hw_pal_device);
372   hw_pal->output.status = 1;
373   hw_pal->output.buffer = '\0';
374   hw_pal->input.status = 0;
375   hw_pal->input.buffer = '\0';
376   return hw_pal;
377 }
378
379
380 const device_descriptor hw_pal_device_descriptor[] = {
381   { "pal", hw_pal_create, &hw_pal_callbacks },
382   { NULL },
383 };
384
385 #endif /* _HW_PAL_C_ */
This page took 0.044935 seconds and 4 git commands to generate.