Mercurial > repos > blastem
comparison sega_mapper.c @ 2052:3748a2a8a4b7
Support Sega mapper without 'SEGA SSF' in header or ROM DB entry and implement a subset of the extended Sega mapper implemented in the Mega Everdrive when 'SEGA SSF' is present
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 01 Jan 2022 18:54:46 -0800 |
parents | d60f2d7c02a5 |
children | b6fdedd3b070 |
comparison
equal
deleted
inserted
replaced
2051:97bfb6089274 | 2052:3748a2a8a4b7 |
---|---|
1 #include "genesis.h" | 1 #include "genesis.h" |
2 #include "util.h" | |
2 | 3 |
3 uint16_t read_sram_w(uint32_t address, m68k_context * context) | 4 uint16_t read_sram_w(uint32_t address, m68k_context * context) |
4 { | 5 { |
5 genesis_context * gen = context->system; | 6 genesis_context * gen = context->system; |
6 address &= gen->save_ram_mask; | 7 address &= gen->save_ram_mask; |
41 } | 42 } |
42 | 43 |
43 m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value) | 44 m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value) |
44 { | 45 { |
45 genesis_context * gen = context->system; | 46 genesis_context * gen = context->system; |
47 if (gen->mapper_type == MAPPER_SEGA_MED_V2) { | |
48 if (gen->bank_regs[8] & 0x20) { | |
49 uint32_t bank = address >> 19; | |
50 address &= 0x7FFFF; | |
51 context->mem_pointers[gen->mapper_start_index + bank][address >> 1] = value; | |
52 } | |
53 return context; | |
54 } | |
46 if ((gen->bank_regs[0] & 0x3) == 1) { | 55 if ((gen->bank_regs[0] & 0x3) == 1) { |
47 address &= gen->save_ram_mask; | 56 address &= gen->save_ram_mask; |
48 switch(gen->save_type) | 57 switch(gen->save_type) |
49 { | 58 { |
50 case RAM_FLAG_BOTH: | 59 case RAM_FLAG_BOTH: |
85 } | 94 } |
86 } | 95 } |
87 return context; | 96 return context; |
88 } | 97 } |
89 | 98 |
99 static void* write_med_ram_w(uint32_t address, void *vcontext, uint16_t value, uint16_t bank) | |
100 { | |
101 m68k_context *context = vcontext; | |
102 genesis_context * gen = context->system; | |
103 if (gen->bank_regs[8] & 0x20) { | |
104 context->mem_pointers[gen->mapper_start_index + bank][address >> 1] = value; | |
105 address += bank * 0x80000; | |
106 m68k_invalidate_code_range(gen->m68k, address, address + 2); | |
107 } | |
108 return vcontext; | |
109 } | |
110 | |
111 void* write_med_ram0_w(uint32_t address, void *vcontext, uint16_t value) | |
112 { | |
113 return write_med_ram_w(address, vcontext, value, 0); | |
114 } | |
115 | |
116 void* write_med_ram1_w(uint32_t address, void *vcontext, uint16_t value) | |
117 { | |
118 return write_med_ram_w(address, vcontext, value, 1); | |
119 } | |
120 | |
121 void* write_med_ram2_w(uint32_t address, void *vcontext, uint16_t value) | |
122 { | |
123 return write_med_ram_w(address, vcontext, value, 2); | |
124 } | |
125 | |
126 void* write_med_ram3_w(uint32_t address, void *vcontext, uint16_t value) | |
127 { | |
128 return write_med_ram_w(address, vcontext, value, 3); | |
129 } | |
130 | |
131 void* write_med_ram4_w(uint32_t address, void *vcontext, uint16_t value) | |
132 { | |
133 return write_med_ram_w(address, vcontext, value, 4); | |
134 } | |
135 | |
136 void* write_med_ram5_w(uint32_t address, void *vcontext, uint16_t value) | |
137 { | |
138 return write_med_ram_w(address, vcontext, value, 5); | |
139 } | |
140 | |
141 void* write_med_ram6_w(uint32_t address, void *vcontext, uint16_t value) | |
142 { | |
143 return write_med_ram_w(address, vcontext, value, 6); | |
144 } | |
145 | |
146 void* write_med_ram7_w(uint32_t address, void *vcontext, uint16_t value) | |
147 { | |
148 return write_med_ram_w(address, vcontext, value, 7); | |
149 } | |
150 | |
151 static void* write_med_ram_b(uint32_t address, void *vcontext, uint8_t value, uint16_t bank) | |
152 { | |
153 m68k_context *context = vcontext; | |
154 genesis_context * gen = context->system; | |
155 if (gen->bank_regs[8] & 0x20) { | |
156 ((uint8_t*)context->mem_pointers[gen->mapper_start_index + bank])[address ^ 1] = value; | |
157 address += bank * 0x80000; | |
158 m68k_invalidate_code_range(gen->m68k, address, address + 1); | |
159 } | |
160 return vcontext; | |
161 } | |
162 | |
163 void* write_med_ram0_b(uint32_t address, void *vcontext, uint8_t value) | |
164 { | |
165 return write_med_ram_b(address, vcontext, value, 0); | |
166 } | |
167 | |
168 void* write_med_ram1_b(uint32_t address, void *vcontext, uint8_t value) | |
169 { | |
170 return write_med_ram_b(address, vcontext, value, 1); | |
171 } | |
172 | |
173 void* write_med_ram2_b(uint32_t address, void *vcontext, uint8_t value) | |
174 { | |
175 return write_med_ram_b(address, vcontext, value, 2); | |
176 } | |
177 | |
178 void* write_med_ram3_b(uint32_t address, void *vcontext, uint8_t value) | |
179 { | |
180 return write_med_ram_b(address, vcontext, value, 3); | |
181 } | |
182 | |
183 void* write_med_ram4_b(uint32_t address, void *vcontext, uint8_t value) | |
184 { | |
185 return write_med_ram_b(address, vcontext, value, 4); | |
186 } | |
187 | |
188 void* write_med_ram5_b(uint32_t address, void *vcontext, uint8_t value) | |
189 { | |
190 return write_med_ram_b(address, vcontext, value, 5); | |
191 } | |
192 | |
193 void* write_med_ram6_b(uint32_t address, void *vcontext, uint8_t value) | |
194 { | |
195 return write_med_ram_b(address, vcontext, value, 6); | |
196 } | |
197 | |
198 void* write_med_ram7_b(uint32_t address, void *vcontext, uint8_t value) | |
199 { | |
200 return write_med_ram_b(address, vcontext, value, 7); | |
201 } | |
202 | |
90 m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value) | 203 m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value) |
91 { | 204 { |
92 genesis_context * gen = context->system; | 205 genesis_context * gen = context->system; |
93 address &= 0xE; | 206 address &= 0xE; |
94 address >>= 1; | 207 address >>= 1; |
95 gen->bank_regs[address] = value; | |
96 if (!address) { | 208 if (!address) { |
97 if (value & 1) { | 209 if (gen->mapper_type == MAPPER_SEGA_MED_V2) { |
210 if (!value & 0x8000) { | |
211 //writes without protection bit set are ignored | |
212 return context; | |
213 } | |
214 gen->bank_regs[8] = value >> 8; | |
215 void *new_ptr = gen->cart + 0x40000*(value & 0x1F); | |
216 if (context->mem_pointers[gen->mapper_start_index] != new_ptr) { | |
217 m68k_invalidate_code_range(gen->m68k, 0, 0x80000); | |
218 context->mem_pointers[gen->mapper_start_index] = new_ptr; | |
219 } | |
220 } else if (value & 1) { | |
98 //Used for games that only use the mapper for SRAM | 221 //Used for games that only use the mapper for SRAM |
99 if (context->mem_pointers[gen->mapper_start_index]) { | 222 if (context->mem_pointers[gen->mapper_start_index]) { |
100 gen->mapper_temp = context->mem_pointers[gen->mapper_start_index]; | 223 gen->mapper_temp = context->mem_pointers[gen->mapper_start_index]; |
101 } | 224 } |
102 context->mem_pointers[gen->mapper_start_index] = NULL; | 225 context->mem_pointers[gen->mapper_start_index] = NULL; |
114 for (int i = 4; i < 8; i++) | 237 for (int i = 4; i < 8; i++) |
115 { | 238 { |
116 context->mem_pointers[gen->mapper_start_index + i] = gen->cart + 0x40000*gen->bank_regs[i]; | 239 context->mem_pointers[gen->mapper_start_index + i] = gen->cart + 0x40000*gen->bank_regs[i]; |
117 } | 240 } |
118 } | 241 } |
119 } else if (gen->mapper_type == MAPPER_SEGA) { | 242 } else if (gen->mapper_type != MAPPER_SEGA_SRAM) { |
120 void *new_ptr = gen->cart + 0x40000*value; | 243 uint32_t mask = ((gen->mapper_type == MAPPER_SEGA_MED_V2 ? (16 *1024 * 1024) : nearest_pow2(gen->header.info.rom_size)) >> 1) - 1; |
244 void *new_ptr = gen->cart + ((0x40000*value) & mask); | |
121 if (context->mem_pointers[gen->mapper_start_index + address] != new_ptr) { | 245 if (context->mem_pointers[gen->mapper_start_index + address] != new_ptr) { |
122 m68k_invalidate_code_range(gen->m68k, address * 0x80000, (address + 1) * 0x80000); | 246 m68k_invalidate_code_range(gen->m68k, address * 0x80000, (address + 1) * 0x80000); |
123 context->mem_pointers[gen->mapper_start_index + address] = new_ptr; | 247 context->mem_pointers[gen->mapper_start_index + address] = new_ptr; |
124 } | 248 } |
125 } | 249 } |
250 gen->bank_regs[address] = value; | |
126 return context; | 251 return context; |
127 } | 252 } |
128 | 253 |
129 m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value) | 254 m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value) |
130 { | 255 { |
131 if (address & 1) { | 256 genesis_context * gen = context->system; |
257 if (gen->mapper_type == MAPPER_SEGA_MED_V2) { | |
258 address &= 0xF; | |
259 if (!address) { | |
260 //not sure if this is correct, possible byte sized writes are always rejected to $A130F0 | |
261 write_bank_reg_w(address, context, value << 8 | value); | |
262 } else if (address > 2 && (address & 1)) { | |
263 write_bank_reg_w(address, context, value); | |
264 } | |
265 } else if (address & 1) { | |
132 write_bank_reg_w(address, context, value); | 266 write_bank_reg_w(address, context, value); |
133 } | 267 } |
134 return context; | 268 return context; |
135 } | 269 } |
136 | 270 |
137 void sega_mapper_serialize(genesis_context *gen, serialize_buffer *buf) | 271 void sega_mapper_serialize(genesis_context *gen, serialize_buffer *buf) |
138 { | 272 { |
139 save_buffer8(buf, gen->bank_regs, sizeof(gen->bank_regs)); | 273 save_buffer8(buf, gen->bank_regs, gen->mapper_type == MAPPER_SEGA_MED_V2 ? sizeof(gen->bank_regs) : sizeof(gen->bank_regs) - 1); |
140 } | 274 } |
141 | 275 |
142 void sega_mapper_deserialize(deserialize_buffer *buf, genesis_context *gen) | 276 void sega_mapper_deserialize(deserialize_buffer *buf, genesis_context *gen) |
143 { | 277 { |
144 for (int i = 0; i < sizeof(gen->bank_regs); i++) | 278 if (gen->mapper_type == MAPPER_SEGA_MED_V2) { |
145 { | 279 uint16_t reg0 = load_int8(buf); |
146 write_bank_reg_w(i * 2, gen->m68k, load_int8(buf)); | 280 for (int i = 1; i < sizeof(gen->bank_regs) - 1; i++) |
147 } | 281 { |
148 } | 282 write_bank_reg_w(i * 2, gen->m68k, load_int8(buf)); |
283 } | |
284 reg0 |= load_int8(buf) << 8; | |
285 write_bank_reg_w(0, gen->m68k, reg0); | |
286 } else { | |
287 for (int i = 0; i < sizeof(gen->bank_regs) - 1; i++) | |
288 { | |
289 write_bank_reg_w(i * 2, gen->m68k, load_int8(buf)); | |
290 } | |
291 } | |
292 } |