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