#define KEY_POLL_INTERVAL_MSEC 5000
-unsigned char read_ranges;
-unsigned int read_addr[8];
-unsigned int read_upper[8];
-unsigned char *read_data[8];
-unsigned char write_ranges;
-unsigned int write_addr[8];
-unsigned int write_upper[8];
-unsigned char *write_data[8];
-address_translation_cache code_translation_cache = {0};
-
int kb_hook_enabled = 0;
int mouse_hook_enabled = 0;
int cpu_emulation_running = 1;
extern int m68ki_remaining_cycles;
#define M68K_SET_IRQ(i) old_level = CPU_INT_LEVEL; \
- CPU_INT_LEVEL = (i << 8); \
- if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700) \
- m68ki_cpu.nmi_pending = TRUE;
-#define M68K_END_TIMESLICE m68ki_initial_cycles = GET_CYCLES(); \
- SET_CYCLES(0);
+ CPU_INT_LEVEL = (i << 8); \
+ if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700) \
+ m68ki_cpu.nmi_pending = TRUE;
+#define M68K_END_TIMESLICE m68ki_initial_cycles = GET_CYCLES(); \
+ SET_CYCLES(0);
#else
#define M68K_SET_IRQ m68k_set_irq
#define M68K_END_TIMESLICE m68k_end_timeslice()
#endif
#define NOP asm("nop"); asm("nop"); asm("nop"); asm("nop");
+#define MEMORY_BARRIER() __sync_synchronize()
#define DEBUG_EMULATOR
#ifdef DEBUG_EMULATOR
struct emulator_config *cfg = NULL;
char keyboard_file[256] = "/dev/input/event1";
-uint64_t trig_irq = 0, serv_irq = 0;
-uint16_t irq_delay = 0;
-unsigned int amiga_reset=0, amiga_reset_last=0;
-unsigned int do_reset=0;
+const uint16_t irq_delay = 0;
+
+struct DoReset
+{
+ char pad0[64];
+ unsigned int value;
+ char pad1[64];
+};
+
+volatile struct DoReset do_reset = {0};
void *ipl_task(void *args) {
printf("IPL thread running\n");
uint16_t old_irq = 0;
uint32_t value;
+ unsigned int amiga_reset=0, amiga_reset_last=0;
while (1) {
value = *(gpio + 13);
+ if (value & (1 << PIN_TXN_IN_PROGRESS))
+ goto noppers;
if (!(value & (1 << PIN_IPL_ZERO))) {
old_irq = irq_delay;
- //NOP
if (!irq) {
- M68K_END_TIMESLICE;
- NOP
irq = 1;
+ MEMORY_BARRIER();
+ M68K_END_TIMESLICE;
}
- //usleep(0);
}
else {
if (irq) {
else {
irq = 0;
}
+ MEMORY_BARRIER();
M68K_END_TIMESLICE;
- NOP
- //usleep(0);
}
}
- if(do_reset==0)
+ if(do_reset.value==0)
{
amiga_reset=(value & (1 << PIN_RESET));
if(amiga_reset!=amiga_reset_last)
if(amiga_reset==0)
{
printf("Amiga Reset is down...\n");
- do_reset=1;
+ do_reset.value=1;
+ MEMORY_BARRIER();
M68K_END_TIMESLICE;
}
else
else
gayleirq = 0;
}*/
- //usleep(0);
- //NOP NOP
+
+noppers:
NOP NOP NOP NOP NOP NOP NOP NOP
//NOP NOP NOP NOP NOP NOP NOP NOP
//NOP NOP NOP NOP NOP NOP NOP NOP
return args;
}
+static inline unsigned int inline_read_status_reg() {
+ *(gpio + 7) = (REG_STATUS << PIN_A0);
+ *(gpio + 7) = 1 << PIN_RD;
+ *(gpio + 7) = 1 << PIN_RD;
+ *(gpio + 7) = 1 << PIN_RD;
+ *(gpio + 7) = 1 << PIN_RD;
+
+ unsigned int value = *(gpio + 13);
+
+ *(gpio + 10) = 0xffffec;
+
+ return (value >> 8) & 0xffff;
+}
+
void *cpu_task() {
- m68k_pulse_reset();
+ m68ki_cpu_core *state = &m68ki_cpu;
+ m68k_pulse_reset(state);
cpu_loop:
if (mouse_hook_enabled) {
printf("%.8X (%.8X)]] %s\n", m68k_get_reg(NULL, M68K_REG_PC), (m68k_get_reg(NULL, M68K_REG_PC) & 0xFFFFFF), disasm_buf);
if (do_disasm)
do_disasm--;
- m68k_execute(1);
+ m68k_execute(state, 1);
}
else {
- if (cpu_emulation_running)
- m68k_execute(loop_cycles);
+ if (cpu_emulation_running) {
+ MEMORY_BARRIER();
+ if (irq)
+ m68k_execute(state, 5);
+ else
+ m68k_execute(state, loop_cycles);
+ }
}
- if (irq) {
- while (irq) {
- last_irq = ((read_reg() & 0xe000) >> 13);
- if (last_irq != last_last_irq) {
+ MEMORY_BARRIER();
+ while (irq) {
+ last_irq = ((inline_read_status_reg() & 0xe000) >> 13);
+ if (last_irq != 0 && last_irq != last_last_irq) {
last_last_irq = last_irq;
M68K_SET_IRQ(last_irq);
}
- m68k_execute(5);
- }
- if (gayleirq && int2_enabled) {
- write16(0xdff09c, 0x8000 | (1 << 3) && last_irq != 2);
- last_last_irq = last_irq;
- last_irq = 2;
- M68K_SET_IRQ(2);
- }
- M68K_SET_IRQ(0);
+ m68k_execute(state, 50);
+ MEMORY_BARRIER();
+ }
+
+ MEMORY_BARRIER();
+ if (!irq && last_last_irq != 0) {
+ //M68K_SET_IRQ(0);
last_last_irq = 0;
- m68k_execute(5);
}
- /*else {
- if (last_irq != 0) {
- M68K_SET_IRQ(0);
- last_last_irq = last_irq;
- last_irq = 0;
- }
- }*/
- if (do_reset) {
+
+ MEMORY_BARRIER();
+ if (do_reset.value) {
cpu_pulse_reset();
- do_reset=0;
+ do_reset.value=0;
usleep(1000000); // 1sec
rtg_on=0;
// while(amiga_reset==0);
}
if (end_signal)
- goto stop_cpu_emulation;
+ goto stop_cpu_emulation;
goto cpu_loop;
}
if (c == 'q') {
printf("Quitting and exiting emulator.\n");
- end_signal = 1;
+ end_signal = 1;
goto key_end;
}
if (c == 'd') {
usleep(0);
}
- printf("IRQs triggered: %lld\n", trig_irq);
- printf("IRQs serviced: %lld\n", serv_irq);
exit(0);
}
m68k_init();
printf("Setting CPU type to %d.\n", cpu_type);
- m68k_set_cpu_type(cpu_type);
+ m68k_set_cpu_type(&m68ki_cpu, cpu_type);
cpu_pulse_reset();
pthread_t ipl_tid = 0, cpu_tid, kbd_tid;
}
void cpu_pulse_reset(void) {
+ m68ki_cpu_core *state = &m68ki_cpu;
ps_pulse_reset();
- if (cfg->platform->handle_reset)
- cfg->platform->handle_reset(cfg);
- //m68k_write_memory_16(INTENA, 0x7FFF);
ovl = 1;
- //m68k_write_memory_8(0xbfe201, 0x0001); // AMIGA OVL
- //m68k_write_memory_8(0xbfe001, 0x0001); // AMIGA OVL high (ROM@0x0)
+ if (cfg->platform->handle_reset)
+ cfg->platform->handle_reset(cfg);
- m68k_pulse_reset();
+ m68k_pulse_reset(state);
}
int cpu_irq_ack(int level) {
uint32_t cdtv_dmac_read(uint32_t address, uint8_t type);
void cdtv_dmac_write(uint32_t address, uint32_t value, uint8_t type);
+unsigned int garbage = 0;
+
static inline void inline_write_16(unsigned int address, unsigned int data) {
*(gpio + 0) = GPFSEL0_OUTPUT;
*(gpio + 1) = GPFSEL1_OUTPUT;
*(gpio + 1) = GPFSEL1_INPUT;
*(gpio + 2) = GPFSEL2_INPUT;
- while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS))
- ;
+ while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS)) {}
+ NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
}
static inline void inline_write_8(unsigned int address, unsigned int data) {
*(gpio + 1) = GPFSEL1_INPUT;
*(gpio + 2) = GPFSEL2_INPUT;
- while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS))
- ;
+ while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS)) {}
+ NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP
}
static inline void inline_write_32(unsigned int address, unsigned int value) {
*(gpio + 7) = (REG_DATA << PIN_A0);
*(gpio + 7) = 1 << PIN_RD;
+ while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS)) {}
unsigned int value = *(gpio + 13);
- while ((value=*(gpio + 13)) & (1 << PIN_TXN_IN_PROGRESS))
- ;
*(gpio + 10) = 0xffffec;
*(gpio + 7) = (REG_DATA << PIN_A0);
*(gpio + 7) = 1 << PIN_RD;
+ while (*(gpio + 13) & (1 << PIN_TXN_IN_PROGRESS)) {}
unsigned int value = *(gpio + 13);
- while ((value=*(gpio + 13)) & (1 << PIN_TXN_IN_PROGRESS))
- ;
*(gpio + 10) = 0xffffec;
return 0;
}
-static inline int32_t platform_read_check(uint8_t type, uint32_t addr, uint32_t *res) {
- switch (addr) {
- case CIAAPRA:
- if (mouse_hook_enabled && (mouse_buttons & 0x01)) {
- rres = (uint32_t)ps_read(type, addr);
- *res = (rres ^ 0x40);
- return 1;
- }
- return 0;
- break;
- case CIAAICR:
- if (kb_hook_enabled) {
- rres = (uint32_t)ps_read(type, addr);
- if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
- rres |= 0x08;
- if (!send_keypress)
- send_keypress = 1;
- }
- if (send_keypress == 2) {
- send_keypress = 0;
- }
- *res = rres;
- return 1;
- }
- return 0;
- break;
- case CIAADAT:
- if (kb_hook_enabled) {
- rres = (uint32_t)ps_read(type, addr);
- uint8_t c = 0, t = 0;
- pop_queued_key(&c, &t);
- t ^= 0x01;
- rres = ((c << 1) | t) ^ 0xFF;
- send_keypress = 2;
- *res = rres;
- return 1;
- }
- return 0;
- break;
- case JOY0DAT:
- if (mouse_hook_enabled) {
- unsigned short result = (mouse_dy << 8) | (mouse_dx);
- *res = (unsigned int)result;
- return 1;
- }
- return 0;
- break;
- case POTGOR:
- if (mouse_hook_enabled) {
- unsigned short result = (unsigned short)ps_read(type, addr);
- // bit 1 rmb, bit 2 mmb
- if (mouse_buttons & 0x06) {
- *res = (unsigned int)((result ^ ((mouse_buttons & 0x02) << 9)) // move rmb to bit 10
- & (result ^ ((mouse_buttons & 0x04) << 6))); // move mmb to bit 8
- return 1;
- }
- *res = (unsigned int)(result & 0xfffd);
- return 1;
- }
- return 0;
- break;
- default:
- break;
+static inline void ps_write(uint8_t type, uint32_t addr, uint32_t val) {
+ switch (type) {
+ case OP_TYPE_BYTE:
+ inline_write_8(addr, val);
+ return;
+ case OP_TYPE_WORD:
+ inline_write_16(addr, val);
+ return;
+ case OP_TYPE_LONGWORD:
+ inline_write_32(addr, val);
+ return;
}
+ // This shouldn't actually happen.
+ return;
+}
+static inline int32_t platform_read_check(uint8_t type, uint32_t addr, uint32_t *res) {
switch (cfg->platform->id) {
case PLATFORM_AMIGA:
+ switch (addr) {
+ case CIAAPRA:
+ if (mouse_hook_enabled && (mouse_buttons & 0x01)) {
+ rres = (uint32_t)ps_read(type, addr);
+ *res = (rres ^ 0x40);
+ return 1;
+ }
+ return 0;
+ break;
+ case CIAAICR:
+ if (kb_hook_enabled) {
+ rres = (uint32_t)ps_read(type, addr);
+ if (get_num_kb_queued() && (!send_keypress || send_keypress == 1)) {
+ rres |= 0x08;
+ if (!send_keypress)
+ send_keypress = 1;
+ }
+ if (send_keypress == 2) {
+ send_keypress = 0;
+ }
+ *res = rres;
+ return 1;
+ }
+ return 0;
+ break;
+ case CIAADAT:
+ if (kb_hook_enabled) {
+ rres = (uint32_t)ps_read(type, addr);
+ uint8_t c = 0, t = 0;
+ pop_queued_key(&c, &t);
+ t ^= 0x01;
+ rres = ((c << 1) | t) ^ 0xFF;
+ send_keypress = 2;
+ *res = rres;
+ return 1;
+ }
+ return 0;
+ break;
+ case JOY0DAT:
+ if (mouse_hook_enabled) {
+ unsigned short result = (mouse_dy << 8) | (mouse_dx);
+ *res = (unsigned int)result;
+ return 1;
+ }
+ return 0;
+ break;
+ case POTGOR:
+ if (mouse_hook_enabled) {
+ unsigned short result = (unsigned short)ps_read(type, addr);
+ // bit 1 rmb, bit 2 mmb
+ if (mouse_buttons & 0x06) {
+ *res = (unsigned int)((result ^ ((mouse_buttons & 0x02) << 9)) // move rmb to bit 10
+ & (result ^ ((mouse_buttons & 0x04) << 6))); // move mmb to bit 8
+ return 1;
+ }
+ *res = (unsigned int)(result & 0xfffd);
+ return 1;
+ }
+ return 0;
+ break;
+ default:
+ break;
+ }
+
if (addr >= cfg->custom_low && addr < cfg->custom_high) {
if (addr >= PISCSI_OFFSET && addr < PISCSI_UPPER) {
*res = handle_piscsi_read(addr, type);
}
static inline int32_t platform_write_check(uint8_t type, uint32_t addr, uint32_t val) {
- switch (addr) {
- case CIAAPRA:
- if (ovl != (val & (1 << 0))) {
- ovl = (val & (1 << 0));
- printf("OVL:%x\n", ovl);
+ switch (cfg->platform->id) {
+ case PLATFORM_MAC:
+ switch (addr) {
+ case 0xEFFFFE: // VIA1?
+ if (val & 0x10 && !ovl) {
+ ovl = 1;
+ printf("[MAC] OVL on.\n");
+ handle_ovl_mappings_mac68k(cfg);
+ } else if (ovl) {
+ ovl = 0;
+ printf("[MAC] OVL off.\n");
+ handle_ovl_mappings_mac68k(cfg);
+ }
+ break;
}
- return 0;
- break;
- case SERDAT: {
- char *serdat = (char *)&val;
- // SERDAT word. see amiga dev docs appendix a; upper byte is control codes, and bit 0 is always 1.
- // ignore this upper byte as it's not viewable data, only display lower byte.
- printf("%c", serdat[0]);
- return 0;
break;
- }
- case INTENA:
- // This code is kind of strange and should probably be reworked/revoked.
- if (!(val & 0x8000)) {
- if (val & 0x04) {
- int2_enabled = 0;
+ case PLATFORM_AMIGA:
+ switch (addr) {
+ case CIAAPRA:
+ if (ovl != (val & (1 << 0))) {
+ ovl = (val & (1 << 0));
+ printf("OVL:%x\n", ovl);
+ }
+ return 0;
+ break;
+ case SERDAT: {
+ char *serdat = (char *)&val;
+ // SERDAT word. see amiga dev docs appendix a; upper byte is control codes, and bit 0 is always 1.
+ // ignore this upper byte as it's not viewable data, only display lower byte.
+ printf("%c", serdat[0]);
+ return 0;
+ break;
}
+ case INTENA:
+ // This code is kind of strange and should probably be reworked/revoked.
+ if (!(val & 0x8000)) {
+ if (val & 0x04) {
+ int2_enabled = 0;
+ }
+ }
+ else if (val & 0x04) {
+ int2_enabled = 1;
+ }
+ return 0;
+ break;
+ default:
+ break;
}
- else if (val & 0x04) {
- int2_enabled = 1;
- }
- return 0;
- break;
- default:
- break;
- }
- switch (cfg->platform->id) {
- case PLATFORM_AMIGA:
if (addr >= cfg->custom_low && addr < cfg->custom_high) {
if (addr >= PISCSI_OFFSET && addr < PISCSI_UPPER) {
handle_piscsi_write(addr, val, type);