mirror of
https://github.com/buserror/mii_emu.git
synced 2024-06-25 15:29:30 +00:00
It is limited for now, hard coded to mine. Still need some sort of way to specify which button to map to the emulated joytick. Same with the axis, currently default to 0,1 Signed-off-by: Michel Pollet <buserror@gmail.com>
709 lines
16 KiB
C
709 lines
16 KiB
C
/*
|
|
* mii.c
|
|
*
|
|
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#include "mii_rom_iiee.h"
|
|
#include "mii.h"
|
|
#include "mii_bank.h"
|
|
#include "mii_video.h"
|
|
#include "mii_sw.h"
|
|
#include "mii_65c02.h"
|
|
#include "minipt.h"
|
|
|
|
|
|
mii_slot_drv_t * mii_slot_drv_list = NULL;
|
|
|
|
static const mii_bank_t _mii_banks_init[MII_BANK_COUNT] = {
|
|
[MII_BANK_MAIN] = {
|
|
.name = "MAIN",
|
|
.base = 0x0000,
|
|
.size = 0xd0, // 208 pages, 48KB
|
|
},
|
|
[MII_BANK_BSR] = {
|
|
.name = "BSR",
|
|
.base = 0xd000,
|
|
.size = 64,
|
|
},
|
|
[MII_BANK_BSR_P2] = {
|
|
.name = "BSR P2",
|
|
.base = 0xd000,
|
|
.size = 16,
|
|
},
|
|
[MII_BANK_AUX] = {
|
|
.name = "AUX",
|
|
.base = 0x0000,
|
|
.size = 0xd0, // 208 pages, 48KB
|
|
},
|
|
[MII_BANK_AUX_BSR] = {
|
|
.name = "AUX BSR",
|
|
.base = 0xd000,
|
|
.size = 64,
|
|
},
|
|
[MII_BANK_AUX_BSR_P2] = {
|
|
.name = "AUX BSR P2",
|
|
.base = 0xd000,
|
|
.size = 16,
|
|
},
|
|
[MII_BANK_ROM] = {
|
|
.name = "ROM",
|
|
.base = 0xc000,
|
|
.size = 0x40, // 64 pages, 16KB
|
|
.ro = 1,
|
|
},
|
|
[MII_BANK_CARD_ROM] = {
|
|
.name = "CARD ROM",
|
|
.base = 0xc100,
|
|
.size = 15,
|
|
.ro = 1,
|
|
},
|
|
};
|
|
|
|
|
|
#include "mii_65c02_ops.h"
|
|
#include "mii_65c02_disasm.h"
|
|
|
|
void
|
|
mii_dump_trace_state(
|
|
mii_t *mii)
|
|
{
|
|
mii_cpu_t * cpu = &mii->cpu;
|
|
mii_cpu_state_t s = mii->cpu_state;
|
|
printf("PC:%04X A:%02X X:%02X Y:%02X S:%02x #%d %c AD:%04X D:%02x %c ",
|
|
cpu->PC, cpu->A, cpu->X, cpu->Y, cpu->S, cpu->cycle,
|
|
s.sync ? 'I' : ' ', s.addr, s.data, s.w ? 'W' : 'R');
|
|
// display the S flags
|
|
static const char *s_flags = "CZIDBRVN";
|
|
for (int i = 0; i < 8; i++)
|
|
printf("%c", cpu->P.P[7-i] ? s_flags[7-i] : tolower(s_flags[7-i]));
|
|
if (s.sync) {
|
|
uint8_t op[16];
|
|
for (int i = 0; i < 4; i++) {
|
|
mii_mem_access(mii, mii->cpu.PC + i, op + i, false, false);
|
|
}
|
|
mii_op_t d = mii_cpu_op[op[0]];
|
|
printf(" ");
|
|
char dis[32];
|
|
mii_cpu_disasm_one(op, cpu->PC, dis, sizeof(dis),
|
|
MII_DUMP_DIS_DUMP_HEX);
|
|
printf(": %s", dis);
|
|
if (d.desc.branch) {
|
|
if (cpu->P.P[d.desc.s_bit] == d.desc.s_bit_value)
|
|
printf(" ; taken");
|
|
}
|
|
printf("\n");
|
|
} else
|
|
printf("\n");
|
|
}
|
|
|
|
void
|
|
mii_dump_run_trace(
|
|
mii_t *mii)
|
|
{
|
|
// walk all the previous PC values in mii->trace, and display a line
|
|
// of disassebly for all of them
|
|
for (int li = 0; li < MII_PC_LOG_SIZE; li++) {
|
|
int idx = (mii->trace.idx + li) & (MII_PC_LOG_SIZE - 1);
|
|
uint16_t pc = mii->trace.log[idx];
|
|
uint8_t op[16];
|
|
for (int i = 0; i < 4; i++)
|
|
mii_mem_access(mii, pc + i, op + i, false, false);
|
|
// mii_op_t d = mii_cpu_op[op[0]];
|
|
char dis[64];
|
|
mii_cpu_disasm_one(op, pc, dis, sizeof(dis),
|
|
MII_DUMP_DIS_PC | MII_DUMP_DIS_DUMP_HEX);
|
|
printf("%s\n", dis);
|
|
}
|
|
}
|
|
|
|
#define _SAME 0xf
|
|
|
|
static inline void
|
|
mii_page_set(
|
|
mii_t * mii,
|
|
uint8_t read,
|
|
uint8_t write,
|
|
uint8_t bank,
|
|
uint8_t end )
|
|
{
|
|
for (int i = bank; i <= end; i++) {
|
|
if (read != _SAME)
|
|
mii->mem[i].read = read;
|
|
if (write != _SAME)
|
|
mii->mem[i].write = write;
|
|
}
|
|
}
|
|
|
|
static inline uint8_t
|
|
mii_sw(
|
|
mii_t *mii,
|
|
uint16_t sw)
|
|
{
|
|
return mii_bank_peek(&mii->bank[MII_BANK_MAIN], sw);
|
|
}
|
|
|
|
static void
|
|
mii_page_table_update(
|
|
mii_t *mii)
|
|
{
|
|
if (!mii->mem_dirty)
|
|
return;
|
|
mii->mem_dirty = 0;
|
|
bool altzp = SW_GETSTATE(mii, SWALTPZ);
|
|
bool page2 = SW_GETSTATE(mii, SWPAGE2);
|
|
bool store80 = SW_GETSTATE(mii, SW80STORE);
|
|
bool hires = SW_GETSTATE(mii, SWHIRES);
|
|
bool ramrd = SW_GETSTATE(mii, SWRAMRD);
|
|
bool ramwrt = SW_GETSTATE(mii, SWRAMWRT);
|
|
bool intcxrom = SW_GETSTATE(mii, SWINTCXROM);
|
|
bool slotc3rom = SW_GETSTATE(mii, SWSLOTC3ROM);
|
|
|
|
if (mii->trace_cpu)
|
|
printf("%04x: page table update altzp:%d page2:%d store80:%d "
|
|
"hires:%d ramrd:%d ramwrt:%d intcxrom:%d "
|
|
"slotc3rom:%d\n", mii->cpu.PC,
|
|
altzp, page2, store80, hires, ramrd, ramwrt, intcxrom, slotc3rom);
|
|
// clean slate
|
|
mii_page_set(mii, MII_BANK_MAIN, MII_BANK_MAIN, 0x00, 0xc0);
|
|
mii_page_set(mii, MII_BANK_ROM, MII_BANK_ROM, 0xc1, 0xff);
|
|
if (altzp)
|
|
mii_page_set(mii, MII_BANK_AUX, MII_BANK_AUX, 0x00, 0x01);
|
|
mii_page_set(mii,
|
|
ramrd ? MII_BANK_AUX : MII_BANK_MAIN,
|
|
ramwrt ? MII_BANK_AUX : MII_BANK_MAIN, 0x02, 0xbf);
|
|
if (store80) {
|
|
mii_page_set(mii,
|
|
page2 ? MII_BANK_AUX : MII_BANK_MAIN,
|
|
page2 ? MII_BANK_AUX : MII_BANK_MAIN, 0x04, 0x07);
|
|
if (hires)
|
|
mii_page_set(mii,
|
|
page2 ? MII_BANK_AUX : MII_BANK_MAIN,
|
|
page2 ? MII_BANK_AUX : MII_BANK_MAIN, 0x20, 0x3f);
|
|
}
|
|
if (!intcxrom)
|
|
mii_page_set(mii, MII_BANK_CARD_ROM, _SAME, 0xc1, 0xc7);
|
|
mii_page_set(mii,
|
|
slotc3rom ? MII_BANK_CARD_ROM : MII_BANK_ROM, _SAME, 0xc3, 0xc3);
|
|
bool bsrread = SW_GETSTATE(mii, BSRREAD);
|
|
bool bsrwrite = SW_GETSTATE(mii, BSRWRITE);
|
|
bool bsrpage2 = SW_GETSTATE(mii, BSRPAGE2);
|
|
mii_page_set(mii,
|
|
bsrread ?
|
|
altzp ? MII_BANK_AUX_BSR : MII_BANK_BSR :
|
|
MII_BANK_ROM,
|
|
bsrwrite ?
|
|
altzp ? MII_BANK_AUX_BSR : MII_BANK_BSR :
|
|
MII_BANK_ROM,
|
|
0xd0, 0xff);
|
|
// BSR P2
|
|
mii_page_set(mii,
|
|
bsrread ?
|
|
(altzp ? MII_BANK_AUX_BSR : MII_BANK_BSR) + bsrpage2 :
|
|
MII_BANK_ROM,
|
|
bsrwrite ?
|
|
(altzp ? MII_BANK_AUX_BSR : MII_BANK_BSR) + bsrpage2 :
|
|
MII_BANK_ROM,
|
|
0xd0, 0xdf);
|
|
}
|
|
|
|
void
|
|
mii_set_sw_override(
|
|
mii_t *mii,
|
|
uint16_t sw_addr,
|
|
mii_bank_access_cb cb,
|
|
void *param)
|
|
{
|
|
if (!mii->soft_switches_override)
|
|
mii->soft_switches_override = calloc(256,
|
|
sizeof(*mii->soft_switches_override));
|
|
sw_addr &= 0xff;
|
|
mii->soft_switches_override[sw_addr].cb = cb;
|
|
mii->soft_switches_override[sw_addr].param = param;
|
|
}
|
|
|
|
static bool
|
|
mii_access_soft_switches(
|
|
mii_t *mii,
|
|
uint16_t addr,
|
|
uint8_t * byte,
|
|
bool write)
|
|
{
|
|
if (!(addr >= 0xc000 && addr <= 0xc0ff) || addr == 0xcfff)
|
|
return false;
|
|
bool res = false;
|
|
uint8_t on = 0;
|
|
mii_bank_t * main = &mii->bank[MII_BANK_MAIN];
|
|
|
|
/*
|
|
* This allows driver (titan accelerator etc) to have their own
|
|
* soft switches, and override/supplement any default ones.
|
|
*/
|
|
if (mii->soft_switches_override && mii->soft_switches_override[addr & 0xff].cb) {
|
|
res = mii->soft_switches_override[addr & 0xff].cb(
|
|
main, mii->soft_switches_override[addr & 0xff].param,
|
|
addr, byte, write);
|
|
if (res)
|
|
return res;
|
|
}
|
|
switch (addr) {
|
|
case 0xc090 ... 0xc0ff: {
|
|
res = true;
|
|
int slot = ((addr >> 4) & 7) - 1;
|
|
#if 0
|
|
printf("SLOT %d addr %04x write %d %02x drv %s\n",
|
|
slot, addr, write, *byte,
|
|
mii->slot[slot].drv ? mii->slot[slot].drv->name : "none");
|
|
#endif
|
|
if (mii->slot[slot].drv) {
|
|
on = mii->slot[slot].drv->access(mii,
|
|
&mii->slot[slot], addr, *byte, write);
|
|
if (!write)
|
|
*byte = on;
|
|
}
|
|
} break;
|
|
case 0xc080 ... 0xc08f: {
|
|
res = true;
|
|
uint8_t mode = addr & 0x0f;
|
|
static const int write_modes[4] = { 0, 1, 0, 1, };
|
|
static const int read_modes[4] = { 1, 0, 0, 1, };
|
|
uint8_t rd = read_modes[mode & 3];
|
|
uint8_t wr = write_modes[mode & 3];
|
|
SW_SETSTATE(mii, BSRWRITE, wr);
|
|
SW_SETSTATE(mii, BSRREAD, rd);
|
|
SW_SETSTATE(mii, BSRPAGE2, !(mode & 0x08));
|
|
mii->mem_dirty = 1;
|
|
if (mii->trace_cpu)
|
|
printf("%04x: BSR mode addr %04x:%02x read:%s write:%s %s altzp:%02x\n",
|
|
mii->cpu.PC, addr,
|
|
mode,
|
|
rd ? "BSR" : "ROM",
|
|
wr ? "BSR" : "ROM",
|
|
SW_GETSTATE(mii, BSRPAGE2) ? "page2" : "page1",
|
|
mii_sw(mii, SWALTPZ));
|
|
} break;
|
|
case 0xcfff:
|
|
res = true;
|
|
mii->mem_dirty = 1;
|
|
printf("%s TODO reset SLOT roms\n", __func__);
|
|
break;
|
|
case SWPAGE2OFF:
|
|
case SWPAGE2ON:
|
|
res = true;
|
|
SW_SETSTATE(mii, SWPAGE2, addr & 1);
|
|
mii_bank_poke(main, SWPAGE2, (addr & 1) << 7);
|
|
mii->mem_dirty = 1;
|
|
break;
|
|
case SWHIRESOFF:
|
|
case SWHIRESON:
|
|
res = true;
|
|
SW_SETSTATE(mii, SWHIRES, addr & 1);
|
|
mii_bank_poke(main, SWHIRES, (addr & 1) << 7);
|
|
mii->mem_dirty = 1;
|
|
// printf("HIRES %s\n", (addr & 1) ? "ON" : "OFF");
|
|
break;
|
|
case SWSPEAKER:
|
|
res = true;
|
|
mii_speaker_click(&mii->speaker);
|
|
break;
|
|
case 0xc064 ... 0xc067: // Joystick, buttons
|
|
case 0xc070: // Analog reset
|
|
res = true;
|
|
mii_analog_access(mii, &mii->analog, addr, byte, write);
|
|
break;
|
|
case 0xc068:
|
|
res = true;
|
|
// IIgs register, read by prodos tho
|
|
break;
|
|
}
|
|
if (res && !mii->mem_dirty)
|
|
return res;
|
|
if (write) {
|
|
switch (addr) {
|
|
case SW80STOREOFF:
|
|
case SW80STOREON:
|
|
res = true;
|
|
SW_SETSTATE(mii, SW80STORE, addr & 1);
|
|
mii_bank_poke(main, SW80STORE, (addr & 1) << 7);
|
|
mii->mem_dirty = 1;
|
|
break;
|
|
case SWRAMRDOFF:
|
|
case SWRAMRDON:
|
|
res = true;
|
|
SW_SETSTATE(mii, SWRAMRD, addr & 1);
|
|
mii_bank_poke(main, SWRAMRD, (addr & 1) << 7);
|
|
mii->mem_dirty = 1;
|
|
break;
|
|
case SWRAMWRTOFF:
|
|
case SWRAMWRTON:
|
|
res = true;
|
|
SW_SETSTATE(mii, SWRAMWRT, addr & 1);
|
|
mii_bank_poke(main, SWRAMWRT, (addr & 1) << 7);
|
|
mii->mem_dirty = 1;
|
|
break;
|
|
case SWALTPZOFF:
|
|
case SWALTPZON:
|
|
res = true;
|
|
SW_SETSTATE(mii, SWALTPZ, addr & 1);
|
|
mii_bank_poke(main, SWALTPZ, (addr & 1) << 7);
|
|
mii->mem_dirty = 1;
|
|
break;
|
|
case SWINTCXROMOFF:
|
|
case SWINTCXROMON:
|
|
res = true;
|
|
SW_SETSTATE(mii, SWINTCXROM, addr & 1);
|
|
mii_bank_poke(main, SWINTCXROM, (addr & 1) << 7);
|
|
mii->mem_dirty = 1;
|
|
break;
|
|
case SWSLOTC3ROMOFF:
|
|
case SWSLOTC3ROMON:
|
|
res = true;
|
|
SW_SETSTATE(mii, SWSLOTC3ROM, addr & 1);
|
|
mii_bank_poke(main, SWSLOTC3ROM, (addr & 1) << 7);
|
|
mii->mem_dirty = 1;
|
|
break;
|
|
}
|
|
} else {
|
|
switch (addr) {
|
|
case SWBSRBANK2:
|
|
*byte = SW_GETSTATE(mii, BSRPAGE2) ? 0x80 : 0;
|
|
res = true;
|
|
break;
|
|
case SWBSRREADRAM:
|
|
*byte = SW_GETSTATE(mii, BSRREAD) ? 0x80 : 0;
|
|
res = true;
|
|
break;
|
|
case SWRAMRD:
|
|
case SWRAMWRT:
|
|
case SW80STORE:
|
|
case SWINTCXROM:
|
|
case SWALTPZ:
|
|
case SWSLOTC3ROM:
|
|
res = true;
|
|
*byte = mii_bank_peek(main, addr);
|
|
break;
|
|
case 0xc020: // toggle TAPE output ?!?!
|
|
case 0xc064: // Analog Input 0 (paddle 0)
|
|
case 0xc065: // Analog Input 1 (paddle 1)
|
|
case 0xc079: // Analog Input Reset
|
|
res = true;
|
|
break;
|
|
case 0xc068:
|
|
res = true;
|
|
// IIgs register, read by prodos tho
|
|
break;
|
|
}
|
|
}
|
|
if (!res) {
|
|
// printf("%s addr %04x write %d %02x\n", __func__, addr, write, *byte);
|
|
// mii->state = MII_STOPPED;
|
|
}
|
|
mii_page_table_update(mii);
|
|
return res;
|
|
}
|
|
|
|
static bool
|
|
mii_access_keyboard(
|
|
mii_t *mii,
|
|
uint16_t addr,
|
|
uint8_t * byte,
|
|
bool write)
|
|
{
|
|
bool res = false;
|
|
mii_bank_t * main = &mii->bank[MII_BANK_MAIN];
|
|
switch (addr) {
|
|
case SWKBD:
|
|
if (!write) {
|
|
res = true;
|
|
*byte = mii_bank_peek(main, SWKBD);
|
|
}
|
|
break;
|
|
case SWAKD: {
|
|
res = true;
|
|
uint8_t r = mii_bank_peek(main, SWAKD);
|
|
if (!write)
|
|
*byte = r;
|
|
r &= 0x7f;
|
|
mii_bank_poke(main, SWAKD, r);
|
|
mii_bank_poke(main, SWKBD, r);
|
|
} break;
|
|
case 0xc061 ... 0xc063: // Push Button 0, 1, 2 (Apple Keys)
|
|
res = true;
|
|
if (!write)
|
|
*byte = mii_bank_peek(main, addr);
|
|
break;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void
|
|
mii_keypress(
|
|
mii_t *mii,
|
|
uint8_t key)
|
|
{
|
|
mii_bank_t * main = &mii->bank[MII_BANK_MAIN];
|
|
key |= 0x80;
|
|
mii_bank_poke(main, SWAKD, key);
|
|
mii_bank_poke(main, SWKBD, key);
|
|
}
|
|
|
|
|
|
void
|
|
mii_init(
|
|
mii_t *mii )
|
|
{
|
|
memset(mii, 0, sizeof(*mii));
|
|
mii->speed = 1.0;
|
|
for (int i = 0; i < MII_BANK_COUNT; i++)
|
|
mii->bank[i] = _mii_banks_init[i];
|
|
mii->bank[MII_BANK_ROM].mem = (uint8_t*)&iie_enhanced_rom_bin[0];
|
|
mii->cpu.trap = MII_TRAP;
|
|
mii_reset(mii, true);
|
|
mii->cpu_state = mii_cpu_init(&mii->cpu);
|
|
for (int i = 0; i < 7; i++)
|
|
mii->slot[i].id = i;
|
|
}
|
|
|
|
void
|
|
mii_prepare(
|
|
mii_t *mii,
|
|
uint32_t flags )
|
|
{
|
|
mii_dd_system_init(mii, &mii->dd);
|
|
mii_speaker_init(mii, &mii->speaker);
|
|
printf("%s driver table\n", __func__);
|
|
mii_slot_drv_t * drv = mii_slot_drv_list;
|
|
while (drv) {
|
|
printf("%s driver: %s\n", __func__, drv->name);
|
|
if (drv->probe && drv->probe(mii, flags)) {
|
|
printf("%s %s probe done\n", __func__, drv->name);
|
|
}
|
|
drv = drv->next;
|
|
}
|
|
}
|
|
|
|
void
|
|
mii_dispose(
|
|
mii_t *mii )
|
|
{
|
|
for (int i = 0; i < 7; i++) {
|
|
if (mii->slot[i].drv && mii->slot[i].drv->dispose)
|
|
mii->slot[i].drv->dispose(mii, &mii->slot[i]);
|
|
}
|
|
for (int i = 0; i < MII_BANK_COUNT; i++)
|
|
mii_bank_dispose(&mii->bank[i]);
|
|
mii_speaker_dispose(&mii->speaker);
|
|
mii_dd_system_dispose(&mii->dd);
|
|
}
|
|
|
|
void
|
|
mii_reset(
|
|
mii_t *mii,
|
|
bool cold)
|
|
{
|
|
// printf("%s cold %d\n", __func__, cold);
|
|
mii->cpu_state.reset = 1;
|
|
mii_bank_t * main = &mii->bank[MII_BANK_MAIN];
|
|
mii->sw_state = M_BSRWRITE | M_BSRPAGE2;
|
|
mii_bank_poke(main, SWSLOTC3ROM, 0);
|
|
mii_bank_poke(main, SWRAMRD, 0);
|
|
mii_bank_poke(main, SWRAMWRT, 0);
|
|
mii_bank_poke(main, SWALTPZ, 0);
|
|
mii_bank_poke(main, SW80STORE, 0);
|
|
mii_bank_poke(main, SW80COL, 0);
|
|
mii->mem_dirty = 1;
|
|
if (cold) {
|
|
/* these HAS to be reset in that state somehow */
|
|
mii_bank_poke(main, SWINTCXROM, 0);
|
|
uint8_t z[2] = {0x55,0x55};
|
|
mii_bank_write(main, 0x3f2, z, 2);
|
|
}
|
|
mii->mem_dirty = 1;
|
|
mii_page_table_update(mii);
|
|
for (int i = 0; i < 7; i++) {
|
|
if (mii->slot[i].drv && mii->slot[i].drv->reset)
|
|
mii->slot[i].drv->reset(mii, &mii->slot[i]);
|
|
}
|
|
}
|
|
|
|
void
|
|
mii_mem_access(
|
|
mii_t *mii,
|
|
uint16_t addr,
|
|
uint8_t * d,
|
|
bool wr,
|
|
bool do_sw)
|
|
{
|
|
if (!do_sw && addr >= 0xc000 && addr <= 0xc0ff)
|
|
return;
|
|
uint8_t done =
|
|
mii_access_keyboard(mii, addr, d, wr) ||
|
|
mii_access_video(mii, addr, d, wr) ||
|
|
mii_access_soft_switches(mii, addr, d, wr);
|
|
if (!done) {
|
|
uint8_t page = addr >> 8;
|
|
if (wr) {
|
|
uint8_t m = mii->mem[page].write;
|
|
mii_bank_t * b = &mii->bank[m];
|
|
if (b->ro) {
|
|
// printf("%s write to RO bank %s %04x:%02x\n",
|
|
// __func__, b->name, addr, *d);
|
|
} else
|
|
mii_bank_write(b, addr, d, 1);
|
|
} else {
|
|
uint8_t m = mii->mem[page].read;
|
|
mii_bank_t * b = &mii->bank[m];
|
|
*d = mii_bank_peek(b, addr);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_mii_handle_trap(
|
|
mii_t *mii)
|
|
{
|
|
// printf("%s TRAP hit PC: %04x\n", __func__, mii->cpu.PC);
|
|
mii->cpu_state.sync = 1;
|
|
mii->cpu_state.trap = 0;
|
|
mii->cpu.state = NULL;
|
|
uint8_t trap = mii_read_one(mii, mii->cpu.PC);
|
|
mii->cpu.PC += 1;
|
|
// printf("%s TRAP %02x return PC %04x\n", __func__, trap, mii->cpu.PC);
|
|
if (mii->trap.map & (1 << trap)) {
|
|
if (mii->trap.trap[trap].cb)
|
|
mii->trap.trap[trap].cb(mii, trap);
|
|
} else {
|
|
printf("%s TRAP %02x not handled\n", __func__, trap);
|
|
mii->state = MII_STOPPED;
|
|
}
|
|
// mii->state = MII_STOPPED;
|
|
}
|
|
|
|
uint8_t
|
|
mii_register_trap(
|
|
mii_t *mii,
|
|
mii_trap_handler_cb cb)
|
|
{
|
|
if (mii->trap.map == 0xffff) {
|
|
printf("%s no more traps!!\n", __func__);
|
|
return 0xff;
|
|
}
|
|
for (int i = 0; i < (int)sizeof(mii->trap.map) * 8; i++) {
|
|
if (!(mii->trap.map & (1 << i))) {
|
|
mii->trap.map |= 1 << i;
|
|
mii->trap.trap[i].cb = cb;
|
|
return i;
|
|
}
|
|
}
|
|
return 0xff;
|
|
}
|
|
|
|
void
|
|
mii_run(
|
|
mii_t *mii)
|
|
{
|
|
/* this runs all cycles for one instruction */
|
|
do {
|
|
if (mii->trace_cpu)
|
|
mii_dump_trace_state(mii);
|
|
mii->cpu_state = mii_cpu_run(&mii->cpu, mii->cpu_state);
|
|
mii_video_run(mii);
|
|
mii_speaker_run(&mii->speaker);
|
|
// extract 16-bit address from pin mask
|
|
const uint16_t addr = mii->cpu_state.addr;
|
|
const uint8_t data = mii->cpu_state.data;
|
|
int wr = mii->cpu_state.w;
|
|
uint8_t d = data;
|
|
if (mii->debug.bp_map) {
|
|
for (int i = 0; i < (int)sizeof(mii->debug.bp_map) * 8; i++) {
|
|
if (!(mii->debug.bp_map & (1 << i)))
|
|
continue;
|
|
if (addr >= mii->debug.bp[i].addr &&
|
|
addr < mii->debug.bp[i].addr + mii->debug.bp[i].size) {
|
|
if (((mii->debug.bp[i].kind & MII_BP_R) && !wr) ||
|
|
((mii->debug.bp[i].kind & MII_BP_W) && wr)) {
|
|
|
|
if (1 || !mii->debug.bp[i].silent) {
|
|
printf("BREAKPOINT %d at %04x PC:%04x\n",
|
|
i, addr, mii->cpu.PC);
|
|
mii_dump_run_trace(mii);
|
|
mii_dump_trace_state(mii);
|
|
mii->state = MII_STOPPED;
|
|
}
|
|
}
|
|
if (!(mii->debug.bp[i].kind & MII_BP_STICKY))
|
|
mii->debug.bp_map &= ~(1 << i);
|
|
mii->debug.bp[i].kind |= MII_BP_HIT;
|
|
}
|
|
}
|
|
}
|
|
mii_mem_access(mii, addr, &d, wr, true);
|
|
if (!wr)
|
|
mii->cpu_state.data = d;
|
|
if (mii->cpu_state.trap) {
|
|
_mii_handle_trap(mii);
|
|
}
|
|
} while (!(mii->cpu_state.sync));
|
|
mii->cycles += mii->cpu.cycle;
|
|
// log PC for the running disassembler display
|
|
mii->trace.log[mii->trace.idx] = mii->cpu.PC;
|
|
mii->trace.idx = (mii->trace.idx + 1) & (MII_PC_LOG_SIZE - 1);
|
|
for (int i = 0; i < 7; i++) {
|
|
if (mii->slot[i].drv && mii->slot[i].drv->run)
|
|
mii->slot[i].drv->run(mii, &mii->slot[i]);
|
|
}
|
|
}
|
|
|
|
//! Read one byte from and addres, using the current memory mapping
|
|
uint8_t
|
|
mii_read_one(
|
|
mii_t *mii,
|
|
uint16_t addr)
|
|
{
|
|
uint8_t d = 0;
|
|
mii_mem_access(mii, addr, &d, 0, false);
|
|
return d;
|
|
}
|
|
//! Read a word from addr, using current memory mapping (little endian)
|
|
uint16_t
|
|
mii_read_word(
|
|
mii_t *mii,
|
|
uint16_t addr)
|
|
{
|
|
uint8_t d = 0;
|
|
uint16_t res = 0;
|
|
mii_mem_access(mii, addr, &d, 0, false);
|
|
res = d;
|
|
mii_mem_access(mii, addr + 1, &d, 0, false);
|
|
res |= d << 8;
|
|
return res;
|
|
}
|
|
/* same accessors, for write
|
|
*/
|
|
void
|
|
mii_write_one(
|
|
mii_t *mii,
|
|
uint16_t addr,
|
|
uint8_t d)
|
|
{
|
|
mii_mem_access(mii, addr, &d, 1, false);
|
|
}
|
|
void
|
|
mii_write_word(
|
|
mii_t *mii,
|
|
uint16_t addr,
|
|
uint16_t w)
|
|
{
|
|
uint8_t d = w;
|
|
mii_mem_access(mii, addr, &d, 1, false);
|
|
d = w >> 8;
|
|
mii_mem_access(mii, addr + 1, &d, 1, false);
|
|
}
|