Wed, 01 Dec 2010 21:55:09 +0000
Edit I/O routines so R/Ws only log if the register is unknown
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <stdbool.h>
5 #include <malloc.h>
6 #include <string.h>
8 #include "SDL.h"
10 #include "musashi/m68k.h"
11 #include "version.h"
12 #include "state.h"
14 void FAIL(char *err)
15 {
16 state_done();
17 fprintf(stderr, "ERROR: %s\nExiting...\n", err);
18 exit(EXIT_FAILURE);
19 }
21 // read m68k memory
22 uint32_t m68k_read_memory_32(uint32_t address)
23 {
24 uint32_t data = 0xFFFFFFFF;
26 // If ROMLMAP is set, force system to access ROM
27 if (!state.romlmap)
28 address |= 0x800000;
30 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
31 // ROM access
32 data = (((uint32_t)state.rom[(address + 0) & (ROM_SIZE - 1)] << 24) |
33 ((uint32_t)state.rom[(address + 1) & (ROM_SIZE - 1)] << 16) |
34 ((uint32_t)state.rom[(address + 2) & (ROM_SIZE - 1)] << 8) |
35 ((uint32_t)state.rom[(address + 3) & (ROM_SIZE - 1)]));
36 } else if (address < state.ram_size - 1) {
37 // RAM
38 data = (((uint32_t)state.ram[address + 0] << 24) |
39 ((uint32_t)state.ram[address + 1] << 16) |
40 ((uint32_t)state.ram[address + 2] << 8) |
41 ((uint32_t)state.ram[address + 3]));
42 } else {
43 // I/O register -- TODO
44 printf("RD32 %08X [unknown I/O register]\n", address);
45 }
46 return data;
47 }
49 uint32_t m68k_read_memory_16(uint32_t address)
50 {
51 uint16_t data = 0xFFFF;
53 // If ROMLMAP is set, force system to access ROM
54 if (!state.romlmap)
55 address |= 0x800000;
57 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
58 // ROM access
59 data = ((state.rom[(address + 0) & (ROM_SIZE - 1)] << 8) |
60 (state.rom[(address + 1) & (ROM_SIZE - 1)]));
61 } else if (address < state.ram_size - 1) {
62 // RAM
63 data = ((state.ram[address + 0] << 8) |
64 (state.ram[address + 1]));
65 } else {
66 // I/O register -- TODO
67 printf("RD16 %08X [unknown I/O register]\n", address);
68 }
70 return data;
71 }
73 uint32_t m68k_read_memory_8(uint32_t address)
74 {
75 uint8_t data = 0xFF;
77 // If ROMLMAP is set, force system to access ROM
78 if (!state.romlmap)
79 address |= 0x800000;
81 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
82 // ROM access
83 data = state.rom[(address + 0) & (ROM_SIZE - 1)];
84 } else if (address < state.ram_size) {
85 // RAM access
86 data = state.ram[address + 0];
87 } else {
88 // I/O register -- TODO
89 printf("RD 8 %08X [unknown I/O register]\n", address);
90 }
92 return data;
93 }
95 // write m68k memory
96 void m68k_write_memory_32(uint32_t address, uint32_t value)
97 {
98 // If ROMLMAP is set, force system to access ROM
99 if (!state.romlmap)
100 address |= 0x800000;
102 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
103 // ROM access
104 // TODO: bus error here? can't write to rom!
105 } else if (address < state.ram_size) {
106 // RAM access
107 state.ram[address + 0] = (value >> 24) & 0xff;
108 state.ram[address + 1] = (value >> 16) & 0xff;
109 state.ram[address + 2] = (value >> 8) & 0xff;
110 state.ram[address + 3] = value & 0xff;
111 } else {
112 switch (address) {
113 case 0xE43000: state.romlmap = ((value & 0x8000) == 0x8000); break; // GCR3: ROMLMAP
114 default: printf("WR32 %08X ==> %02X\n", address, state.romlmap, value); break;
115 }
116 }
117 }
119 void m68k_write_memory_16(uint32_t address, uint32_t value)
120 {
121 // If ROMLMAP is set, force system to access ROM
122 if (!state.romlmap)
123 address |= 0x800000;
125 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
126 // ROM access
127 // TODO: bus error here? can't write to rom!
128 } else if (address < state.ram_size) {
129 // RAM access
130 state.ram[address + 0] = (value >> 8) & 0xff;
131 state.ram[address + 1] = value & 0xff;
132 } else {
133 switch (address) {
134 case 0xE43000: state.romlmap = ((value & 0x8000) == 0x8000); break; // GCR3: ROMLMAP
135 default: printf("WR16 %08X %d %02X\n", address, state.romlmap, value); break;
136 }
137 }
138 }
140 void m68k_write_memory_8(uint32_t address, uint32_t value)
141 {
142 // If ROMLMAP is set, force system to access ROM
143 if (!state.romlmap)
144 address |= 0x800000;
146 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
147 // ROM access
148 // TODO: bus error here? can't write to rom!
149 } else if (address < state.ram_size) {
150 state.ram[address] = value & 0xff;
151 } else {
152 switch (address) {
153 case 0xE43000: state.romlmap = ((value & 0x80) == 0x80); break; // GCR3: ROMLMAP
154 default: printf("WR 8 %08X %d %02X\n", address, state.romlmap, value); break;
155 }
156 }
157 }
159 // for the disassembler
160 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
161 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
162 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
164 int main(void)
165 {
166 // copyright banner
167 printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator. Version %s, %s mode.\n", VER_FULLSTR, VER_BUILD_TYPE);
168 printf("Copyright (C) 2010 P. A. Pemberton. All rights reserved.\nLicensed under the Apache License Version 2.0.\n");
169 printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
170 printf("Built %s by %s@%s.\n", VER_COMPILE_DATETIME, VER_COMPILE_BY, VER_COMPILE_HOST);
171 printf("Compiler: %s\n", VER_COMPILER);
172 printf("CFLAGS: %s\n", VER_CFLAGS);
173 printf("\n");
175 // set up system state
176 // 512K of RAM
177 state_init(512*1024);
179 // set up musashi and reset the CPU
180 m68k_set_cpu_type(M68K_CPU_TYPE_68010);
181 m68k_pulse_reset();
182 /*
183 size_t i = 0x80001a;
184 size_t len;
185 do {
186 char dasm[512];
187 len = m68k_disassemble(dasm, i, M68K_CPU_TYPE_68010);
188 printf("%06X: %s\n", i, dasm);
189 i += len;
190 } while (i < 0x8000ff);
191 */
193 // set up SDL
194 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) {
195 printf("Could not initialise SDL: %s.\n", SDL_GetError());
196 return -1;
197 }
199 /***
200 * The 3B1 CPU runs at 10MHz, with DMA running at 1MHz and video refreshing at
201 * around 60Hz (???), with a 60Hz periodic interrupt.
202 */
203 const uint32_t TIMESLOT_FREQUENCY = 240; // Hz
204 const uint32_t MILLISECS_PER_TIMESLOT = 1e3 / TIMESLOT_FREQUENCY;
205 const uint32_t CLOCKS_PER_60HZ = (10e6 / 60);
206 uint32_t next_timeslot = SDL_GetTicks() + MILLISECS_PER_TIMESLOT;
207 uint32_t clock_cycles = 0;
208 bool exitEmu = false;
209 for (;;) {
210 // Run the CPU for however many cycles we need to. CPU core clock is
211 // 10MHz, and we're running at 240Hz/timeslot. Thus: 10e6/240 or
212 // 41667 cycles per timeslot.
213 clock_cycles += m68k_execute(10e6/TIMESLOT_FREQUENCY);
215 // TODO: run DMA here
217 // Is it time to run the 60Hz periodic interrupt yet?
218 if (clock_cycles > CLOCKS_PER_60HZ) {
219 // TODO: refresh screen
220 // TODO: trigger periodic interrupt (if enabled)
221 // decrement clock cycle counter, we've handled the intr.
222 clock_cycles -= CLOCKS_PER_60HZ;
223 }
225 printf("timeslot\n");
227 // make sure frame rate is equal to real time
228 uint32_t now = SDL_GetTicks();
229 if (now < next_timeslot) {
230 // timeslot finished early -- eat up some time
231 SDL_Delay(next_timeslot - now);
232 } else {
233 // timeslot finished late -- skip ahead to gain time
234 // TODO: if this happens a lot, we should let the user know
235 // that their PC might not be fast enough...
236 next_timeslot = now;
237 }
238 // advance to the next timeslot
239 next_timeslot += MILLISECS_PER_TIMESLOT;
241 // if we've been asked to exit the emulator, then do so.
242 if (exitEmu) break;
243 }
245 // shut down and exit
246 SDL_Quit();
248 return 0;
249 }