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