/***************************************************************************** * pce * *****************************************************************************/ /***************************************************************************** * File name: src/arch/macplus/macplus.c * * Created: 2007-04-15 by Hampa Hug * * Copyright: (C) 2007-2024 Hampa Hug * *****************************************************************************/ /***************************************************************************** * This program is free software. You can redistribute it and / or modify it * * under the terms of the GNU General Public License version 2 as published * * by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY, without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * * Public License for more details. * *****************************************************************************/ #include "main.h" #include "hook.h" #include "hotkey.h" #include "iwm.h" #include "keyboard.h" #include "macplus.h" #include "mem.h" #include "msg.h" #include "rtc.h" #include "scsi.h" #include "serial.h" #include "sony.h" #include "sound.h" #include "video.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* The CPU is synchronized with real time MAC_CPU_SYNC times per seconds */ #define MAC_CPU_SYNC 250 #ifdef PCE_HOST_WINDOWS #define MAC_CPU_SLEEP 20000 #else #define MAC_CPU_SLEEP 10000 #endif static unsigned char par_classic_pwm[64] = { 0x00, 0x01, 0x3b, 0x02, 0x3c, 0x28, 0x36, 0x03, 0x3d, 0x20, 0x31, 0x29, 0x37, 0x13, 0x23, 0x04, 0x3e, 0x34, 0x1e, 0x21, 0x32, 0x0c, 0x0e, 0x2a, 0x38, 0x10, 0x1b, 0x14, 0x24, 0x17, 0x2c, 0x05, 0x3f, 0x3a, 0x27, 0x35, 0x1f, 0x30, 0x12, 0x22, 0x33, 0x1d, 0x0b, 0x0d, 0x0f, 0x1a, 0x16, 0x2b, 0x39, 0x26, 0x2f, 0x11, 0x1c, 0x0a, 0x19, 0x15, 0x25, 0x2e, 0x09, 0x18, 0x2d, 0x08, 0x07, 0x06 }; static void mac_classic_set_pwm (macplus_t *sim, const unsigned char *buf, unsigned cnt) { unsigned i, v; v = 0; for (i = 0; i < cnt; i++) { v += par_classic_pwm[buf[0] & 0x3f]; } v = v / cnt; if (v < 1) { v = 1; } else if (v > 31) { v = 31; } v = 32 + (223 * (30 - (v - 1)) + 15) / 30; if ((sim->video != NULL) && (sim->video->brightness != v)) { mac_video_set_brightness (sim->video, v); } } static void mac_interrupt_check (macplus_t *sim) { unsigned i; unsigned val; val = sim->intr >> 1; i = 0; while (val != 0) { i += 1; val = val >> 1; } #ifdef DEBUG_INT mac_log_deb ("interrupt level %u\n", i); #endif e68_interrupt (sim->cpu, i); } void mac_interrupt (macplus_t *sim, unsigned level, int val) { if (val) { sim->intr |= (1U << level); } else { sim->intr &= ~(1U << level); } mac_interrupt_check (sim); } static void mac_interrupt_via (void *ext, unsigned char val) { macplus_t *sim = ext; if (val) { sim->intr_scsi_via |= 1; } else { sim->intr_scsi_via &= ~1; } mac_interrupt (ext, 1, sim->intr_scsi_via); } static void mac_interrupt_scsi (void *ext, unsigned char val) { macplus_t *sim = ext; if (sim->via_port_b & 0x40) { val = 0; } else { val = (val != 0); } if (val) { sim->intr_scsi_via |= 2; } else { sim->intr_scsi_via &= ~2; } mac_interrupt (sim, 1, sim->intr_scsi_via); } static void mac_interrupt_scc (void *ext, unsigned char val) { mac_interrupt (ext, 2, val); } static void mac_interrupt_vbi (void *ext, unsigned char val) { unsigned i; unsigned char pbuf[370]; macplus_t *sim = ext; if (val) { e6522_set_ca1_inp (&sim->via, 0); e6522_set_ca1_inp (&sim->via, 1); mac_sound_vbl (&sim->sound); for (i = 0; i < 370; i++) { pbuf[i] = mem_get_uint8 (sim->mem, sim->sbuf1 + i + 1); } if (sim->model & PCE_MAC_CLASSIC) { mac_classic_set_pwm (sim, pbuf, 370); } else { mac_iwm_set_pwm (&sim->iwm, pbuf, 370); } } } static void mac_interrupt_sony_check (macplus_t *sim) { unsigned long a7; #ifdef DEBUG_SONY mac_log_deb ("sony: check\n"); #endif if (e68_get_iml (sim->cpu) == 7) { #ifdef DEBUG_SONY mac_log_deb ("sony: check aborted (iml=7)\n"); #endif return; } a7 = e68_get_areg32 (sim->cpu, 7); e68_set_mem32 (sim->cpu, a7 - 4, e68_get_pc (sim->cpu)); e68_set_areg32 (sim->cpu, 7, a7 - 4); e68_set_pc_prefetch (sim->cpu, sim->sony.check_addr); } void mac_interrupt_osi (void *ext, unsigned char val) { macplus_t *sim = ext; if (val) { if (mac_sony_check (&sim->sony)) { mac_interrupt_sony_check (sim); } e6522_set_ca2_inp (&sim->via, 0); e6522_set_ca2_inp (&sim->via, 1); } } static void mac_set_reset (void *ext, unsigned char val) { if (val == 0) { return; } mac_reset (ext); } static void mac_ram_write (void *ext, uint32_t addr, unsigned size) { macplus_t *sim = ext; if (sim->video == NULL) { return; } if ((addr + size) > sim->video->vbuf_addr && addr < (sim->video->vbuf_addr + sim->video->vbuf_size)) { mac_video_set_dirty (sim->video); } } static void mac_set_vbuf (macplus_t *sim, unsigned long addr) { unsigned char *vbuf; unsigned long vbuf_size; mem_blk_t *blk; vbuf_size = ((unsigned long)(sim->video->w + 7) / 8) * sim->video->h; if (addr < mem_blk_get_size (sim->ram)) { vbuf = mem_blk_get_data (sim->ram) + addr; } else { blk = mem_get_blk (sim->mem, addr); if (blk == NULL) { mac_video_set_vbuf (sim->video, NULL); mac_video_set_vbuf_addr (sim->video, 0, 0); return; } vbuf = mem_blk_get_data (blk); vbuf += mem_blk_get_addr (blk) - sim->vbuf1; } mac_video_set_vbuf (sim->video, vbuf); mac_video_set_vbuf_addr (sim->video, addr, vbuf_size); } static void mac_check_mouse (macplus_t *sim) { if (sim->adb != NULL) { return; } if ((sim->mouse_delta_x <= -2) || (sim->mouse_delta_x >= 2)) { if (sim->dcd_a) { sim->via_port_b &= ~0x10; } else { sim->via_port_b |= 0x10; } if (sim->mouse_delta_x > 0) { sim->via_port_b ^= 0x10; sim->mouse_delta_x -= 2; } else { sim->mouse_delta_x += 2; } e6522_set_irb_inp (&sim->via, sim->via_port_b); e8530_set_dcd_a (&sim->scc, sim->dcd_a); sim->dcd_a = !sim->dcd_a; } if ((sim->mouse_delta_y <= -2) || (sim->mouse_delta_y >= 2)) { if (sim->dcd_b) { sim->via_port_b &= ~0x20; } else { sim->via_port_b |= 0x20; } if (sim->mouse_delta_y > 0) { sim->mouse_delta_y -= 2; } else { sim->via_port_b ^= 0x20; sim->mouse_delta_y += 2; } e6522_set_irb_inp (&sim->via, sim->via_port_b); e8530_set_dcd_b (&sim->scc, sim->dcd_b); sim->dcd_b = !sim->dcd_b; } } static void mac_set_mouse (void *ext, int dx, int dy, unsigned but) { macplus_t *sim = ext; unsigned char old; if (sim->pause) { if (but) { mac_set_pause (sim, 0); } return; } if ((sim->mouse_button ^ but) & ~but & 4) { mac_set_msg (sim, "term.release", "1"); } sim->mouse_button = but; if (sim->adb_mouse != NULL) { adb_mouse_move (sim->adb_mouse, but, dx, dy); return; } old = sim->via_port_b; if (but & 1) { sim->via_port_b &= 0xf7; } else { sim->via_port_b |= 0x08; } if (sim->via_port_b != old) { e6522_set_irb_inp (&sim->via, sim->via_port_b); } sim->mouse_delta_x += dx; sim->mouse_delta_y += dy; } static void mac_get_mouse (void *ext, int *x, int *y) { macplus_t *sim = ext; /* RawMouse low-memory global at 0x82c */ *y = (int) mem_get_uint16_be (sim->mem, 0x82c); *x = (int) mem_get_uint16_be (sim->mem, 0x82e); } static void mac_set_key (void *ext, unsigned event, pce_key_t key) { macplus_t *sim = ext; if (event == PCE_KEY_EVENT_MAGIC) { mac_set_hotkey (sim, key); return; } if (sim->kbd != NULL) { mac_kbd_set_key (sim->kbd, event, key); } if (sim->adb_kbd != NULL) { adb_kbd_set_key (sim->adb_kbd, event, key); } } static void mac_set_adb_int (void *ext, unsigned char val) { macplus_t *sim = ext; if (val) { sim->via_port_b &= ~0x08; } else { sim->via_port_b |= 0x08; } e6522_set_irb_inp (&sim->via, sim->via_port_b); } static void mac_set_iwm_motor (void *ext, unsigned char val) { macplus_t *sim = ext; mac_set_speed (sim, PCE_MAC_SPEED_IWM, val ? 4 : 0); } static void mac_set_rtc_data (void *ext, unsigned char val) { macplus_t *sim = ext; if (val) { sim->via_port_b |= 0x01; } else { sim->via_port_b &= ~0x01; } e6522_set_irb_inp (&sim->via, sim->via_port_b); } static void mac_set_via_port_a (void *ext, unsigned char val) { macplus_t *sim = ext; unsigned char old; if (sim->via_port_a == val) { return; } #ifdef DEBUG_VIA mac_log_deb ("via: set port a: %02X\n", val); #endif old = sim->via_port_a; sim->via_port_a = val; if ((old ^ val) & 0x10) { if (sim->model & PCE_MAC_PLUS) { mac_set_overlay (sim, (val & 0x10) != 0); } else if (sim->model & (PCE_MAC_SE | PCE_MAC_CLASSIC)) { mac_iwm_set_drive_sel (&sim->iwm, (val & 0x10) != 0); } } if ((old ^ val) & 0x20) { mac_iwm_set_head_sel (&sim->iwm, (val & 0x20) != 0); } if ((old ^ val) & 0x40) { unsigned long addr; if (val & 0x40) { mac_log_deb ("main video buffer\n"); addr = sim->vbuf1; } else { mac_log_deb ("alternate video buffer\n"); addr = sim->vbuf2; } mac_set_vbuf (sim, addr); } if ((old ^ val) & 0x08) { if (sim->model & PCE_MAC_PLUS) { unsigned char *sbuf; sbuf = mem_blk_get_data (sim->ram); if (val & 0x08) { mac_log_deb ("main sound buffer\n"); sbuf += sim->sbuf1; } else { mac_log_deb ("alternate sound buffer\n"); sbuf += sim->sbuf2; } mac_sound_set_sbuf (&sim->sound, sbuf); } } if ((old ^ val) & 0x07) { mac_sound_set_volume (&sim->sound, val & 7); } } static void mac_set_via_port_b (void *ext, unsigned char val) { macplus_t *sim = ext; unsigned char old; if (sim->via_port_b == val) { return; } #ifdef DEBUG_VIA mac_log_deb ("via: set port b: %02X\n", val); #endif old = sim->via_port_b; sim->via_port_b = val; mac_rtc_set_uint8 (&sim->rtc, val); if ((old ^ val) & 0x80) { mac_sound_set_enable (&sim->sound, (val & 0x80) == 0); } if (sim->adb != NULL) { mac_adb_set_state (sim->adb, (val >> 4) & 3); } } static unsigned char mac_scc_get_uint8 (void *ext, unsigned long addr) { unsigned char val; macplus_t *sim = ext; val = 0xff; switch (addr) { case 0x1ffff8: val = e8530_get_ctl_b (&sim->scc); break; case 0x1ffffa: val = e8530_get_ctl_a (&sim->scc); break; case 0x1ffffc: val = e8530_get_data_b (&sim->scc); break; case 0x1ffffe: val = e8530_get_data_a (&sim->scc); break; } #ifdef DEBUG_SCC mac_log_deb ("scc: get 8: %06lX -> %02X\n", addr, val); #endif return (val); } static void mac_scc_set_uint8 (void *ext, unsigned long addr, unsigned char val) { macplus_t *sim = ext; #ifdef DEBUG_SCC mac_log_deb ("scc: set 8: %06lX <- %02X\n", addr, val); #endif switch (addr) { case 0x3ffff9: e8530_set_ctl_b (&sim->scc, val); break; case 0x3ffffb: e8530_set_ctl_a (&sim->scc, val); break; case 0x3ffffd: e8530_set_data_b (&sim->scc, val); break; case 0x3fffff: e8530_set_data_a (&sim->scc, val); break; } } static void mac_setup_system (macplus_t *sim, ini_sct_t *ini) { int memtest; const char *model; ini_sct_t *sct; if ((sct = ini_next_sct (ini, NULL, "system")) == NULL) { sct = ini; } ini_get_string (sct, "model", &model, "mac-plus"); if (ini_get_bool (sct, "memtest", &memtest, 1)) { ini_get_bool (ini, "memtest", &memtest, 1); } pce_log_tag (MSG_INF, "SYSTEM:", "model=%s memtest=%d\n", model, memtest ); if (strcmp (model, "mac-128k") == 0) { sim->model = PCE_MAC_PLUS; } else if (strcmp (model, "mac-512k") == 0) { sim->model = PCE_MAC_PLUS; } else if (strcmp (model, "mac-plus") == 0) { sim->model = PCE_MAC_PLUS; } else if (strcmp (model, "mac-se") == 0) { sim->model = PCE_MAC_SE; } else if (strcmp (model, "mac-classic") == 0) { sim->model = PCE_MAC_CLASSIC; } else { pce_log (MSG_ERR, "*** unknown model (%s)\n", model); sim->model = PCE_MAC_PLUS; } sim->memtest = (memtest != 0); } static void mac_setup_mem (macplus_t *sim, ini_sct_t *ini) { sim->mem = mem_new(); mem_set_fct (sim->mem, sim, mac_mem_get_uint8, mac_mem_get_uint16, mac_mem_get_uint32, mac_mem_set_uint8, mac_mem_set_uint16, mac_mem_set_uint32 ); ini_get_ram (sim->mem, ini, &sim->ram); ini_get_rom (sim->mem, ini); sim->ram = mem_get_blk (sim->mem, 0x00000000); sim->rom = mem_get_blk (sim->mem, 0x00400000); sim->ram_ovl = NULL; sim->rom_ovl = NULL; if (sim->ram == NULL) { pce_log (MSG_ERR, "*** RAM not found at 000000\n"); return; } if (sim->rom == NULL) { pce_log (MSG_ERR, "*** ROM not found at 400000\n"); return; } sim->ram_ovl = mem_blk_clone (sim->ram); mem_blk_set_addr (sim->ram_ovl, 0x00600000); if (mem_blk_get_size (sim->ram_ovl) > 0x00200000) { mem_blk_set_size (sim->ram_ovl, 0x00200000); } sim->rom_ovl = mem_blk_clone (sim->rom); mem_blk_set_addr (sim->rom_ovl, 0); sim->overlay = 0; if (sim->memtest == 0) { pce_log_tag (MSG_INF, "RAM:", "disabling memory test\n"); if (sim->model & PCE_MAC_PLUS) { mem_set_uint32_be (sim->mem, 0x02ae, 0x00400000); } else if (sim->model & (PCE_MAC_SE | PCE_MAC_CLASSIC)) { mem_set_uint32_be (sim->mem, 0x0cfc, 0x574c5343); } } } static void mac_setup_cpu (macplus_t *sim, ini_sct_t *ini) { ini_sct_t *sct; const char *model; unsigned speed; sct = ini_next_sct (ini, NULL, "cpu"); ini_get_string (sct, "model", &model, "68000"); ini_get_uint16 (sct, "speed", &speed, 0); pce_log_tag (MSG_INF, "CPU:", "model=%s speed=%d\n", model, speed); sim->cpu = e68_new(); if (sim->cpu == NULL) { return; } if (mac_set_cpu_model (sim, model)) { pce_log (MSG_ERR, "*** unknown cpu model (%s)\n", model); } e68_set_mem_fct (sim->cpu, sim->mem, &mem_get_uint8, &mem_get_uint16_be, &mem_get_uint32_be, &mem_set_uint8, &mem_set_uint16_be, &mem_set_uint32_be ); e68_set_reset_fct (sim->cpu, sim, mac_set_reset); e68_set_hook_fct (sim->cpu, sim, mac_hook); e68_set_address_check (sim->cpu, 0); sim->speed_factor = speed; sim->speed_limit[PCE_MAC_SPEED_USER] = speed; } static void mac_setup_via (macplus_t *sim, ini_sct_t *ini) { ini_sct_t *sct; mem_blk_t *blk; unsigned long addr, size; sct = ini_next_sct (ini, NULL, "via"); ini_get_uint32 (sct, "address", &addr, 0x00efe000); ini_get_uint32 (sct, "size", &size, 16 * 512); pce_log_tag (MSG_INF, "VIA:", "addr=0x%06lx size=0x%lx\n", addr, size); e6522_init (&sim->via, 9); e6522_set_irq_fct (&sim->via, sim, mac_interrupt_via); e6522_set_ora_fct (&sim->via, sim, mac_set_via_port_a); e6522_set_orb_fct (&sim->via, sim, mac_set_via_port_b); blk = mem_blk_new (addr, size, 0); if (blk == NULL) { return; } mem_blk_set_fct (blk, &sim->via, e6522_get_uint8, e6522_get_uint16, e6522_get_uint32, e6522_set_uint8, e6522_set_uint16, e6522_set_uint32 ); mem_add_blk (sim->mem, blk, 1); } static void mac_setup_scc (macplus_t *sim, ini_sct_t *ini) { ini_sct_t *sct; mem_blk_t *blk; unsigned long addr, size; sct = ini_next_sct (ini, NULL, "scc"); ini_get_uint32 (sct, "address", &addr, 0x800000); ini_get_uint32 (sct, "size", &size, 0x400000); pce_log_tag (MSG_INF, "SCC:", "addr=0x%06lx size=0x%lx\n", addr, size); e8530_init (&sim->scc); e8530_set_irq_fct (&sim->scc, sim, mac_interrupt_scc); e8530_set_clock (&sim->scc, 3672000, 3672000, 3672000); blk = mem_blk_new (addr, size, 0); if (blk == NULL) { return; } mem_blk_set_fct (blk, sim, mac_scc_get_uint8, NULL, NULL, mac_scc_set_uint8, NULL, NULL ); mem_add_blk (sim->mem, blk, 1); } static void mac_setup_serial (macplus_t *sim, ini_sct_t *ini) { ini_sct_t *sct; unsigned port; unsigned multichar; const char *driver; mac_ser_init (&sim->ser[0]); mac_ser_set_scc (&sim->ser[0], &sim->scc, 0); mac_ser_init (&sim->ser[1]); mac_ser_set_scc (&sim->ser[1], &sim->scc, 1); sct = ini_next_sct (ini, NULL, "serial"); while (sct != NULL) { ini_get_uint16 (sct, "port", &port, 0); ini_get_uint16 (sct, "multichar", &multichar, 1); ini_get_string (sct, "driver", &driver, NULL); pce_log_tag (MSG_INF, "SERIAL:", "port=%u multichar=%u driver=%s\n", port, multichar, (driver != NULL) ? driver : "" ); sct = ini_next_sct (ini, sct, "serial"); if (port > 1) { pce_log (MSG_ERR, "*** bad port number (%u)\n", port); continue; } e8530_set_multichar (&sim->scc, port, multichar, multichar); if (driver != NULL) { if (mac_ser_set_driver (&sim->ser[port], driver)) { pce_log (MSG_ERR, "*** can't open driver (%s)\n", driver); } } } } static void mac_setup_rtc (macplus_t *sim, ini_sct_t *ini) { ini_sct_t *sct; const char *fname; const char *start; int localtime, realtime, romdisk, atalk; unsigned volume; sct = ini_next_sct (ini, NULL, "rtc"); ini_get_string (sct, "file", &fname, "pram.dat"); ini_get_bool (sct, "localtime", &localtime, 0); ini_get_bool (sct, "realtime", &realtime, 1); ini_get_bool (sct, "romdisk", &romdisk, 0); ini_get_uint16 (sct, "volume", &volume, 0xff); ini_get_string (sct, "start", &start, NULL); if (ini_get_bool (sct, "appletalk", &atalk, 0)) { atalk = -1; } pce_log_tag (MSG_INF, "RTC:", "file=%s localtime=%d realtime=%d start=%s romdisk=%d " "atalk=%d volume=%u\n", fname, localtime, realtime, (start != NULL) ? start : "", romdisk, atalk, volume ); sim->rtc_fname = strdup (fname); mac_rtc_init (&sim->rtc); mac_rtc_set_data_fct (&sim->rtc, sim, mac_set_rtc_data); mac_rtc_set_osi_fct (&sim->rtc, sim, mac_interrupt_osi); if (localtime) { mac_rtc_set_time_gmtoff (&sim->rtc); } mac_rtc_set_realtime (&sim->rtc, realtime); if (mac_rtc_load_file (&sim->rtc, fname)) { pce_log (MSG_ERR, "*** reading rtc file failed\n"); } if (romdisk) { sim->rtc.data[0x78] = 0x00; sim->rtc.data[0x79] = 0x06; sim->rtc.data[0x7a] = 0xff; sim->rtc.data[0x7b] = 0xcb; } if (atalk == 0) { sim->rtc.data[0x13] = 0x22; } else if (atalk == 1) { sim->rtc.data[0x13] = 0x21; } if (volume < 8) { sim->rtc.data[0x08] &= 0xf8; sim->rtc.data[0x08] |= (volume & 7); } if (start != NULL) { mac_rtc_set_time_str (&sim->rtc, start); } else { mac_rtc_set_time_now (&sim->rtc); } } static void mac_setup_kbd (macplus_t *sim, ini_sct_t *ini) { ini_sct_t *sct; unsigned model; int intl, motion; sim->kbd = NULL; if ((sim->model & PCE_MAC_PLUS) == 0) { return; } sct = ini_next_sct (ini, NULL, "keyboard"); ini_get_uint16 (sct, "model", &model, 1); ini_get_bool (sct, "intl", &intl, 0); ini_get_bool (sct, "keypad_motion", &motion, 0); pce_log_tag (MSG_INF, "KEYBOARD:", "model=%u international=%d keypad=%s\n", model, intl, motion ? "motion" : "keypad" ); sim->kbd = mac_kbd_new(); if (sim->kbd == NULL) { return; } mac_kbd_set_model (sim->kbd, model, intl); mac_kbd_set_keypad_mode (sim->kbd, motion); mac_kbd_set_data_fct (sim->kbd, &sim->via, e6522_set_shift_inp); mac_kbd_set_intr_fct (sim->kbd, sim, mac_interrupt); e6522_set_shift_out_fct (&sim->via, sim->kbd, mac_kbd_set_uint8); e6522_set_cb2_fct (&sim->via, sim->kbd, mac_kbd_set_data); } static void mac_setup_adb (macplus_t *sim, ini_sct_t *ini) { ini_sct_t *sct; int mouse, keyboard, motion; sim->adb = NULL; sim->adb_mouse = NULL; sim->adb_kbd = NULL; if ((sim->model & (PCE_MAC_SE | PCE_MAC_CLASSIC)) == 0) { return; } sct = ini_next_sct (ini, NULL, "adb"); ini_get_bool (sct, "mouse", &mouse, 1); ini_get_bool (sct, "keyboard", &keyboard, 1); ini_get_bool (sct, "keypad_motion", &motion, 0); pce_log_tag (MSG_INF, "ADB:", "enabled\n"); sim->adb = mac_adb_new(); if (sim->adb == NULL) { pce_log (MSG_ERR, "*** can't create adb\n"); return; } adb_set_shift_in_fct (sim->adb, &sim->via, e6522_shift_in); adb_set_shift_out_fct (sim->adb, &sim->via, e6522_shift_out); adb_set_int_fct (sim->adb, sim, mac_set_adb_int); if (mouse) { pce_log_tag (MSG_INF, "ADB:", "mouse\n"); sim->adb_mouse = adb_mouse_new(); if (sim->adb_mouse != NULL) { adb_add_device (sim->adb, &sim->adb_mouse->dev); } } if (keyboard) { pce_log_tag (MSG_INF, "ADB:", "keyboard keypad_mode=%s\n", motion ? "motion" : "keypad" ); sim->adb_kbd = adb_kbd_new(); if (sim->adb_kbd != NULL) { adb_kbd_set_keypad_mode (sim->adb_kbd, motion); adb_add_device (sim->adb, &sim->adb_kbd->dev); } } } static void mac_setup_disks (macplus_t *sim, ini_sct_t *ini) { sim->dsks = ini_get_disks (ini); } static void mac_setup_iwm (macplus_t *sim, ini_sct_t *ini) { unsigned n; int single, rotate, inserted, pwm; unsigned drive, disk; ini_sct_t *sct, *sctdev; sct = ini_next_sct (ini, NULL, "iwm"); mac_iwm_init (&sim->iwm); mac_iwm_set_motor_fct (&sim->iwm, sim, mac_set_iwm_motor); mac_iwm_set_disks (&sim->iwm, sim->dsks); pce_log_tag (MSG_INF, "IWM:", "addr=0x%06lx\n", 0xd00000UL); sctdev = ini_next_sct (sct, NULL, "drive"); n = 0; while (sctdev != NULL) { ini_get_uint16 (sctdev, "drive", &drive, n); ini_get_uint16 (sctdev, "disk", &disk, drive); ini_get_bool (sct, "single_sided", &single, 0); ini_get_bool (sctdev, "single_sided", &single, single); ini_get_bool (sct, "pwm", &pwm, 1); ini_get_bool (sctdev, "pwm", &pwm, pwm); ini_get_bool (sct, "inserted", &inserted, 0); ini_get_bool (sctdev, "inserted", &inserted, inserted); if ((drive >= 1) && (drive <= 8)) { if (par_disk_boot & (1U << (drive - 1))) { inserted = 1; } } ini_get_bool (sct, "auto_rotate", &rotate, 0); ini_get_bool (sctdev, "auto_rotate", &rotate, rotate); pce_log_tag (MSG_INF, "IWM:", "drive=%u size=%uK pwm=%d ins=%d rotate=%d disk=%u\n", drive, single ? 400 : 800, pwm, inserted, rotate, disk ); mac_iwm_enable_pwm (&sim->iwm, drive - 1, pwm); mac_iwm_set_heads (&sim->iwm, drive - 1, single ? 1 : 2); mac_iwm_set_disk_id (&sim->iwm, drive - 1, disk); mac_iwm_set_auto_rotate (&sim->iwm, drive - 1, rotate); if (inserted) { mac_iwm_insert (&sim->iwm, drive - 1); } n = drive + 1; sctdev = ini_next_sct (sct, sctdev, "drive"); } } static void mac_setup_scsi (macplus_t *sim, ini_sct_t *ini) { ini_sct_t *sct, *sctdev; mem_blk_t *blk; unsigned long addr, size; unsigned id, drive, daynaport; const char *vendor, *product, *mac_addr, *tap_dev, *tap_cmd, *bridged_if; sct = ini_next_sct (ini, NULL, "scsi"); if (sct == NULL) { return; } ini_get_uint32 (sct, "address", &addr, 0x580000); ini_get_uint32 (sct, "size", &size, 0x80000); pce_log_tag (MSG_INF, "SCSI:", "addr=0x%06lx size=0x%lx\n", addr, size); mac_scsi_init (&sim->scsi); if (sim->model & PCE_MAC_SE) { mac_scsi_set_int_fct (&sim->scsi, sim, mac_interrupt_scsi); } mac_scsi_set_disks (&sim->scsi, sim->dsks); blk = mem_blk_new (addr, size, 0); if (blk == NULL) { return; } mem_blk_set_fct (blk, &sim->scsi, mac_scsi_get_uint8, mac_scsi_get_uint16, NULL, mac_scsi_set_uint8, mac_scsi_set_uint16, NULL ); mem_add_blk (sim->mem, blk, 1); sctdev = ini_next_sct (sct, NULL, "device"); while (sctdev != NULL) { ini_get_uint16 (sctdev, "id", &id, 0); ini_get_uint16 (sctdev, "drive", &drive, 0); ini_get_uint16 (sctdev, "daynaport", &daynaport, 0); if (drive) { ini_get_string (sctdev, "vendor", &vendor, "PCE"); ini_get_string (sctdev, "product", &product, "PCEDISK"); pce_log_tag (MSG_INF, "SCSI:", "id=%u drive=%u vendor=\"%s\" product=\"%s\"\n", id, drive, vendor, product ); mac_scsi_set_drive (&sim->scsi, id, drive); mac_scsi_set_drive_vendor (&sim->scsi, id, vendor); mac_scsi_set_drive_product (&sim->scsi, id, product); } else if (daynaport) { ini_get_string (sctdev, "tap", &tap_dev, "/dev/tap0"); ini_get_string (sctdev, "tap_cmd", &tap_cmd, ""); ini_get_string (sctdev, "mac_addr", &mac_addr, "00:80:19:c0:ff:ee"); ini_get_string (sctdev, "bridged_if", &bridged_if, ""); pce_log_tag (MSG_INF, "SCSI:", #if PCE_ENABLE_VMNET "id=%u daynaport=%u bridged=%s mac_addr=%s\n", id, daynaport, bridged_if, mac_addr #else "id=%u daynaport=%u tap=%s cmd=%s mac_addr=%s\n", id, daynaport, tap_dev, tap_cmd, mac_addr #endif ); mac_scsi_set_daynaport (&sim->scsi, id, tap_dev, tap_cmd, mac_addr, bridged_if); } sctdev = ini_next_sct (sct, sctdev, "device"); } } static void mac_setup_sony (macplus_t *sim, ini_sct_t *ini) { unsigned i; int format_hd_as_dd; char var[32]; unsigned def, val; ini_sct_t *sct; sct = ini_next_sct (ini, NULL, "sony"); ini_get_uint16 (sct, "insert_delay", &def, 0); ini_get_bool (sct, "format_hd_as_dd", &format_hd_as_dd, 0); mac_sony_init (&sim->sony, sct != NULL); mac_sony_set_mem (&sim->sony, sim->mem); mac_sony_set_disks (&sim->sony, sim->dsks); sim->sony.format_hd_as_dd = format_hd_as_dd; if (sct == NULL) { return; } for (i = 0; i < SONY_DRIVES; i++) { if (par_disk_boot & (1U << i)) { val = 1; } else { sprintf (var, "insert_delay_%u", i + 1); ini_get_uint16 (sct, var, &val, def); } mac_sony_set_delay (&sim->sony, i, val); pce_log_tag (MSG_INF, "SONY:", "drive=%u delay=%lu\n", i + 1, val ); } } static void mac_setup_sound (macplus_t *sim, ini_sct_t *ini) { unsigned long addr; unsigned long freq; const char *driver; ini_sct_t *sct; mac_sound_init (&sim->sound); if (sim->ram == NULL) { return; } sct = ini_next_sct (ini, NULL, "sound"); addr = mem_blk_get_size (sim->ram); addr = (addr < 0x300) ? 0 : (addr - 0x300); ini_get_uint32 (sct, "address", &addr, addr); ini_get_uint32 (sct, "lowpass", &freq, 6000); ini_get_string (sct, "driver", &driver, NULL); pce_log_tag (MSG_INF, "SOUND:", "addr=0x%06lX lowpass=%lu driver=%s\n", addr, freq, (driver != NULL) ? driver : "" ); sim->sbuf1 = addr; sim->sbuf2 = addr - 0x5c00; mac_sound_set_sbuf (&sim->sound, mem_blk_get_data (sim->ram) + sim->sbuf1); mac_sound_set_lowpass (&sim->sound, freq); if (driver != NULL) { if (mac_sound_set_driver (&sim->sound, driver)) { pce_log (MSG_ERR, "*** setting sound driver failed (%s)\n", driver ); } } } static void mac_setup_terminal (macplus_t *sim, ini_sct_t *ini) { sim->trm = ini_get_terminal (ini, par_terminal); if (sim->trm == NULL) { return; } trm_set_msg_fct (sim->trm, sim, mac_set_msg); trm_set_key_fct (sim->trm, sim, mac_set_key); trm_set_mouse_fct (sim->trm, sim, mac_set_mouse); trm_set_get_mouse_fct (sim->trm, sim, mac_get_mouse); } static void mac_setup_video (macplus_t *sim, ini_sct_t *ini) { unsigned long addr1, addr2; unsigned w, h, i; unsigned bright; unsigned long col0, col1; ini_sct_t *sct; if (sim->ram == NULL) { return; } sct = ini_next_sct (ini, NULL, "video"); ini_get_uint16 (sct, "width", &w, 512); ini_get_uint16 (sct, "height", &h, 342); addr1 = mem_blk_get_size (sim->ram); addr1 = (addr1 < 0x5900) ? 0 : (addr1 - ((w * h / 8) + 0x380)); ini_get_uint32 (sct, "address", &addr2, addr1); ini_get_uint32 (sct, "color0", &col0, 0); ini_get_uint32 (sct, "color1", &col1, 0xffffff); ini_get_uint16 (sct, "brightness", &bright, 1000); pce_log_tag (MSG_INF, "VIDEO:", "addr=0x%06lX w=%u h=%u bright=%u%%\n", addr2, w, h, bright / 10 ); sim->vbuf1 = addr2; if ((addr1 == addr2) && (addr2 >= 0x8000)) { sim->vbuf2 = addr2 - 0x8000; } else { sim->vbuf2 = addr2; } sim->video = mac_video_new (w, h); if (sim->video == NULL) { return; } mac_video_set_vbi_fct (sim->video, sim, mac_interrupt_vbi); mac_set_vbuf (sim, sim->vbuf1); if (sim->trm != NULL) { mac_video_set_terminal (sim->video, sim->trm); trm_open (sim->trm, w, h); } mac_video_set_color (sim->video, col0, col1); mac_video_set_brightness (sim->video, (255UL * bright + 500) / 1000); for (i = 0; i < (w / 8) * h; i++) { mem_set_uint8 (sim->mem, sim->vbuf1 + i, 0xff); } } void mac_init (macplus_t *sim, ini_sct_t *ini) { unsigned i; sim->trm = NULL; sim->video = NULL; sim->reset = 0; sim->disk_id = 1; sim->dcd_a = 0; sim->dcd_b = 0; sim->mouse_delta_x = 0; sim->mouse_delta_y = 0; sim->mouse_button = 0; sim->intr = 0; sim->pause = 0; sim->brk = 0; sim->speed_factor = 1; sim->speed_limit[0] = 1; sim->speed_clock_extra = 0; for (i = 1; i < PCE_MAC_SPEED_CNT; i++) { sim->speed_limit[i] = 0; } sim->ser_clk = 0; sim->clk_cnt = 0; for (i = 0; i < 4; i++) { sim->clk_div[i] = 0; } bps_init (&sim->bps); mac_setup_system (sim, ini); mac_setup_mem (sim, ini); mac_setup_cpu (sim, ini); mac_setup_via (sim, ini); mac_setup_scc (sim, ini); mac_setup_serial (sim, ini); mac_setup_rtc (sim, ini); mac_setup_kbd (sim, ini); mac_setup_adb (sim, ini); mac_setup_disks (sim, ini); mac_setup_iwm (sim, ini); mac_setup_scsi (sim, ini); mac_setup_sony (sim, ini); mac_setup_sound (sim, ini); mac_setup_terminal (sim, ini); mac_setup_video (sim, ini); e68_set_ram_write_fct (sim->cpu, sim, mac_ram_write); pce_load_mem_ini (sim->mem, ini); trm_set_msg_trm (sim->trm, "term.title", "pce-macplus"); mac_clock_discontinuity (sim); } macplus_t *mac_new (ini_sct_t *ini) { macplus_t *sim; sim = malloc (sizeof (macplus_t)); if (sim == NULL) { return (NULL); } mac_init (sim, ini); return (sim); } void mac_free (macplus_t *sim) { if (sim == NULL) { return; } if (mac_rtc_save_file (&sim->rtc, sim->rtc_fname)) { pce_log (MSG_ERR, "*** writing rtc file failed (%s)\n", sim->rtc_fname ); } free (sim->rtc_fname); mac_video_del (sim->video); trm_del (sim->trm); mac_sound_free (&sim->sound); mac_sony_free (&sim->sony); mac_scsi_free (&sim->scsi); mac_iwm_free (&sim->iwm); dsks_del (sim->dsks); mac_adb_del (sim->adb); mac_kbd_del (sim->kbd); mac_rtc_free (&sim->rtc); mac_ser_free (&sim->ser[1]); mac_ser_free (&sim->ser[0]); e8530_free (&sim->scc); e6522_free (&sim->via); e68_del (sim->cpu); mem_del (sim->mem); mem_blk_del (sim->ram_ovl); mem_blk_del (sim->rom_ovl); bps_free (&sim->bps); } void mac_del (macplus_t *sim) { if (sim != NULL) { mac_free (sim); free (sim); } } unsigned long long mac_get_clkcnt (macplus_t *sim) { return (sim->clk_cnt); } void mac_clock_discontinuity (macplus_t *sim) { sim->sync_clk = 0; sim->sync_us = 0; pce_get_interval_us (&sim->sync_us); sim->speed_clock_extra = 0; } void mac_set_pause (macplus_t *sim, int pause) { sim->pause = (pause != 0); if (sim->pause == 0) { mac_clock_discontinuity (sim); } } static void mac_adjust_speed (macplus_t *sim) { unsigned i, v; v = 0; for (i = 0; i < PCE_MAC_SPEED_CNT; i++) { if (sim->speed_limit[i] > 0) { if ((v == 0) || (sim->speed_limit[i] < v)) { v = sim->speed_limit[i]; } } } if (v == sim->speed_factor) { return; } mac_log_deb ("speed: %u\n", v); mac_rtc_set_realtime (&sim->rtc, (v != 1)); sim->speed_factor = v; sim->speed_clock_extra = 0; mac_clock_discontinuity (sim); } void mac_set_speed (macplus_t *sim, unsigned idx, unsigned factor) { if (idx >= PCE_MAC_SPEED_CNT) { return; } sim->speed_limit[idx] = factor; mac_adjust_speed (sim); } int mac_set_msg_trm (macplus_t *sim, const char *msg, const char *val) { if (sim->trm == NULL) { return (1); } return (trm_set_msg_trm (sim->trm, msg, val)); } int mac_set_cpu_model (macplus_t *sim, const char *model) { if (strcmp (model, "68000") == 0) { e68_set_68000 (sim->cpu); } else if (strcmp (model, "68010") == 0) { e68_set_68010 (sim->cpu); } else if (strcmp (model, "68020") == 0) { e68_set_68020 (sim->cpu); } else { return (1); } return (0); } void mac_reset (macplus_t *sim) { if (sim->reset) { return; } sim->reset = 1; mac_log_deb ("mac: reset\n"); sim->dcd_a = 0; sim->dcd_b = 0; sim->mouse_delta_x = 0; sim->mouse_delta_y = 0; sim->mouse_button = 0; sim->intr = 0; sim->intr_scsi_via = 0; if (sim->model & PCE_MAC_PLUS) { mac_set_overlay (sim, 1); } else { mac_set_overlay (sim, 0); if ((sim->rom != NULL) && (sim->rom->size >= 8)) { e68_set_mem32 (sim->cpu, 0, mem_blk_get_uint32_be (sim->rom, 0)); e68_set_mem32 (sim->cpu, 4, mem_blk_get_uint32_be (sim->rom, 4)); } } e6522_reset (&sim->via); sim->via_port_a = 0xf7; sim->via_port_b = 0xff; e6522_set_ira_inp (&sim->via, sim->via_port_a); e6522_set_irb_inp (&sim->via, sim->via_port_b); mac_sony_reset (&sim->sony); mac_scsi_reset (&sim->scsi); e8530_reset (&sim->scc); if (sim->adb != NULL) { adb_reset (sim->adb); } e68_reset (sim->cpu); mac_clock_discontinuity (sim); sim->reset = 0; } static void mac_realtime_sync (macplus_t *sim, unsigned long n) { unsigned long us1, us2; sim->sync_clk += n; if (sim->sync_clk >= (MAC_CPU_CLOCK / MAC_CPU_SYNC)) { sim->sync_clk -= (MAC_CPU_CLOCK / MAC_CPU_SYNC); us1 = pce_get_interval_us (&sim->sync_us); us2 = (1000000 / MAC_CPU_SYNC); if (us1 < us2) { sim->sync_sleep += us2 - us1; if (sim->sync_sleep > 0) { sim->speed_clock_extra += 1; } } else { sim->sync_sleep -= us1 - us2; if (sim->sync_sleep < 0) { if (sim->speed_clock_extra > 0) { sim->speed_clock_extra -= 1; } } } if (sim->sync_sleep >= MAC_CPU_SLEEP) { pce_usleep (sim->sync_sleep); } if (sim->sync_sleep < -1000000) { mac_log_deb ("system too slow, skipping 1 second\n"); sim->sync_sleep += 1000000; } } } void mac_clock_scc (macplus_t *sim, unsigned n) { /* 3.672 MHz = (15/32 * 7.8336 MHz) */ sim->ser_clk += 15 * n; if (sim->ser_clk >= 32) { e8530_clock (&sim->scc, sim->ser_clk / 32); sim->ser_clk &= 31; } } void mac_clock (macplus_t *sim, unsigned n) { unsigned long viaclk, clkdiv, cpuclk; if (n == 0) { n = sim->cpu->delay; if (n == 0) { n = 1; } } if (sim->speed_factor == 0) { cpuclk = n + sim->speed_clock_extra; clkdiv = 1; } else { cpuclk = n; clkdiv = sim->speed_factor; } e68_clock (sim->cpu, cpuclk); mac_sound_clock (&sim->sound, cpuclk); sim->clk_cnt += n; sim->clk_div[0] += n; while (sim->clk_div[0] >= clkdiv) { sim->clk_div[1] += 1; sim->clk_div[0] -= clkdiv; } if (sim->clk_div[1] < 10) { return; } viaclk = sim->clk_div[1] / 10; e6522_clock (&sim->via, viaclk); if (sim->adb != NULL) { mac_adb_clock (sim->adb, 10 * viaclk); } mac_iwm_clock (&sim->iwm, viaclk); mac_clock_scc (sim, 10 * viaclk); sim->clk_div[1] -= 10 * viaclk; sim->clk_div[2] += 10 * viaclk; if (sim->clk_div[2] < 256) { return; } mac_video_clock (sim->video, sim->clk_div[2]); mac_ser_process (&sim->ser[0]); mac_ser_process (&sim->ser[1]); if (sim->kbd != NULL) { mac_kbd_clock (sim->kbd, sim->clk_div[2]); } sim->clk_div[3] += sim->clk_div[2]; sim->clk_div[2] = 0; if (sim->clk_div[3] < 8192) { return; } if (sim->trm != NULL) { trm_check (sim->trm); } mac_check_mouse (sim); mac_rtc_clock (&sim->rtc, sim->clk_div[3]); mac_realtime_sync (sim, sim->clk_div[3]); sim->clk_div[3] = 0; }