]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/ppc/hw_pal.c
* config/sh/tm-sh.h (BELIEVE_PCC_PROMOTION): Define, so that
[thirdparty/binutils-gdb.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 #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_ */