2003-06-21 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / sim / ppc / hw_pal.c
CommitLineData
c906108c
SS
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
116enum {
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
129typedef struct _hw_pal_console_buffer {
130 char buffer;
131 int status;
132} hw_pal_console_buffer;
133
134typedef 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 */
142static void
143scan_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 */
161static void
162write_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
171static unsigned
172hw_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
218static unsigned
219hw_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
263static void
264hw_pal_instance_delete_callback(device_instance *instance)
265{
266 /* nothing to delete, the hw_pal is attached to the device */
267 return;
268}
269
270static int
271hw_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
279static int
280hw_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
294static 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
300static device_instance *
301hw_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
311static const device_interrupt_port_descriptor hw_pal_interrupt_ports[] = {
312 { "int", 0, MAX_NR_PROCESSORS },
313 { NULL }
314};
315
316
317static void
318hw_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
331static 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
346static void *
347hw_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
361const device_descriptor hw_pal_device_descriptor[] = {
362 { "pal", hw_pal_create, &hw_pal_callbacks },
363 { NULL },
364};
365
366#endif /* _HW_PAL_C_ */
This page took 0.188034 seconds and 4 git commands to generate.