Sun, 28 Nov 2010 22:04:14 +0000
enforce RAM size requirements
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 void state_done(void);
12 void FAIL(char *err)
13 {
14 state_done();
15 fprintf(stderr, "ERROR: %s\nExiting...\n", err);
16 exit(EXIT_FAILURE);
17 }
19 // Maximum size of the Boot PROMs. Must be a binary power of two.
20 #define ROM_SIZE 32768
22 struct {
23 // Boot PROM can be up to 32Kbytes total size
24 uint8_t rom[ROM_SIZE];
26 // Main system RAM
27 uint8_t *ram;
28 size_t ram_size; // number of RAM bytes allocated
30 // GENERAL CONTROL REGISTER
31 bool romlmap;
32 } state;
34 int state_init()
35 {
36 // Free RAM if it's allocated
37 if (state.ram != NULL)
38 free(state.ram);
40 // Initialise hardware registers
41 state.romlmap = false;
43 // Allocate RAM, making sure the user has specified a valid RAM amount first
44 // Basically: 512KiB minimum, 4MiB maximum, in increments of 512KiB.
45 if ((state.ram_size < 512*1024) || ((state.ram_size % (512*1024)) != 0))
46 return -1;
47 state.ram = malloc(state.ram_size);
48 if (state.ram == NULL)
49 return -2;
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 + romlen2) > ROM_SIZE) FAIL("ROMs are too large to fit in memory!");
68 // sanity checks completed; load the ROMs!
69 uint8_t *romdat1, *romdat2;
70 romdat1 = malloc(romlen);
71 romdat2 = malloc(romlen2);
72 fread(romdat1, 1, romlen, r15c);
73 fread(romdat2, 1, romlen2, r14c);
75 // convert the ROM data
76 for (size_t i=0; i<(romlen + romlen2); i+=2) {
77 state.rom[i+0] = romdat1[i/2];
78 state.rom[i+1] = romdat2[i/2];
79 }
81 for (size_t i=0; i<16; i++) printf("%02X ", state.rom[i]);
82 printf("\n");
84 // TODO: if ROM buffer not filled, repeat the ROM data we read until it is.
86 // free the data arrays and close the files
87 free(romdat1);
88 free(romdat2);
89 fclose(r14c);
90 fclose(r15c);
92 return 0;
93 }
95 void state_done()
96 {
97 if (state.ram != NULL)
98 free(state.ram);
99 }
101 // read m68k memory
102 uint32_t m68k_read_memory_32(uint32_t address)
103 {
104 uint32_t data = 0xFFFFFFFF;
106 printf("RD32 %08X %d", address, state.romlmap);
108 // If ROMLMAP is set, force system to access ROM
109 if (!state.romlmap)
110 address |= 0x800000;
112 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
113 // ROM access
114 data = (((uint32_t)state.rom[(address + 0) & (ROM_SIZE - 1)] << 24) |
115 ((uint32_t)state.rom[(address + 1) & (ROM_SIZE - 1)] << 16) |
116 ((uint32_t)state.rom[(address + 2) & (ROM_SIZE - 1)] << 8) |
117 ((uint32_t)state.rom[(address + 3) & (ROM_SIZE - 1)]));
118 } else if (address < state.ram_size - 1) {
119 // RAM
120 data = (((uint32_t)state.ram[address + 0] << 24) |
121 ((uint32_t)state.ram[address + 1] << 16) |
122 ((uint32_t)state.ram[address + 2] << 8) |
123 ((uint32_t)state.ram[address + 3]));
124 }
126 printf(" ==> %08X\n", data);
127 return data;
128 }
130 uint32_t m68k_read_memory_16(uint32_t address)
131 {
132 uint16_t data = 0xFFFF;
134 printf("RD16 %08X %d", address, state.romlmap);
136 // If ROMLMAP is set, force system to access ROM
137 if (!state.romlmap)
138 address |= 0x800000;
140 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
141 // ROM access
142 data = ((state.rom[(address + 0) & (ROM_SIZE - 1)] << 8) |
143 (state.rom[(address + 1) & (ROM_SIZE - 1)]));
144 } else if (address < state.ram_size - 1) {
145 // RAM
146 data = ((state.ram[address + 0] << 8) |
147 (state.ram[address + 1]));
148 }
150 printf(" ==> %04X\n", data);
151 return data;
152 }
154 uint32_t m68k_read_memory_8(uint32_t address)
155 {
156 uint8_t data = 0xFF;
158 printf("RD 8 %08X %d ", address, state.romlmap);
160 // If ROMLMAP is set, force system to access ROM
161 if (!state.romlmap)
162 address |= 0x800000;
164 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
165 // ROM access
166 data = state.rom[(address + 0) & (ROM_SIZE - 1)];
167 } else if (address < state.ram_size) {
168 // RAM access
169 data = state.ram[address + 0];
170 }
172 printf("==> %02X\n", data);
173 return data;
174 }
176 // write m68k memory
177 void m68k_write_memory_32(uint32_t address, uint32_t value)
178 {
179 // If ROMLMAP is set, force system to access ROM
180 if (!state.romlmap)
181 address |= 0x800000;
183 printf("WR32 %08X %d %02X\n", address, state.romlmap, value);
185 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
186 // ROM access
187 // TODO: bus error here? can't write to rom!
188 } else if (address < state.ram_size) {
189 // RAM access
190 state.ram[address + 0] = (value >> 24) & 0xff;
191 state.ram[address + 1] = (value >> 16) & 0xff;
192 state.ram[address + 2] = (value >> 8) & 0xff;
193 state.ram[address + 3] = value & 0xff;
194 } else {
195 switch (address) {
196 case 0xE43000: state.romlmap = ((value & 0x8000) == 0x8000);
197 }
198 }
199 }
201 void m68k_write_memory_16(uint32_t address, uint32_t value)
202 {
203 // If ROMLMAP is set, force system to access ROM
204 if (!state.romlmap)
205 address |= 0x800000;
207 printf("WR16 %08X %d %02X\n", address, state.romlmap, value);
209 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
210 // ROM access
211 // TODO: bus error here? can't write to rom!
212 } else if (address < state.ram_size) {
213 // RAM access
214 state.ram[address + 0] = (value >> 8) & 0xff;
215 state.ram[address + 1] = value & 0xff;
216 } else {
217 switch (address) {
218 case 0xE43000: state.romlmap = ((value & 0x8000) == 0x8000);
219 }
220 }
221 }
223 void m68k_write_memory_8(uint32_t address, uint32_t value)
224 {
225 // If ROMLMAP is set, force system to access ROM
226 if (!state.romlmap)
227 address |= 0x800000;
229 printf("WR 8 %08X %d %02X\n", address, state.romlmap, value);
231 if ((address >= 0x800000) && (address <= 0xBFFFFF)) {
232 // ROM access
233 // TODO: bus error here? can't write to rom!
234 } else if (address < state.ram_size) {
235 state.ram[address] = value & 0xff;
236 } else {
237 switch (address) {
238 case 0xE43000: state.romlmap = ((value & 0x80) == 0x80);
239 }
240 }
241 }
243 // for the disassembler
244 uint32_t m68k_read_disassembler_32(uint32_t addr) { return m68k_read_memory_32(addr); }
245 uint32_t m68k_read_disassembler_16(uint32_t addr) { return m68k_read_memory_16(addr); }
246 uint32_t m68k_read_disassembler_8 (uint32_t addr) { return m68k_read_memory_8 (addr); }
248 int main(void)
249 {
250 // copyright banner
251 printf("FreeBee: A Quick-and-Dirty AT&T 3B1 Emulator\n");
252 printf("Copyright (C) 2010 P. A. Pemberton.\n");
253 printf("Musashi M680x0 emulator engine developed by Karl Stenerud <kstenerud@gmail.com>\n");
255 // set up system state
256 // 512K of RAM
257 state.ram_size = 512*1024;
258 state_init();
260 // set up musashi
261 m68k_set_cpu_type(M68K_CPU_TYPE_68010);
262 m68k_pulse_reset();
264 char dasm[512];
265 m68k_disassemble(dasm, 0x80001a, M68K_CPU_TYPE_68010);
266 printf("%s\n", dasm);
268 // set up SDL
270 // emulation loop!
271 // repeat:
272 // m68k_execute()
273 // m68k_set_irq() every 60ms
274 printf("ran for %d cycles\n", m68k_execute(100000));
276 // shut down and exit
278 return 0;
279 }