Commit | Line | Data |
---|---|---|
1ed0c0e7 MM |
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 | #include "cpu.h" | |
31 | ||
32 | ||
33 | #include <stdio.h> | |
34 | #include <fcntl.h> | |
35 | ||
36 | #if 0 | |
37 | #ifdef HAVE_TIME_H | |
38 | #include <time.h> | |
39 | #endif | |
40 | #endif | |
41 | ||
42 | #ifdef HAVE_STRING_H | |
43 | #include <string.h> | |
44 | #else | |
45 | #ifdef HAVE_STRINGS_H | |
46 | #include <strings.h> | |
47 | #endif | |
48 | #endif | |
49 | ||
50 | #ifdef HAVE_UNISTD_H | |
51 | #include <unistd.h> | |
52 | #endif | |
53 | #ifdef HAVE_STDLIB_H | |
54 | #include <stdlib.h> | |
55 | #endif | |
56 | ||
f64dbcdd MM |
57 | #if !defined(O_NDELAY) || !defined(F_GETFL) || !defined(F_SETFL) |
58 | #undef WITH_STDIO | |
59 | #define WITH_STDIO DO_USE_STDIO | |
60 | #endif | |
1ed0c0e7 MM |
61 | |
62 | /* Device: | |
63 | ||
64 | pal@<address> | |
65 | ||
66 | ||
67 | Description: | |
68 | ||
69 | Typical hardware dependant hack. This device allows the firmware | |
70 | to gain access to all the things the firmware needs (but the OS | |
71 | doesn't). All registers are little endian (byte 0 is the least | |
72 | significant) and must be accessed correctly aligned. | |
73 | ||
74 | <address> + 0: write - halts simulation with exit code byte[0]. | |
75 | ||
76 | <address> + 4: read - processor nr in byte[0]. | |
77 | ||
78 | <address> + 8: write - send interrupt message to port byte[0] with | |
79 | value byte[1]. | |
80 | ||
81 | <address> + 12: read - nr processors in byte[0]. | |
82 | ||
83 | ||
84 | Properties: | |
85 | ||
86 | NONE. */ | |
87 | ||
88 | ||
89 | enum { | |
90 | hw_pal_reset_register = 0x0, | |
91 | hw_pal_cpu_nr_register = 0x4, | |
92 | hw_pal_int_register = 0x8, | |
93 | hw_pal_nr_cpu_register = 0xa, | |
94 | hw_pal_read_fifo = 0x10, | |
95 | hw_pal_read_status = 0x14, | |
96 | hw_pal_write_fifo = 0x18, | |
97 | hw_pal_write_status = 0x1a, | |
98 | hw_pal_address_mask = 0x1f, | |
99 | }; | |
100 | ||
101 | ||
102 | typedef struct _hw_pal_console_buffer { | |
103 | char buffer; | |
104 | int status; | |
105 | } hw_pal_console_buffer; | |
106 | ||
107 | typedef struct _hw_pal_device { | |
108 | hw_pal_console_buffer input; | |
109 | hw_pal_console_buffer output; | |
110 | } hw_pal_device; | |
111 | ||
112 | ||
113 | /* check the console for an available character */ | |
114 | static void | |
115 | scan_hw_pal(hw_pal_device *hw_pal) | |
116 | { | |
117 | if (WITH_STDIO == DO_USE_STDIO) { | |
118 | int c = getchar (); | |
119 | if (c == EOF) { | |
120 | hw_pal->input.buffer = 0; | |
121 | hw_pal->input.status = 0; | |
122 | } else { | |
123 | hw_pal->input.buffer = c; | |
124 | hw_pal->input.status = 1; | |
125 | } | |
126 | ||
127 | } else { | |
f64dbcdd MM |
128 | #if !defined(O_NDELAY) || !defined(F_GETFL) || !defined(F_SETFL) |
129 | error ("O_NDELAY, F_GETFL, or F_SETFL not defined"); | |
130 | ||
131 | #else | |
1ed0c0e7 MM |
132 | /* check for input */ |
133 | int flags; | |
134 | int status; | |
135 | /* get the old status */ | |
136 | flags = fcntl(0, F_GETFL, 0); | |
137 | if (flags == -1) { | |
138 | perror("hw_pal"); | |
139 | return; | |
140 | } | |
141 | /* temp, disable blocking IO */ | |
142 | status = fcntl(0, F_SETFL, flags | O_NDELAY); | |
143 | if (status == -1) { | |
144 | perror("hw_pal"); | |
145 | return; | |
146 | } | |
147 | /* try for input */ | |
148 | status = read(0, &hw_pal->input.buffer, 1); | |
149 | if (status == 1) { | |
150 | hw_pal->input.status = 1; | |
151 | } | |
152 | else { | |
153 | hw_pal->input.status = 0; | |
154 | } | |
155 | /* return to regular vewing */ | |
156 | flags = fcntl(0, F_SETFL, flags); | |
157 | if (flags == -1) { | |
158 | perror("hw_pal"); | |
159 | return; | |
160 | } | |
f64dbcdd | 161 | #endif |
1ed0c0e7 MM |
162 | } |
163 | } | |
164 | ||
165 | /* write the character to the hw_pal */ | |
166 | static void | |
167 | write_hw_pal(hw_pal_device *hw_pal, | |
168 | char val) | |
169 | { | |
170 | if (WITH_STDIO == DO_USE_STDIO) { | |
171 | putchar (val); | |
172 | ||
173 | } else { | |
174 | printf_filtered("%c", val) ; | |
175 | } | |
176 | ||
177 | hw_pal->output.buffer = val; | |
178 | hw_pal->output.status = 1; | |
179 | } | |
180 | ||
181 | ||
182 | static unsigned | |
183 | hw_pal_io_read_buffer_callback(device *me, | |
184 | void *dest, | |
185 | int space, | |
186 | unsigned_word addr, | |
187 | unsigned nr_bytes, | |
188 | cpu *processor, | |
189 | unsigned_word cia) | |
190 | { | |
191 | hw_pal_device *hw_pal = (hw_pal_device*)device_data(me); | |
192 | unsigned_1 val; | |
193 | switch (addr & hw_pal_address_mask) { | |
194 | case hw_pal_cpu_nr_register: | |
195 | val = cpu_nr(processor); | |
196 | break; | |
197 | case hw_pal_nr_cpu_register: | |
198 | val = device_find_integer_property(me, "/openprom/options/smp"); | |
199 | break; | |
200 | case hw_pal_read_fifo: | |
201 | val = hw_pal->input.buffer; | |
202 | break; | |
203 | case hw_pal_read_status: | |
204 | scan_hw_pal(hw_pal); | |
205 | val = hw_pal->input.status; | |
206 | break; | |
207 | case hw_pal_write_fifo: | |
208 | val = hw_pal->output.buffer; | |
209 | break; | |
210 | case hw_pal_write_status: | |
211 | val = hw_pal->output.status; | |
212 | break; | |
213 | default: | |
214 | val = 0; | |
215 | } | |
216 | memset(dest, 0, nr_bytes); | |
217 | *(unsigned_1*)dest = val; | |
218 | return nr_bytes; | |
219 | } | |
220 | ||
221 | ||
222 | static unsigned | |
223 | hw_pal_io_write_buffer_callback(device *me, | |
224 | const void *source, | |
225 | int space, | |
226 | unsigned_word addr, | |
227 | unsigned nr_bytes, | |
228 | cpu *processor, | |
229 | unsigned_word cia) | |
230 | { | |
231 | hw_pal_device *hw_pal = (hw_pal_device*)device_data(me); | |
232 | unsigned_1 *byte = (unsigned_1*)source; | |
233 | ||
234 | switch (addr & hw_pal_address_mask) { | |
235 | case hw_pal_reset_register: | |
236 | cpu_halt(processor, cia, was_exited, byte[0]); | |
237 | break; | |
238 | case hw_pal_int_register: | |
239 | device_interrupt_event(me, | |
240 | byte[0], /*port*/ | |
241 | (nr_bytes > 1 ? byte[1] : 0), /* val */ | |
242 | processor, cia); | |
243 | break; | |
244 | case hw_pal_read_fifo: | |
245 | hw_pal->input.buffer = byte[0]; | |
246 | break; | |
247 | case hw_pal_read_status: | |
248 | hw_pal->input.status = byte[0]; | |
249 | break; | |
250 | case hw_pal_write_fifo: | |
251 | write_hw_pal(hw_pal, byte[0]); | |
252 | break; | |
253 | case hw_pal_write_status: | |
254 | hw_pal->output.status = byte[0]; | |
255 | break; | |
256 | } | |
257 | return nr_bytes; | |
258 | } | |
259 | ||
260 | ||
261 | /* instances of the hw_pal device */ | |
262 | static void * | |
263 | hw_pal_instance_create_callback(device *me, | |
264 | const char *args) | |
265 | { | |
266 | /* make life easier, attach the hw_pal data to the instance */ | |
267 | return device_data(me); | |
268 | } | |
269 | ||
270 | static void | |
271 | hw_pal_instance_delete_callback(device_instance *instance) | |
272 | { | |
273 | /* nothing to delete, the hw_pal is attached to the device */ | |
274 | return; | |
275 | } | |
276 | ||
277 | static int | |
278 | hw_pal_instance_read_callback(device_instance *instance, | |
279 | void *buf, | |
280 | unsigned_word len) | |
281 | { | |
282 | char *buf_char = (char *)buf; | |
1ed0c0e7 MM |
283 | if (WITH_STDIO == DO_USE_STDIO) { |
284 | char *line = fgets (buf_char, len, stdin); | |
285 | return ((!line) ? -1 : strlen (buf_char)); | |
286 | ||
287 | } else { | |
288 | return read(0, buf_char, len); | |
289 | } | |
290 | } | |
291 | ||
292 | static int | |
293 | hw_pal_instance_write_callback(device_instance *instance, | |
294 | const void *buf, | |
295 | unsigned_word len) | |
296 | { | |
297 | int i; | |
298 | const char *chp = buf; | |
299 | hw_pal_device *hw_pal = device_instance_data(instance); | |
300 | for (i = 0; i < len; i++) | |
301 | write_hw_pal(hw_pal, chp[i]); | |
302 | ||
303 | if (WITH_STDIO == DO_USE_STDIO) { | |
304 | fflush (stdout); | |
305 | } | |
306 | return i; | |
307 | } | |
308 | ||
309 | static device_callbacks const hw_pal_callbacks = { | |
310 | { generic_device_init_address, }, | |
311 | { NULL, }, /* address */ | |
312 | { hw_pal_io_read_buffer_callback, | |
313 | hw_pal_io_write_buffer_callback, }, | |
314 | { NULL, }, /* DMA */ | |
315 | { NULL, }, /* interrupt */ | |
316 | { NULL, }, /* unit */ | |
317 | { hw_pal_instance_create_callback, | |
318 | hw_pal_instance_delete_callback, | |
319 | hw_pal_instance_read_callback, | |
320 | hw_pal_instance_write_callback, }, | |
321 | }; | |
322 | ||
323 | ||
324 | static void * | |
325 | hw_pal_create(const char *name, | |
326 | const device_unit *unit_address, | |
327 | const char *args, | |
328 | device *parent) | |
329 | { | |
330 | /* create the descriptor */ | |
331 | hw_pal_device *hw_pal = ZALLOC(hw_pal_device); | |
332 | hw_pal->output.status = 1; | |
333 | hw_pal->output.buffer = '\0'; | |
334 | hw_pal->input.status = 0; | |
335 | hw_pal->input.buffer = '\0'; | |
336 | return hw_pal; | |
337 | } | |
338 | ||
339 | ||
340 | const device_descriptor hw_pal_device_descriptor[] = { | |
341 | { "pal", hw_pal_create, &hw_pal_callbacks }, | |
342 | { NULL }, | |
343 | }; | |
344 | ||
345 | #endif /* _HW_PAL_C_ */ |