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}