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