fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/sim405/hook.c *
7 * Created: 2018-12-22 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2018 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include "main.h"
24#include "hook.h"
25#include "msg.h"
26#include "sim405.h"
27
28#include <cpu/ppc405/ppc405.h>
29#include <devices/memory.h>
30
31
32#define PCE_HOOK_CHECK 0x0000
33#define PCE_HOOK_GET_VERSION 0x0001
34#define PCE_HOOK_GET_VERSION_STR 0x0002
35#define PCE_HOOK_INIT 0x0100
36#define PCE_HOOK_PUTC 0x0101
37#define PCE_HOOK_GETC 0x0102
38#define PCE_HOOK_STOP 0x0200
39#define PCE_HOOK_ABORT 0x0201
40#define PCE_HOOK_MSG 0x0300
41#define PCE_HOOK_GET_TIME_UNIX 0x0400
42#define PCE_HOOK_READ_OPEN 0x0500
43#define PCE_HOOK_READ_CLOSE 0x0501
44#define PCE_HOOK_READ 0x0502
45#define PCE_HOOK_WRITE_OPEN 0x0600
46#define PCE_HOOK_WRITE_CLOSE 0x0601
47#define PCE_HOOK_WRITE 0x0602
48
49
50void s405_hook_init (sim405_t *sim)
51{
52 sim->hook_read = NULL;
53 sim->hook_write = NULL;
54
55 sim->hook_idx = 0;
56 sim->hook_cnt = 0;
57}
58
59void s405_hook_free (sim405_t *sim)
60{
61 if (sim->hook_write != NULL) {
62 fclose (sim->hook_write);
63 }
64
65 if (sim->hook_read != NULL) {
66 fclose (sim->hook_read);
67 }
68}
69
70static
71int hook_get_str (sim405_t *sim, char *str, unsigned max)
72{
73 if (sim->hook_cnt >= max) {
74 return (1);
75 }
76
77 memcpy (str, sim->hook_buf, sim->hook_cnt);
78
79 str[sim->hook_cnt] = 0;
80
81 return (0);
82}
83
84static
85int hook_get_str2 (sim405_t *sim, char *str1, char *str2, unsigned max)
86{
87 unsigned i, idx;
88 char *dst;
89
90 dst = str1;
91 idx = 0;
92
93 for (i = 0; i < sim->hook_cnt; i++) {
94 if (idx >= max) {
95 return (1);
96 }
97
98 if (sim->hook_buf[i] == 0) {
99 dst[idx] = 0;
100 dst = str2;
101 idx = 0;
102 }
103 else {
104 dst[idx++] = sim->hook_buf[i];
105 }
106 }
107
108 if (idx >= max) {
109 return (1);
110 }
111
112 dst[idx] = 0;
113
114 return (0);
115}
116
117static
118int hook_set_str (sim405_t *sim, const char *str)
119{
120 unsigned n;
121
122 n = strlen (str);
123
124 if (n > 256) {
125 return (1);
126 }
127
128 memcpy (sim->hook_buf, str, n);
129
130 sim->hook_idx = 0;
131 sim->hook_cnt = n;
132
133 return (0);
134}
135
136static
137void s405_hook_log (sim405_t *sim)
138{
139 pce_log (MSG_DEB,
140 "%08lX: hook (R3=%08lX R4=%08lX)\n",
141 (unsigned long) p405_get_pc (sim->ppc),
142 (unsigned long) p405_get_gpr (sim->ppc, 3),
143 (unsigned long) p405_get_gpr (sim->ppc, 4)
144 );
145}
146
147static
148void s405_hook_check (sim405_t *sim)
149{
150 p405_set_gpr (sim->ppc, 3, 0xffffffce);
151}
152
153static
154void s405_hook_get_version (sim405_t *sim)
155{
156 p405_set_gpr (sim->ppc, 4, PCE_VERSION_MAJ);
157 p405_set_gpr (sim->ppc, 5, PCE_VERSION_MIN);
158 p405_set_gpr (sim->ppc, 6, PCE_VERSION_MIC);
159
160 p405_set_gpr (sim->ppc, 3, 0);
161}
162
163static
164void s405_hook_get_version_str (sim405_t *sim)
165{
166 p405_set_gpr (sim->ppc, 3, -1);
167
168 if (hook_set_str (sim, PCE_VERSION_STR)) {
169 return;
170 }
171
172 p405_set_gpr (sim->ppc, 3, 0);
173}
174
175static
176void s405_hook_initc (sim405_t *sim)
177{
178 sim->hook_idx = 0;
179 sim->hook_cnt = 0;
180
181 p405_set_gpr (sim->ppc, 3, 0);
182}
183
184static
185void s405_hook_putc (sim405_t *sim)
186{
187 p405_set_gpr (sim->ppc, 3, -1);
188
189 if (sim->hook_cnt >= 256) {
190 return;
191 }
192
193 sim->hook_buf[sim->hook_cnt++] = p405_get_gpr (sim->ppc, 4) & 0xff;
194
195 p405_set_gpr (sim->ppc, 3, 0);
196}
197
198static
199void s405_hook_getc (sim405_t *sim)
200{
201 if (sim->hook_idx >= sim->hook_cnt) {
202 p405_set_gpr (sim->ppc, 3, -1);
203 return;
204 }
205
206 p405_set_gpr (sim->ppc, 3, sim->hook_buf[sim->hook_idx++]);
207}
208
209static
210void s405_hook_stop (sim405_t *sim)
211{
212 sim->brk = 1;
213 p405_set_gpr (sim->ppc, 3, 0);
214}
215
216static
217void s405_hook_abort (sim405_t *sim)
218{
219 sim->brk = 2;
220 p405_set_gpr (sim->ppc, 3, 0);
221}
222
223static
224void s405_hook_msg (sim405_t *sim)
225{
226 char msg[256], val[256];
227
228 p405_set_gpr (sim->ppc, 3, -1);
229
230 if (hook_get_str2 (sim, msg, val, 256)) {
231 return;
232 }
233
234 if (s405_set_msg (sim, msg, val)) {
235 return;
236 }
237
238 p405_set_gpr (sim->ppc, 3, 0);
239}
240
241static
242void s405_hook_get_time_unix (sim405_t *sim)
243{
244 unsigned long long tm;
245
246 tm = (unsigned long long) time (NULL);
247
248 p405_set_gpr (sim->ppc, 4, (tm >> 32) & 0xffffffff);
249 p405_set_gpr (sim->ppc, 5, tm & 0xffffffff);
250
251 p405_set_gpr (sim->ppc, 3, 0);
252}
253
254static
255void s405_hook_read_open (sim405_t *sim)
256{
257 char str[256];
258
259 p405_set_gpr (sim->ppc, 3, 0xffffffff);
260
261 if (hook_get_str (sim, str, 256)) {
262 return;
263 }
264
265 if (sim->hook_read != NULL) {
266 fclose (sim->hook_read);
267 }
268
269 if ((sim->hook_read = fopen (str, "rb")) == NULL) {
270 return;
271 }
272
273 p405_set_gpr (sim->ppc, 3, 0);
274}
275
276static
277void s405_hook_read_close (sim405_t *sim)
278{
279 p405_set_gpr (sim->ppc, 3, 0xffffffff);
280
281 if (sim->hook_read != NULL) {
282 fclose (sim->hook_read);
283 sim->hook_read = NULL;
284 }
285
286 p405_set_gpr (sim->ppc, 3, 0);
287}
288
289static
290void s405_hook_read (sim405_t *sim)
291{
292 p405_t *c;
293 unsigned n;
294 unsigned char buf[16];
295
296 c = sim->ppc;
297
298 if (sim->hook_read == NULL) {
299 p405_set_gpr (c, 3, 0xffffffff);
300 return;
301 }
302
303 memset (buf, 0, 16);
304
305 n = fread (buf, 1, 16, sim->hook_read);
306
307 p405_set_gpr (c, 4, buf_get_uint32_be (buf, 0));
308 p405_set_gpr (c, 5, buf_get_uint32_be (buf, 4));
309 p405_set_gpr (c, 6, buf_get_uint32_be (buf, 8));
310 p405_set_gpr (c, 7, buf_get_uint32_be (buf, 12));
311
312 p405_set_gpr (c, 3, n);
313}
314
315static
316void s405_hook_write_open (sim405_t *sim)
317{
318 char str[256];
319
320 p405_set_gpr (sim->ppc, 3, 0xffffffff);
321
322 if (hook_get_str (sim, str, 256)) {
323 return;
324 }
325
326 if (sim->hook_write != NULL) {
327 fclose (sim->hook_write);
328 }
329
330 if ((sim->hook_write = fopen (str, "wb")) == NULL) {
331 return;
332 }
333
334 p405_set_gpr (sim->ppc, 3, 0);
335}
336
337static
338void s405_hook_write_close (sim405_t *sim)
339{
340 p405_set_gpr (sim->ppc, 3, 0xffffffff);
341
342 if (sim->hook_write != NULL) {
343 fclose (sim->hook_write);
344 sim->hook_write = NULL;
345 }
346
347 p405_set_gpr (sim->ppc, 3, 0);
348}
349
350static
351void s405_hook_write (sim405_t *sim)
352{
353 unsigned n;
354 unsigned char buf[16];
355
356 p405_set_gpr (sim->ppc, 3, 0xffffffff);
357
358 if (sim->hook_write == NULL) {
359 return;
360 }
361
362 n = p405_get_gpr (sim->ppc, 8);
363
364 if ((n == 0) || (n > 16)) {
365 return;
366 }
367
368 buf_set_uint32_be (buf, 0, p405_get_gpr (sim->ppc, 4));
369 buf_set_uint32_be (buf, 4, p405_get_gpr (sim->ppc, 5));
370 buf_set_uint32_be (buf, 8, p405_get_gpr (sim->ppc, 6));
371 buf_set_uint32_be (buf, 12, p405_get_gpr (sim->ppc, 7));
372
373 n = fwrite (buf, 1, n, sim->hook_write);
374
375 p405_set_gpr (sim->ppc, 3, n);
376}
377
378void s405_hook (sim405_t *sim, unsigned long ir)
379{
380 switch (p405_get_gpr (sim->ppc, 3)) {
381 case PCE_HOOK_CHECK:
382 s405_hook_check (sim);
383 break;
384
385 case PCE_HOOK_GET_VERSION:
386 s405_hook_get_version (sim);
387 break;
388
389 case PCE_HOOK_GET_VERSION_STR:
390 s405_hook_get_version_str (sim);
391 break;
392
393 case PCE_HOOK_INIT:
394 s405_hook_initc (sim);
395 break;
396
397 case PCE_HOOK_PUTC:
398 s405_hook_putc (sim);
399 break;
400
401 case PCE_HOOK_GETC:
402 s405_hook_getc (sim);
403 break;
404
405 case PCE_HOOK_STOP:
406 s405_hook_stop (sim);
407 break;
408
409 case PCE_HOOK_ABORT:
410 s405_hook_abort (sim);
411 break;
412
413 case PCE_HOOK_MSG:
414 s405_hook_msg (sim);
415 break;
416
417 case PCE_HOOK_GET_TIME_UNIX:
418 s405_hook_get_time_unix (sim);
419 break;
420
421 case PCE_HOOK_READ_OPEN:
422 s405_hook_read_open (sim);
423 break;
424
425 case PCE_HOOK_READ_CLOSE:
426 s405_hook_read_close (sim);
427 break;
428
429 case PCE_HOOK_READ:
430 s405_hook_read (sim);
431 break;
432
433 case PCE_HOOK_WRITE_OPEN:
434 s405_hook_write_open (sim);
435 break;
436
437 case PCE_HOOK_WRITE_CLOSE:
438 s405_hook_write_close (sim);
439 break;
440
441 case PCE_HOOK_WRITE:
442 s405_hook_write (sim);
443 break;
444
445 default:
446 s405_hook_log (sim);
447 p405_set_gpr (sim->ppc, 3, 0xffffffff);
448 break;
449 }
450}