cb9784536ae30f16dcf2b99fecc341468b8c0cca
[mercenary-reloaded.git] / src / libcpu / execute.c
1 /* CPU emulation loop and memory access
2  *
3  * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
4  * All Rights Reserved
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include <stdio.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include "execute.h"
24 #include "m68k.h"
25 #include "m68kcpu.h"
26
27 //#define DEBUG_CPU
28
29 #define IOMASK  0xfffff000
30 #define IOBASE  0x00dff000
31
32 static uint8_t *memory = NULL;
33 static uint32_t memory_size = 0;
34 static uint16_t *chipreg = NULL;
35
36 static uint16_t read_io(unsigned int address)
37 {
38 #ifdef DEBUG_CPU
39         printf("Chip read from 0x%08x\n", address);
40 #endif
41         return emulate_io_read(address);
42 }
43
44 static void write_io(unsigned int address, uint16_t value)
45 {
46 #ifdef DEBUG_CPU
47         printf("Chip write to 0x%08x\n", address);
48 #endif
49         if ((address & IOMASK) == IOBASE)
50                 chipreg[address & ~IOMASK] = value;
51         emulate_io_write(address, value);
52 }
53
54 unsigned int m68k_read_memory_8(unsigned int address)
55 {
56         if (address > memory_size - 1) {
57                 if ((address & 1)) {
58                         /* read lower (right) byte */
59                         return read_io(address & ~1);
60                 } else {
61                         /* read upper (left) byte */
62                         return read_io(address) >> 8;
63                 }
64         }
65         return *((uint8_t *)(memory + address));
66 }
67
68 unsigned int m68k_read_memory_16(unsigned int address)
69 {
70         if (address > memory_size - 2) {
71                 return read_io(address);
72         }
73         return  (memory[address] << 8) |
74                  memory[address + 1];
75 }
76
77 unsigned int m68k_read_memory_32(unsigned int address)
78 {
79         if (address > memory_size - 4) {
80                 int32_t value;
81                 value = read_io(address) << 16;
82                 value |= read_io(address + 2);
83                 return value;
84         }
85         return  (memory[address] << 24)|
86                 (memory[address + 1] << 16) |
87                 (memory[address + 2] << 8) |
88                  memory[address + 3];
89 }
90
91 void m68k_write_memory_8(unsigned int address, unsigned int value)
92 {
93         if (address > memory_size - 1) {
94                 if ((address & 1)) {
95                         /* write lower (right) byte */
96                         write_io(address & ~1, 0xff00 | value);
97                 } else {
98                         /* write upper (left) byte */
99                         write_io(address, 0x00ff | (value << 8));
100                 }
101                 return;
102         }
103         *((uint8_t *)(memory + address)) = value;
104 }
105
106 void m68k_write_memory_16(unsigned int address, unsigned int value)
107 {
108         if (address > memory_size - 2) {
109                 write_io(address, value);
110                 return;
111         }
112         memory[address] = value >> 8;
113         memory[address + 1] = value;
114 }
115
116 void m68k_write_memory_32(unsigned int address, unsigned int value)
117 {
118         if (address > memory_size - 4) {
119                 write_io(address, value >> 16);
120                 write_io(address + 2, value);
121                 return;
122         }
123         memory[address] = value >> 24;
124         memory[address + 1] = value >> 16;
125         memory[address + 2] = value >> 8;
126         memory[address + 3] = value;
127 }
128
129 void execute_init(int32_t _memory_size, uint8_t *_memory, uint16_t *_chipreg)
130 {
131         memory_size = _memory_size;
132         memory = _memory;
133         chipreg = _chipreg;
134
135         /* init CPU */
136         m68k_init();
137         m68k_set_cpu_type(M68K_CPU_TYPE_68000);
138 }
139
140 void reset_cpu(void)
141 {
142         m68k_pulse_reset();
143 }
144
145 int execute_cpu(int irq, const struct cpu_stop stop_at[], int *event)
146 {
147         int cycle_count = 0;
148         int instruction_count = 0;
149         int i;
150         uint32_t save_pc;
151
152         if (irq) {
153                 save_pc = REG_PC;
154                 m68k_set_irq(irq);
155                 /* loop until we returned from interrupt */
156                 do {
157                         /* execute one opcode */
158                         cycle_count += m68k_execute(0);
159                         instruction_count++;
160                 } while (REG_PC != save_pc);
161 #ifdef DEBUG_CPU
162                 printf("interrupt %d took %d opcodes\n", irq, instruction_count);
163 #endif
164         } else {
165                 do {
166                         /* execute one opcode */
167                         cycle_count += m68k_execute(0);
168                         instruction_count++;
169
170                         /* checking if game does not hit any 'stop_at' break point, give error output */
171                         if (instruction_count >= 10000000) {
172                                 if (instruction_count == 10000000)
173                                         fprintf(stderr, "!!! games seems to got stuck in an endless loop, please fix !!!\n");
174                                 fprintf(stderr, "program counter at: %06x\n", REG_PC);
175                                 if (instruction_count == 10000020)
176                                         break;
177                         }
178
179                         for (i = 0; stop_at[i].event; i++) {
180                                 if (REG_PC == stop_at[i].pc) {
181 #ifdef DEBUG_CPU
182                                         printf("execution to address 0x%06x took %d opcodes\n", REG_PC, instruction_count);
183 #endif
184                                         *event = stop_at[i].event;
185                                         return cycle_count;
186                                 }
187                         }
188                 } while (42);
189         }
190
191         return cycle_count;
192 }
193