fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 450 lines 8.6 kB view raw
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}