Sun, 28 Nov 2010 19:53:53 +0000
set up ROM loader and state storage, add basic emulator core
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdint.h>
4 #include <stdbool.h>
5 #include <malloc.h>
6 #include <string.h>
7 #include "musashi/m68k.h"
8 #include "version.h"
10 #define ROM_SIZE (32768/4)
12 void state_done(void);
14 void FAIL(char *err)
15 {
16 state_done();
17 fprintf(stderr, "ERROR: %s\nExiting...\n", err);
18 exit(EXIT_FAILURE);
19 }
22 struct {
23 // Boot PROM can be up to 32Kbytes total size
24 uint32_t rom[ROM_SIZE];
26 // Main system RAM
27 uint32_t *ram;
28 size_t ram_size; // number of RAM bytes allocated
29 uint32_t ram_addr_mask; // address mask
31 // GENERAL CONTROL REGISTER
32 bool romlmap;
33 } state;
35 int state_init()
36 {
37 // Free RAM if it's allocated
38 if (state.ram != NULL)
39 free(state.ram);
41 // Initialise hardware registers
42 state.romlmap = false;
44 // Allocate RAM
45 // TODO: make sure ram size selection is valid!
46 state.ram = malloc(state.ram_size);
47 if (state.ram == NULL)
48 return -1;
49 state.ram_addr_mask = state.ram_size - 1;
51 // Load ROMs
52 FILE *r14c, *r15c;
53 r14c = fopen("roms/14c.bin", "rb");
54 if (r14c == NULL) FAIL("unable to open roms/14c.bin");
55 r15c = fopen("roms/15c.bin", "rb");
56 if (r15c == NULL) FAIL("unable to open roms/15c.bin");
58 // get ROM file size
59 fseek(r14c, 0, SEEK_END);
60 size_t romlen = ftell(r14c);
61 fseek(r14c, 0, SEEK_SET);
62 fseek(r15c, 0, SEEK_END);
63 size_t romlen2 = ftell(r15c);
64 fseek(r15c, 0, SEEK_SET);
65 if (romlen2 != romlen) FAIL("ROMs are not the same size!");
66 if ((romlen / 4) > (ROM_SIZE / 2)) FAIL("ROM 14C is too big!");
67 if ((romlen2 / 4) > (ROM_SIZE / 2)) FAIL("ROM 15C is too big!");
69 // sanity checks completed; load the ROMs!
70 uint8_t *romdat1, *romdat2;
71 romdat1 = malloc(romlen);
72 romdat2 = malloc(romlen2);
73 fread(romdat1, 1, romlen, r15c);
74 fread(romdat2, 1, romlen2, r14c);
76 // convert the ROM data
77 for (size_t i=0; i<romlen; i+=2) {
78 state.rom[i/2] = (
79 (romdat1[i+0] << 24) |
80 (romdat2[i+0] << 16) |
81 (romdat1[i+1] << 8) |
82 (romdat2[i+1]));
83 }
85 for (int i=0; i<8; i++)
86 printf("%02X %02X ", romdat1[i], romdat2[i]);
87 printf("\n%08X %08X\n", state.rom[0], state.rom[1]);
89 // free the data arrays and close the files
90 free(romdat1);
91 free(romdat2);
92 fclose(r14c);
93 fclose(r15c);
95 return 0;
96 }
98 void state_done()
99 {
100 if (state.ram != NULL)
101 free(state.ram);
102 }
104 // read m68k memory
105 // TODO: refactor musashi to use stdint, and properly sized integers!
106 // TODO: find a way to make musashi use function pointers instead of hard coded callbacks, maybe use a context struct too
107 uint32_t m68k_read_memory_32(uint32_t address)
108 {
109 // If ROMLMAP is set, force system to access ROM
110 if (!state.romlmap)
111 address |= 0x800000;
113 if (address >= 0xC00000) {
114 // I/O Registers B
115 // TODO
116 } else if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
117 // ROM access
118 printf("%08X\n", state.rom[(address & (ROM_SIZE-1)) / 4]);
119 return state.rom[(address & (ROM_SIZE-1)) / 4];
120 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
121 // I/O Registers A
122 // TODO
123 } else if (address <= 0x3FFFFF) {
124 // RAM
125 return state.ram[(address & state.ram_addr_mask) / 4];
126 }
127 return 0xffffffff;
128 }
130 uint32_t m68k_read_memory_16(uint32_t address)
131 {
132 if (address & 2) {
133 return m68k_read_memory_32(address) & 0xFFFF;
134 } else {
135 return (m68k_read_memory_32(address) >> 16) & 0xFFFF;
136 }
137 }
139 uint32_t m68k_read_memory_8(uint32_t address)
140 {
141 // If ROMLMAP is set, force system to access ROM
142 if (!state.romlmap)
143 address |= 0x800000;
145 switch (address & 3) {
146 case 3: return m68k_read_memory_32(address) & 0xFF;
147 case 2: return (m68k_read_memory_32(address) >> 8) & 0xFF;
148 case 1: return (m68k_read_memory_32(address) >> 16) & 0xFF;
149 case 0: return (m68k_read_memory_32(address) >> 24) & 0xFF;
150 }
151 return 0xffffffff;
152 }
154 // write m68k memory
155 void m68k_write_memory_32(uint32_t address, uint32_t value)
156 {
157 // If ROMLMAP is set, force system to access ROM
158 if (!state.romlmap)
159 address |= 0x800000;
161 if (address >= 0xC00000) {
162 // I/O Registers B
163 // TODO
164 } else if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
165 // ROM access
166 // TODO: bus error here? can't write to rom!
167 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
168 // I/O Registers A
169 // TODO
170 } else if (address <= 0x3FFFFF) {
171 // RAM
172 state.ram[(address & state.ram_addr_mask) / 4] = value;
173 }
174 }
176 void m68k_write_memory_16(uint32_t address, uint32_t value)
177 {
178 // If ROMLMAP is set, force system to access ROM
179 if (!state.romlmap)
180 address |= 0x800000;
182 if (address >= 0xC00000) {
183 // I/O Registers B
184 // TODO
185 } else if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
186 // ROM access
187 // TODO: bus error here? can't write to rom!
188 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
189 // I/O Registers A
190 // TODO
191 } else if (address <= 0x3FFFFF) {
192 // RAM
193 if (address & 2)
194 state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0xFFFF0000) | (value & 0xFFFF);
195 else
196 state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0x0000FFFF) | ((value & 0xFFFF) << 16);
197 }
198 }
200 void m68k_write_memory_8(uint32_t address, uint32_t value)
201 {
202 // If ROMLMAP is set, force system to access ROM
203 if (!state.romlmap)
204 address |= 0x800000;
206 if (address >= 0xC00000) {
207 // I/O Registers B
208 // TODO
209 } else if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
210 // ROM access
211 // TODO: bus error here? can't write to rom!
212 } else if ((address >= 0x400000) && (address <= 0x7FFFFF)) {
213 // I/O Registers A
214 // TODO
215 } else if (address <= 0x3FFFFF) {
216 // RAM
217 switch (address & 3) {
218 case 3: state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0xFFFFFF00) | (value & 0xFF);
219 case 2: state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0xFFFF00FF) | ((value & 0xFF) << 8);
220 case 1: state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0xFF00FFFF) | ((value & 0xFF) << 16);
221 case 0: state.ram[(address & state.ram_addr_mask) / 4] = (state.ram[(address & state.ram_addr_mask) / 4] & 0x00FFFFFF) | ((value & 0xFF) << 24);
222 }
223 }
224 }
226 int main(void)
227 {
228 // copyright banner
229 printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator\n");
230 printf("Copyright (C) 2010 P. A. Pemberton.\n");
231 printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
233 // set up system state
234 // 512K of RAM
235 state.ram_size = 512*1024;
236 state_init();
238 // set up musashi
239 m68k_set_cpu_type(M68K_CPU_TYPE_68010);
240 m68k_pulse_reset();
242 // set up SDL
244 // emulation loop!
245 // repeat:
246 // m68k_execute()
247 // m68k_set_irq() every 60ms
248 m68k_execute(100000);
250 // shut down and exit
252 return 0;
253 }