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