Mercurial > repos > blastem
comparison segacd.c @ 1502:2564b6ba2e12 segacd
Initial skeleton of Sega CD memory handlers
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 12 Dec 2017 09:44:33 -0800 |
parents | d51230205405 |
children | a763523dadf4 |
comparison
equal
deleted
inserted
replaced
1472:d2d637dbacfb | 1502:2564b6ba2e12 |
---|---|
1 #include <stdlib.h> | |
2 #include <string.h> | |
3 #include "segacd.h" | |
4 #include "genesis.h" | |
5 #include "util.h" | |
6 | |
7 static void *prog_ram_wp_write16(uint32_t address, void *vcontext, uint16_t value) | |
8 { | |
9 return vcontext; | |
10 } | |
11 | |
12 static void *prog_ram_wp_write8(uint32_t address, void *vcontext, uint8_t value) | |
13 { | |
14 return vcontext; | |
15 } | |
16 | |
17 static uint16_t work_ram_2M_read16(uint32_t address, void *vcontext) | |
18 { | |
19 return 0; | |
20 } | |
21 | |
22 static uint8_t work_ram_2M_read8(uint32_t address, void *vcontext) | |
23 { | |
24 return 0; | |
25 } | |
26 | |
27 static void *work_ram_2M_write16(uint32_t address, void *vcontext, uint16_t value) | |
28 { | |
29 return vcontext; | |
30 } | |
31 | |
32 static void *work_ram_2M_write8(uint32_t address, void *vcontext, uint8_t value) | |
33 { | |
34 return vcontext; | |
35 } | |
36 | |
37 static uint16_t work_ram_1M_read16(uint32_t address, void *vcontext) | |
38 { | |
39 return 0; | |
40 } | |
41 | |
42 static uint8_t work_ram_1M_read8(uint32_t address, void *vcontext) | |
43 { | |
44 return 0; | |
45 } | |
46 | |
47 static void *work_ram_1M_write16(uint32_t address, void *vcontext, uint16_t value) | |
48 { | |
49 return vcontext; | |
50 } | |
51 | |
52 static void *work_ram_1M_write8(uint32_t address, void *vcontext, uint8_t value) | |
53 { | |
54 return vcontext; | |
55 } | |
56 | |
57 static uint8_t pcm_read8(uint32_t address, void *vcontext) | |
58 { | |
59 return 0; | |
60 } | |
61 | |
62 static uint16_t pcm_read16(uint32_t address, void *vcontext) | |
63 { | |
64 return 0xFF00 | pcm_read8(address+1, vcontext); | |
65 } | |
66 | |
67 static void *pcm_write8(uint32_t address, void *vcontext, uint8_t value) | |
68 { | |
69 return vcontext; | |
70 } | |
71 | |
72 static void *pcm_write16(uint32_t address, void *vcontext, uint16_t value) | |
73 { | |
74 return pcm_write8(address+1, vcontext, value); | |
75 } | |
76 | |
77 static uint16_t sub_gate_read16(uint32_t address, void *vcontext) | |
78 { | |
79 m68k_context *m68k = vcontext; | |
80 segacd_context *cd = m68k->system; | |
81 return cd->gate_array[(address & 0x1FF) >> 1]; | |
82 } | |
83 | |
84 static uint8_t sub_gate_read8(uint32_t address, void *vcontext) | |
85 { | |
86 m68k_context *m68k = vcontext; | |
87 segacd_context *cd = m68k->system; | |
88 uint16_t val = cd->gate_array[(address & 0x1FF) >> 1]; | |
89 return address & 1 ? val : val >> 8; | |
90 } | |
91 | |
92 static void *sub_gate_write16(uint32_t address, void *vcontext, uint16_t value) | |
93 { | |
94 m68k_context *m68k = vcontext; | |
95 segacd_context *cd = m68k->system; | |
96 uint32_t reg = (address & 0x1FF) >> 1; | |
97 switch (reg) | |
98 { | |
99 case 0x7: | |
100 cd->gate_array[reg] &= 0xFF00; | |
101 cd->gate_array[reg] |= value & 0xFF; | |
102 break; | |
103 case 0x10: | |
104 case 0x11: | |
105 case 0x12: | |
106 case 0x13: | |
107 case 0x14: | |
108 case 0x15: | |
109 case 0x16: | |
110 case 0x17: | |
111 //no effects for these other than saving the value | |
112 cd->gate_array[reg] = value; | |
113 break; | |
114 default: | |
115 printf("Unhandled gate array write %X:%X\n", address, value); | |
116 } | |
117 return vcontext; | |
118 } | |
119 | |
120 static void *sub_gate_write8(uint32_t address, void *vcontext, uint8_t value) | |
121 { | |
122 m68k_context *m68k = vcontext; | |
123 segacd_context *cd = m68k->system; | |
124 uint32_t reg = (address & 0x1FF) >> 1; | |
125 uint16_t value16; | |
126 if (address & 1) { | |
127 value16 = cd->gate_array[reg] & 0xFF00 | value; | |
128 } else { | |
129 value16 = cd->gate_array[reg] & 0xFF | (value << 8); | |
130 } | |
131 return sub_gate_write16(address, vcontext, value16); | |
132 } | |
133 | |
134 static uint16_t main_gate_read16(uint32_t address, void *vcontext) | |
135 { | |
136 m68k_context *m68k = vcontext; | |
137 segacd_context *cd = m68k->system; | |
138 return cd->gate_array[(address & 0x1FF) >> 1]; | |
139 } | |
140 | |
141 static uint8_t main_gate_read8(uint32_t address, void *vcontext) | |
142 { | |
143 m68k_context *m68k = vcontext; | |
144 segacd_context *cd = m68k->system; | |
145 uint16_t val = cd->gate_array[(address & 0x1FF) >> 1]; | |
146 return address & 1 ? val : val >> 8; | |
147 } | |
148 | |
149 static void *main_gate_write16(uint32_t address, void *vcontext, uint16_t value) | |
150 { | |
151 m68k_context *m68k = vcontext; | |
152 genesis_context *gen = m68k->system; | |
153 segacd_context *cd = gen->expansion; | |
154 uint32_t reg = (address & 0x1FF) >> 1; | |
155 switch (reg) | |
156 { | |
157 case 0x7: | |
158 cd->gate_array[reg] &= 0xFF; | |
159 cd->gate_array[reg] |= value & 0xFF00; | |
160 break; | |
161 case 0x8: | |
162 case 0x9: | |
163 case 0xA: | |
164 case 0xB: | |
165 case 0xC: | |
166 case 0xD: | |
167 case 0xE: | |
168 case 0xF: | |
169 //no effects for these other than saving the value | |
170 cd->gate_array[reg] = value; | |
171 break; | |
172 default: | |
173 printf("Unhandled gate array write %X:%X\n", address, value); | |
174 } | |
175 return vcontext; | |
176 } | |
177 | |
178 static void *main_gate_write8(uint32_t address, void *vcontext, uint8_t value) | |
179 { | |
180 m68k_context *m68k = vcontext; | |
181 genesis_context *gen = m68k->system; | |
182 segacd_context *cd = gen->expansion; | |
183 uint32_t reg = (address & 0x1FF) >> 1; | |
184 uint16_t value16; | |
185 if (address & 1) { | |
186 value16 = cd->gate_array[reg] & 0xFF00 | value; | |
187 } else { | |
188 value16 = cd->gate_array[reg] & 0xFF | (value << 8); | |
189 } | |
190 return main_gate_write16(address, vcontext, value16); | |
191 } | |
192 | |
193 segacd_context *alloc_configure_segacd(system_media *media, uint32_t opts, uint8_t force_region, rom_info *info) | |
194 { | |
195 static memmap_chunk sub_cpu_map[] = { | |
196 {0x000000, 0x00FEFF, 0x0000, .flags=MMAP_READ | MMAP_CODE, .write_16 = prog_ram_wp_write16, .write_8 = prog_ram_wp_write8}, | |
197 {0x00FF00, 0x07FFFF, 0x0000, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE}, | |
198 {0x080000, 0x0BFFFF, 0x0000, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 0, | |
199 .read_16 = work_ram_2M_read16, .write_16 = work_ram_2M_write16, .read_8 = work_ram_2M_read8, .write_8 = work_ram_2M_write8}, | |
200 {0x0C0000, 0x0DFFFF, 0x0000, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 1, | |
201 .read_16 = work_ram_1M_read16, .write_16 = work_ram_1M_write16, .read_8 = work_ram_1M_read8, .write_8 = work_ram_1M_write8}, | |
202 {0xFE0000, 0xFEFFFF, 0x3FFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_ONLY_ODD}, | |
203 {0xFF0000, 0xFF7FFF, 0x0000, .read_16 = pcm_read16, .write_16 = pcm_write16, .read_8 = pcm_read8, .write_8 = pcm_write8}, | |
204 {0xFF8000, 0xFF81FF, 0x0000, .read_16 = sub_gate_read16, .write_16 = sub_gate_write16, .read_8 = sub_gate_read8, .write_8 = sub_gate_write8} | |
205 }; | |
206 segacd_context *cd = calloc(sizeof(segacd_context), 1); | |
207 FILE *f = fopen("cdbios.bin", "rb"); | |
208 if (!f) { | |
209 fatal_error("Failed to open CD firmware for reading"); | |
210 } | |
211 long firmware_size = file_size(f); | |
212 uint32_t adjusted_size = nearest_pow2(firmware_size); | |
213 cd->rom = malloc(adjusted_size); | |
214 if (firmware_size != fread(cd->rom, 1, firmware_size, f)) { | |
215 fatal_error("Failed to read CD firmware"); | |
216 } | |
217 cd->rom_mut = malloc(adjusted_size); | |
218 memcpy(cd->rom_mut, cd->rom, adjusted_size); | |
219 byteswap_rom(firmware_size, cd->rom); | |
220 cd->prog_ram = malloc(512*1024); | |
221 cd->work_ram = malloc(256*1024); | |
222 cd->pcm_ram = malloc(64*1024); | |
223 //TODO: Load state from file | |
224 cd->bram = malloc(8*1024); | |
225 | |
226 sub_cpu_map[0].buffer = sub_cpu_map[1].buffer = cd->prog_ram; | |
227 sub_cpu_map[4].buffer = cd->bram; | |
228 m68k_options *mopts = malloc(sizeof(m68k_options)); | |
229 init_m68k_opts(mopts, sub_cpu_map, sizeof(sub_cpu_map) / sizeof(*sub_cpu_map), 4); | |
230 cd->m68k = init_68k_context(mopts, NULL); | |
231 cd->m68k->system = cd; | |
232 cd->busreq = 1; | |
233 cd->busack = 1; | |
234 | |
235 return cd; | |
236 } | |
237 | |
238 memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint32_t *num_chunks) | |
239 { | |
240 static memmap_chunk main_cpu_map[] = { | |
241 {0x000000, 0x01FFFF, 0x00000, .flags=MMAP_READ}, | |
242 {0x020000, 0x03FFFF, 0x1FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL, .ptr_index = 0},//TODO: support running main CPU code from here | |
243 {0x040000, 0x05FFFF, 0x1FFFF, .flags=MMAP_READ}, //first ROM alias | |
244 //TODO: additional ROM/prog RAM aliases | |
245 {0x200000, 0x01FFFF, 0x1FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL, .ptr_index = 1}, | |
246 {0x220000, 0x03FFFF, 0x1FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL, .ptr_index = 2}, | |
247 }; | |
248 //TODO: support cart boot maps | |
249 //TODO: support BRAM cart | |
250 main_cpu_map[0].buffer = cd->rom_mut; | |
251 main_cpu_map[2].buffer = cd->rom; | |
252 main_cpu_map[1].buffer = cd->prog_ram; | |
253 main_cpu_map[3].buffer = cd->work_ram; | |
254 main_cpu_map[3].buffer = cd->work_ram + 0x10000; | |
255 *num_chunks = sizeof(main_cpu_map) / sizeof(*main_cpu_map); | |
256 return main_cpu_map; | |
257 } |