main
backend.c
1/*
2 Copyright 2013 Michael Pavone
3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5*/
6#include "backend.h"
7#include <stdlib.h>
8
9deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest)
10{
11 deferred_addr * new_head = malloc(sizeof(deferred_addr));
12 new_head->next = old_head;
13 new_head->address = address & 0xFFFFFF;
14 new_head->dest = dest;
15 return new_head;
16}
17
18void remove_deferred_until(deferred_addr **head_ptr, deferred_addr * remove_to)
19{
20 for(deferred_addr *cur = *head_ptr; cur && cur != remove_to; cur = *head_ptr)
21 {
22 *head_ptr = cur->next;
23 free(cur);
24 }
25}
26
27void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_func get_native)
28{
29 deferred_addr * cur = *head_ptr;
30 deferred_addr **last_next = head_ptr;
31 while(cur)
32 {
33 code_ptr native = get_native(context, cur->address);//get_native_address(opts->native_code_map, cur->address);
34 if (native) {
35 int32_t disp = native - (cur->dest + 4);
36 code_ptr out = cur->dest;
37 *(out++) = disp;
38 disp >>= 8;
39 *(out++) = disp;
40 disp >>= 8;
41 *(out++) = disp;
42 disp >>= 8;
43 *out = disp;
44 *last_next = cur->next;
45 free(cur);
46 cur = *last_next;
47 } else {
48 last_next = &(cur->next);
49 cur = cur->next;
50 }
51 }
52}
53
54memmap_chunk const *find_map_chunk(uint32_t address, cpu_options *opts, uint16_t flags, uint32_t *size_sum)
55{
56 if (size_sum) {
57 *size_sum = 0;
58 }
59 address &= opts->address_mask;
60 for (memmap_chunk const *cur = opts->memmap, *end = opts->memmap + opts->memmap_chunks; cur != end; cur++)
61 {
62 if (address >= cur->start && address < cur->end) {
63 return cur;
64 } else if (size_sum && (cur->flags & flags) == flags) {
65 *size_sum += chunk_size(opts, cur);
66 }
67 }
68 return NULL;
69}
70
71void * get_native_pointer(uint32_t address, void ** mem_pointers, cpu_options * opts)
72{
73 memmap_chunk const * memmap = opts->memmap;
74 address &= opts->address_mask;
75 for (uint32_t chunk = 0; chunk < opts->memmap_chunks; chunk++)
76 {
77 if (address >= memmap[chunk].start && address < memmap[chunk].end) {
78 if (!(memmap[chunk].flags & (MMAP_READ|MMAP_READ_CODE))) {
79 return NULL;
80 }
81 uint8_t * base = memmap[chunk].flags & MMAP_PTR_IDX
82 ? mem_pointers[memmap[chunk].ptr_index]
83 : memmap[chunk].buffer;
84 if (!base) {
85 if (memmap[chunk].flags & MMAP_AUX_BUFF) {
86 return memmap[chunk].buffer + (address & memmap[chunk].aux_mask);
87 }
88 return NULL;
89 }
90 return base + (address & memmap[chunk].mask);
91 }
92 }
93 return NULL;
94}
95
96void * get_native_write_pointer(uint32_t address, void ** mem_pointers, cpu_options * opts)
97{
98 memmap_chunk const * memmap = opts->memmap;
99 address &= opts->address_mask;
100 for (uint32_t chunk = 0; chunk < opts->memmap_chunks; chunk++)
101 {
102 if (address >= memmap[chunk].start && address < memmap[chunk].end) {
103 if (!(memmap[chunk].flags & (MMAP_WRITE))) {
104 return NULL;
105 }
106 uint8_t * base = memmap[chunk].flags & MMAP_PTR_IDX
107 ? mem_pointers[memmap[chunk].ptr_index]
108 : memmap[chunk].buffer;
109 if (!base) {
110 if (memmap[chunk].flags & MMAP_AUX_BUFF) {
111 return memmap[chunk].buffer + (address & memmap[chunk].aux_mask);
112 }
113 return NULL;
114 }
115 return base + (address & memmap[chunk].mask);
116 }
117 }
118 return NULL;
119}
120
121uint16_t read_word(uint32_t address, void **mem_pointers, cpu_options *opts, void *context)
122{
123 memmap_chunk const *chunk = find_map_chunk(address, opts, 0, NULL);
124 if (!chunk) {
125 return 0xFFFF;
126 }
127 uint32_t offset = address & chunk->mask;
128 if (chunk->flags & MMAP_READ) {
129 uint8_t *base;
130 if (chunk->flags & MMAP_PTR_IDX) {
131 base = mem_pointers[chunk->ptr_index];
132 } else {
133 base = chunk->buffer;
134 }
135 if (base) {
136 uint16_t val;
137 if ((chunk->flags & MMAP_ONLY_ODD) || (chunk->flags & MMAP_ONLY_EVEN)) {
138 offset /= 2;
139 val = base[offset];
140 if (chunk->flags & MMAP_ONLY_ODD) {
141 val |= 0xFF00;
142 } else {
143 val = val << 8 | 0xFF;
144 }
145 } else {
146 val = *(uint16_t *)(base + offset);
147 }
148 return val;
149 }
150 }
151 if ((!(chunk->flags & MMAP_READ) || (chunk->flags & MMAP_FUNC_NULL)) && chunk->read_16) {
152 return chunk->read_16(offset, context);
153 }
154 return 0xFFFF;
155}
156
157uint8_t read_byte(uint32_t address, void **mem_pointers, cpu_options *opts, void *context)
158{
159 memmap_chunk const *chunk = find_map_chunk(address, opts, 0, NULL);
160 if (!chunk) {
161 return 0xFF;
162 }
163 uint32_t offset = address & chunk->mask;
164 if (chunk->flags & MMAP_READ) {
165 uint8_t *base;
166 if (chunk->flags & MMAP_PTR_IDX) {
167 base = mem_pointers[chunk->ptr_index];
168 } else {
169 base = chunk->buffer;
170 }
171 if (base) {
172 if ((chunk->flags & MMAP_ONLY_ODD) || (chunk->flags & MMAP_ONLY_EVEN)) {
173 if (address & 1) {
174 if (chunk->flags & MMAP_ONLY_EVEN) {
175 return 0xFF;
176 }
177 } else if (chunk->flags & MMAP_ONLY_ODD) {
178 return 0xFF;
179 }
180 offset /= 2;
181 }
182 return base[offset];
183 }
184 }
185 if ((!(chunk->flags & MMAP_READ) || (chunk->flags & MMAP_FUNC_NULL)) && chunk->read_8) {
186 return chunk->read_8(offset, context);
187 }
188 return 0xFF;
189}
190
191void write_byte(uint32_t address, uint8_t value, void **mem_pointers, cpu_options *opts, void *context)
192{
193 memmap_chunk const *chunk = find_map_chunk(address, opts, 0, NULL);
194 if (!chunk) {
195 return;
196 }
197 uint32_t offset = address & chunk->mask;
198 if (chunk->flags & MMAP_WRITE) {
199 uint8_t *base;
200 if (chunk->flags & MMAP_PTR_IDX) {
201 base = mem_pointers[chunk->ptr_index];
202 } else {
203 base = chunk->buffer;
204 }
205 if (base) {
206 if ((chunk->flags & MMAP_ONLY_ODD) || (chunk->flags & MMAP_ONLY_EVEN)) {
207 if (address & 1) {
208 if (chunk->flags & MMAP_ONLY_EVEN) {
209 return;
210 }
211 } else if (chunk->flags & MMAP_ONLY_ODD) {
212 return;
213 }
214 offset /= 2;
215 }
216 base[offset] = value;
217 }
218 }
219 if ((!(chunk->flags & MMAP_WRITE) || (chunk->flags & MMAP_FUNC_NULL)) && chunk->write_8) {
220 chunk->write_8(offset, context, value);
221 }
222}
223
224uint32_t chunk_size(cpu_options *opts, memmap_chunk const *chunk)
225{
226 if (chunk->mask == opts->address_mask) {
227 return chunk->end - chunk->start;
228 } else {
229 return chunk->mask + 1;
230 }
231}
232
233uint32_t ram_size(cpu_options *opts)
234{
235 uint32_t size = 0;
236 for (int i = 0; i < opts->memmap_chunks; i++)
237 {
238 if (opts->memmap[i].flags & MMAP_CODE) {
239 if (opts->memmap[i].mask == opts->address_mask) {
240 size += opts->memmap[i].end - opts->memmap[i].start;
241 } else {
242 size += opts->memmap[i].mask + 1;
243 }
244 }
245 }
246 return size;
247}