Update the copyright notice of some of the files I missed
[external/binutils.git] / sim / ppc / hw_pal.c
1 /*  This file is part of the program psim.
2     
3     Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
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 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #else
36 #ifdef HAVE_STRINGS_H
37 #include <strings.h>
38 #endif
39 #endif
40
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44 #ifdef HAVE_STDLIB_H
45 #include <stdlib.h>
46 #endif
47
48
49 /* DEVICE
50
51    
52    pal - glue logic device containing assorted junk
53
54    
55    DESCRIPTION
56
57    
58    Typical hardware dependant hack.  This device allows the firmware
59    to gain access to all the things the firmware needs (but the OS
60    doesn't).
61
62    The pal contains the following registers.  Except for the interrupt
63    level register, each of the below is 8 bytes in size and must be
64    accessed using correct alignment.  For 16 and 32 bit accesses the
65    bytes not directed to the register are ignored:
66    
67    |0   reset register (write)
68    |4   processor id register (read)
69    |8   interrupt port (write)
70    |9   interrupt level (write)
71    |12  processor count register (read)
72    |16  tty input fifo register (read)
73    |20  tty input status register (read)
74    |24  tty output fifo register (write)
75    |28  tty output status register (read)
76
77    Reset register (write) halts the simulator exiting with the
78    value written.
79    
80    Processor id register (read) returns the processor number (0
81    .. N-1) of the processor performing the read.
82    
83    The interrupt registers should be accessed as a pair (using a 16 or
84    32 bit store).  The low byte specifies the interrupt port while the
85    high byte specifies the level to drive that port at.  By
86    convention, the pal's interrupt ports (int0, int1, ...) are wired
87    up to the corresponding processor's level sensative external
88    interrupt pin.  Eg: A two byte write to address 8 of 0x0102
89    (big-endian) will result in processor 2's external interrupt pin to
90    be asserted.
91
92    Processor count register (read) returns the total number of
93    processors active in the current simulation.
94
95    TTY input fifo register (read), if the TTY input status register
96    indicates a character is available by being nonzero, returns the
97    next available character from the pal's tty input port.
98
99    Similarly, the TTY output fifo register (write), if the TTY output
100    status register indicates the output fifo is not full by being
101    nonzero, outputs the character written to the tty's output port.
102
103
104    PROPERTIES
105    
106
107    reg = <address> <size> (required)
108
109    Specify the address (within the parent bus) that this device is to
110    live.
111
112
113    */
114
115
116 enum {
117   hw_pal_reset_register = 0x0,
118   hw_pal_cpu_nr_register = 0x4,
119   hw_pal_int_register = 0x8,
120   hw_pal_nr_cpu_register = 0xa,
121   hw_pal_read_fifo = 0x10,
122   hw_pal_read_status = 0x14,
123   hw_pal_write_fifo = 0x18,
124   hw_pal_write_status = 0x1a,
125   hw_pal_address_mask = 0x1f,
126 };
127
128
129 typedef struct _hw_pal_console_buffer {
130   char buffer;
131   int status;
132 } hw_pal_console_buffer;
133
134 typedef struct _hw_pal_device {
135   hw_pal_console_buffer input;
136   hw_pal_console_buffer output;
137   device *disk;
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   char c;
146   int count;
147   count = sim_io_read_stdin(&c, sizeof(c));
148   switch (count) {
149   case sim_io_not_ready:
150   case sim_io_eof:
151     hw_pal->input.buffer = 0;
152     hw_pal->input.status = 0;
153     break;
154   default:
155     hw_pal->input.buffer = c;
156     hw_pal->input.status = 1;
157   }
158 }
159
160 /* write the character to the hw_pal */
161 static void
162 write_hw_pal(hw_pal_device *hw_pal,
163              char val)
164 {
165   sim_io_write_stdout(&val, 1);
166   hw_pal->output.buffer = val;
167   hw_pal->output.status = 1;
168 }
169
170
171 static unsigned
172 hw_pal_io_read_buffer_callback(device *me,
173                                void *dest,
174                                int space,
175                                unsigned_word addr,
176                                unsigned nr_bytes,
177                                cpu *processor,
178                                unsigned_word cia)
179 {
180   hw_pal_device *hw_pal = (hw_pal_device*)device_data(me);
181   unsigned_1 val;
182   switch (addr & hw_pal_address_mask) {
183   case hw_pal_cpu_nr_register:
184     val = cpu_nr(processor);
185     DTRACE(pal, ("read - cpu-nr %d\n", val));
186     break;
187   case hw_pal_nr_cpu_register:
188     val = tree_find_integer_property(me, "/openprom/options/smp");
189     DTRACE(pal, ("read - nr-cpu %d\n", val));
190     break;
191   case hw_pal_read_fifo:
192     val = hw_pal->input.buffer;
193     DTRACE(pal, ("read - input-fifo %d\n", val));
194     break;
195   case hw_pal_read_status:
196     scan_hw_pal(hw_pal);
197     val = hw_pal->input.status;
198     DTRACE(pal, ("read - input-status %d\n", val));
199     break;
200   case hw_pal_write_fifo:
201     val = hw_pal->output.buffer;
202     DTRACE(pal, ("read - output-fifo %d\n", val));
203     break;
204   case hw_pal_write_status:
205     val = hw_pal->output.status;
206     DTRACE(pal, ("read - output-status %d\n", val));
207     break;
208   default:
209     val = 0;
210     DTRACE(pal, ("read - ???\n"));
211   }
212   memset(dest, 0, nr_bytes);
213   *(unsigned_1*)dest = val;
214   return nr_bytes;
215 }
216
217
218 static unsigned
219 hw_pal_io_write_buffer_callback(device *me,
220                                 const void *source,
221                                 int space,
222                                 unsigned_word addr,
223                                 unsigned nr_bytes,
224                                 cpu *processor,
225                                 unsigned_word cia)
226 {
227   hw_pal_device *hw_pal = (hw_pal_device*)device_data(me);
228   unsigned_1 *byte = (unsigned_1*)source;
229   
230   switch (addr & hw_pal_address_mask) {
231   case hw_pal_reset_register:
232     cpu_halt(processor, cia, was_exited, byte[0]);
233     break;
234   case hw_pal_int_register:
235     device_interrupt_event(me,
236                            byte[0], /*port*/
237                            (nr_bytes > 1 ? byte[1] : 0), /* val */
238                            processor, cia);
239     break;
240   case hw_pal_read_fifo:
241     hw_pal->input.buffer = byte[0];
242     DTRACE(pal, ("write - input-fifo %d\n", byte[0]));
243     break;
244   case hw_pal_read_status:
245     hw_pal->input.status = byte[0];
246     DTRACE(pal, ("write - input-status %d\n", byte[0]));
247     break;
248   case hw_pal_write_fifo:
249     write_hw_pal(hw_pal, byte[0]);
250     DTRACE(pal, ("write - output-fifo %d\n", byte[0]));
251     break;
252   case hw_pal_write_status:
253     hw_pal->output.status = byte[0];
254     DTRACE(pal, ("write - output-status %d\n", byte[0]));
255     break;
256   }
257   return nr_bytes;
258 }
259
260
261 /* instances of the hw_pal device */
262
263 static void
264 hw_pal_instance_delete_callback(device_instance *instance)
265 {
266   /* nothing to delete, the hw_pal is attached to the device */
267   return;
268 }
269
270 static int
271 hw_pal_instance_read_callback(device_instance *instance,
272                               void *buf,
273                               unsigned_word len)
274 {
275   DITRACE(pal, ("read - %s (%ld)", (const char*)buf, (long int)len));
276   return sim_io_read_stdin(buf, len);
277 }
278
279 static int
280 hw_pal_instance_write_callback(device_instance *instance,
281                                const void *buf,
282                                unsigned_word len)
283 {
284   int i;
285   const char *chp = buf;
286   hw_pal_device *hw_pal = device_instance_data(instance);
287   DITRACE(pal, ("write - %s (%ld)", (const char*)buf, (long int)len));
288   for (i = 0; i < len; i++)
289     write_hw_pal(hw_pal, chp[i]);
290   sim_io_flush_stdoutput();
291   return i;
292 }
293
294 static const device_instance_callbacks hw_pal_instance_callbacks = {
295   hw_pal_instance_delete_callback,
296   hw_pal_instance_read_callback,
297   hw_pal_instance_write_callback,
298 };
299
300 static device_instance *
301 hw_pal_create_instance(device *me,
302                        const char *path,
303                        const char *args)
304 {
305   return device_create_instance_from(me, NULL,
306                                      device_data(me),
307                                      path, args,
308                                      &hw_pal_instance_callbacks);
309 }
310
311 static const device_interrupt_port_descriptor hw_pal_interrupt_ports[] = {
312   { "int", 0, MAX_NR_PROCESSORS },
313   { NULL }
314 };
315
316
317 static void
318 hw_pal_attach_address(device *me,
319                       attach_type attach,
320                       int space,
321                       unsigned_word addr,
322                       unsigned nr_bytes,
323                       access_type access,
324                       device *client)
325 {
326   hw_pal_device *pal = (hw_pal_device*)device_data(me);
327   pal->disk = client;
328 }
329
330
331 static device_callbacks const hw_pal_callbacks = {
332   { generic_device_init_address, },
333   { hw_pal_attach_address, }, /* address */
334   { hw_pal_io_read_buffer_callback,
335       hw_pal_io_write_buffer_callback, },
336   { NULL, }, /* DMA */
337   { NULL, NULL, hw_pal_interrupt_ports }, /* interrupt */
338   { generic_device_unit_decode,
339     generic_device_unit_encode,
340     generic_device_address_to_attach_address,
341     generic_device_size_to_attach_size },
342   hw_pal_create_instance,
343 };
344
345
346 static void *
347 hw_pal_create(const char *name,
348               const device_unit *unit_address,
349               const char *args)
350 {
351   /* create the descriptor */
352   hw_pal_device *hw_pal = ZALLOC(hw_pal_device);
353   hw_pal->output.status = 1;
354   hw_pal->output.buffer = '\0';
355   hw_pal->input.status = 0;
356   hw_pal->input.buffer = '\0';
357   return hw_pal;
358 }
359
360
361 const device_descriptor hw_pal_device_descriptor[] = {
362   { "pal", hw_pal_create, &hw_pal_callbacks },
363   { NULL },
364 };
365
366 #endif /* _HW_PAL_C_ */