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