OVR: Change the way to walk and rotate with the controller
[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 <string.h>
24 #include "../libsdl/print.h"
25 #include "execute.h"
26 #include "m68k.h"
27 #include "m68kcpu.h"
28
29 //#define DEBUG_CPU
30
31 #define IOMASK  0xfffff000
32 #define IOBASE  0x00dff000
33
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;
40
41
42 static uint16_t read_io_16(unsigned int address)
43 {
44 #ifdef DEBUG_CPU
45         printf("Chip read from 0x%08x\n", address);
46 #endif
47         return io_read(address);
48 }
49
50 static void write_io_16(unsigned int address, uint16_t value)
51 {
52 #ifdef DEBUG_CPU
53         printf("Chip write to 0x%08x\n", address);
54 #endif
55         if ((address & IOMASK) == IOBASE)
56                 chipreg[address & ~IOMASK] = value;
57         io_write(address, value);
58 }
59
60 unsigned int m68k_read_memory_8(unsigned int address)
61 {
62         if (address > memory_size - 1) {
63                 if ((address & 1)) {
64                         /* read lower (right) byte */
65                         return read_io_16(address & ~1);
66                 } else {
67                         /* read upper (left) byte */
68                         return read_io_16(address) >> 8;
69                 }
70         }
71         return *((uint8_t *)(memory + address));
72 }
73
74 unsigned int m68k_read_memory_16(unsigned int address)
75 {
76         if (address > memory_size - 2) {
77                 return read_io_16(address);
78         }
79         return  (memory[address] << 8) |
80                  memory[address + 1];
81 }
82
83 unsigned int m68k_read_memory_32(unsigned int address)
84 {
85         if (address > memory_size - 4) {
86                 int32_t value;
87                 value = read_io_16(address) << 16;
88                 value |= read_io_16(address + 2);
89                 return value;
90         }
91         return  (memory[address] << 24)|
92                 (memory[address + 1] << 16) |
93                 (memory[address + 2] << 8) |
94                  memory[address + 3];
95 }
96
97 void m68k_write_memory_8(unsigned int address, unsigned int value)
98 {
99         if (address > memory_size - 1) {
100                 if ((address & 1)) {
101                         /* write lower (right) byte */
102                         write_io_16(address & ~1, 0xff00 | value);
103                 } else {
104                         /* write upper (left) byte */
105                         write_io_16(address, 0x00ff | (value << 8));
106                 }
107                 return;
108         }
109         *((uint8_t *)(memory + address)) = value;
110 }
111
112 void m68k_write_memory_16(unsigned int address, unsigned int value)
113 {
114         if (address > memory_size - 2) {
115                 write_io_16(address, value);
116                 return;
117         }
118         memory[address] = value >> 8;
119         memory[address + 1] = value;
120 }
121
122 void m68k_write_memory_32(unsigned int address, unsigned int value)
123 {
124         if (address > memory_size - 4) {
125                 write_io_16(address, value >> 16);
126                 write_io_16(address + 2, value);
127                 return;
128         }
129         memory[address] = value >> 24;
130         memory[address + 1] = value >> 16;
131         memory[address + 2] = value >> 8;
132         memory[address + 3] = value;
133 }
134
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[])
136 {
137         int i;
138
139         memory_size = _memory_size;
140         memory = _memory;
141         stop_event = _stop_event;
142         chipreg = _chipreg;
143         io_read = _io_read;
144         io_write = _io_write;
145
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);
151                         exit(0);
152                 }
153                 stop_event[stop_at[i].pc] = stop_at[i].event;
154         }
155
156         /* init CPU */
157         m68k_init();
158         m68k_set_cpu_type(M68K_CPU_TYPE_68000);
159 }
160
161 void reset_cpu(void)
162 {
163         m68k_pulse_reset();
164 }
165
166 int execute_cpu(int irq, int *event)
167 {
168         int cycle_count = 0;
169         int instruction_count = 0;
170         uint32_t save_pc;
171
172         if (irq) {
173                 save_pc = REG_PC;
174                 m68k_set_irq(irq);
175                 /* loop until we returned from interrupt */
176                 do {
177                         /* execute one opcode */
178                         cycle_count += m68k_execute(0);
179                         instruction_count++;
180                 } while (REG_PC != save_pc);
181 #ifdef DEBUG_CPU
182                 printf("interrupt %d took %d opcodes\n", irq, instruction_count);
183 #endif
184         } else {
185                 do {
186                         /* execute one opcode */
187                         cycle_count += m68k_execute(0);
188                         instruction_count++;
189
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)
196                                         break;
197                         }
198
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);
202                                 exit(0);
203                         }
204                         if (stop_event[REG_PC]) {
205                                 *event = stop_event[REG_PC];
206                                 return cycle_count;
207                         }
208                 } while (42);
209         }
210
211         return cycle_count;
212 }
213