1 /* CPU emulation loop and memory access
3 * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "../libsdl/print.h"
31 #define IOMASK 0xfffff000
32 #define IOBASE 0x00dff000
34 static uint8_t *memory = NULL;
35 static uint8_t *stop_event = NULL;
36 static uint32_t memory_size = 0;
37 static uint16_t *chipreg = NULL;
38 static uint16_t (*io_read)(uint32_t address) = NULL;
39 static void (*io_write)(uint32_t address, uint16_t value) = NULL;
42 static uint16_t read_io_16(unsigned int address)
45 printf("Chip read from 0x%08x\n", address);
47 return io_read(address);
50 static void write_io_16(unsigned int address, uint16_t value)
53 printf("Chip write to 0x%08x\n", address);
55 if ((address & IOMASK) == IOBASE)
56 chipreg[address & ~IOMASK] = value;
57 io_write(address, value);
60 unsigned int m68k_read_memory_8(unsigned int address)
62 if (address > memory_size - 1) {
64 /* read lower (right) byte */
65 return read_io_16(address & ~1);
67 /* read upper (left) byte */
68 return read_io_16(address) >> 8;
71 return *((uint8_t *)(memory + address));
74 unsigned int m68k_read_memory_16(unsigned int address)
76 if (address > memory_size - 2) {
77 return read_io_16(address);
79 return (memory[address] << 8) |
83 unsigned int m68k_read_memory_32(unsigned int address)
85 if (address > memory_size - 4) {
87 value = read_io_16(address) << 16;
88 value |= read_io_16(address + 2);
91 return (memory[address] << 24)|
92 (memory[address + 1] << 16) |
93 (memory[address + 2] << 8) |
97 void m68k_write_memory_8(unsigned int address, unsigned int value)
99 if (address > memory_size - 1) {
101 /* write lower (right) byte */
102 write_io_16(address & ~1, 0xff00 | value);
104 /* write upper (left) byte */
105 write_io_16(address, 0x00ff | (value << 8));
109 *((uint8_t *)(memory + address)) = value;
112 void m68k_write_memory_16(unsigned int address, unsigned int value)
114 if (address > memory_size - 2) {
115 write_io_16(address, value);
118 memory[address] = value >> 8;
119 memory[address + 1] = value;
122 void m68k_write_memory_32(unsigned int address, unsigned int value)
124 if (address > memory_size - 4) {
125 write_io_16(address, value >> 16);
126 write_io_16(address + 2, value);
129 memory[address] = value >> 24;
130 memory[address + 1] = value >> 16;
131 memory[address + 2] = value >> 8;
132 memory[address + 3] = value;
135 void execute_init(int32_t _memory_size, uint8_t *_memory, uint8_t *_stop_event, uint16_t *_chipreg, uint16_t (*_io_read)(uint32_t address), void (*_io_write)(uint32_t address, uint16_t value), const struct cpu_stop stop_at[])
139 memory_size = _memory_size;
141 stop_event = _stop_event;
144 io_write = _io_write;
146 /* flag where the cpu shall stop at */
147 memset(stop_event, 0, _memory_size);
148 for (i = 0; stop_at[i].event; i++) {
149 if (stop_at[i].pc >= memory_size) {
150 print_error("stop-event at PC=%x is out of memory=%x\n", stop_at[i].pc, memory_size);
153 stop_event[stop_at[i].pc] = stop_at[i].event;
158 m68k_set_cpu_type(M68K_CPU_TYPE_68000);
166 int execute_cpu(int irq, int *event)
169 int instruction_count = 0;
175 /* loop until we returned from interrupt */
177 /* execute one opcode */
178 cycle_count += m68k_execute(0);
180 } while (REG_PC != save_pc);
182 printf("interrupt %d took %d opcodes\n", irq, instruction_count);
186 /* execute one opcode */
187 cycle_count += m68k_execute(0);
190 /* checking if game does not hit any 'stop_at' break point, give error output */
191 if (instruction_count >= 10000000) {
192 if (instruction_count == 10000000)
193 print_error("!!! games seems to got stuck in an endless loop, please fix !!!\n");
194 fprintf(stderr, "program counter at: %06x\n", REG_PC);
195 if (instruction_count == 10000020)
199 /* stop execution if there is an event */
200 if (REG_PC >= memory_size) {
201 print_error("CPU execution reaches PC=%x that is out of memory=%x\n", REG_PC, memory_size);
204 if (stop_event[REG_PC]) {
205 *event = stop_event[REG_PC];