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