/ src / common / memory.c
memory.c
  1  /*
  2   * memory.c
  3   *
  4   * Copyright (C) 1999 Jonathan St-André
  5   * Copyright (C) 1999 Hugo Villeneuve <hugo@hugovil.com>
  6   *
  7   * This file is released under the GPLv2
  8   */
  9  
 10  #include <stdbool.h>
 11  #include <stdio.h>
 12  #include <string.h>
 13  
 14  #include "common.h"
 15  #include "cpu8051.h"
 16  #include "reg8051.h"
 17  #include "hexfile.h"
 18  #include "memory.h"
 19  #include "options.h"
 20  
 21  struct mem_infos_t {
 22  	int size;
 23  	int max_size;
 24  	uint8_t *buf;
 25  };
 26  
 27  struct mem_infos_t mem_infos[MEM_ID_COUNT];
 28  
 29  extern struct options_t options;
 30  
 31  /* Init each 8051 memory sections. */
 32  void
 33  mem_init(void)
 34  {
 35  	int k;
 36  	struct mem_infos_t *m;
 37  
 38  	/* Set desired and maximum allowable sizes for each memory type. */
 39  	mem_infos[PGM_MEM_ID].size = options.pram_size;
 40  	mem_infos[PGM_MEM_ID].max_size = PGM_MEM_MAX_SIZE;
 41  
 42  	mem_infos[INT_MEM_ID].size = options.iram_size;
 43  	mem_infos[INT_MEM_ID].max_size = INT_MEM_MAX_SIZE;
 44  
 45  	mem_infos[EXT_MEM_ID].size = options.xram_size;
 46  	mem_infos[EXT_MEM_ID].max_size = EXT_MEM_MAX_SIZE;
 47  
 48  	/* Verify if desired sizes are valid, and if so allocate memory. */
 49  	for (k = 0; k < MEM_ID_COUNT; k++) {
 50  		m = &mem_infos[k];
 51  
 52  		if (m->size > m->max_size) {
 53  			log_fail("Memory size invalid (max = %d)", m->max_size);
 54  		}
 55  
 56  		m->buf = malloc(m->size);
 57  		if (m->buf == NULL) {
 58  			log_fail("%s", strerror(errno));
 59  		}
 60  
 61  		memset(m->buf, 0x00, m->size);
 62  	}
 63  }
 64  
 65  /* Return true if address is valid, false otherwise. */
 66  int
 67  mem_check_address(enum mem_id_t id, unsigned long address, int display_error)
 68  {
 69  	if (address >= (unsigned long) mem_infos[id].max_size) {
 70  		if (display_error == DISPLAY_ERROR_YES)
 71  			log_err("Address out of range ($%X >= $%X", address,
 72  				mem_infos[id].max_size - 1);
 73  		return false;
 74  	} else {
 75  		return true;
 76  	}
 77  }
 78  
 79  void
 80  mem_convert_bit_address(uint8_t bit_address, uint8_t *byte_address,
 81  			uint8_t *bit_number)
 82  {
 83  	if (bit_address > 0x7F) {
 84  		/* SFR 80-FF */
 85  		*byte_address = bit_address & 0xF8;
 86  		*bit_number = bit_address & 0x07;
 87  	} else {
 88  		/* 20-2F */
 89  		*byte_address = (bit_address >> 3) + 0x20;
 90  		*bit_number = bit_address & 0x07;
 91  	}
 92  }
 93  
 94  uint8_t *
 95  mem_getbuf(enum mem_id_t id, unsigned long address)
 96  {
 97  	return &mem_infos[id].buf[address];
 98  }
 99  
100  void
101  mem_clear(enum mem_id_t id)
102  {
103  	memset(mem_infos[id].buf, 0, mem_infos[id].size);
104  }
105  
106  void
107  mem_write8(enum mem_id_t id, unsigned long address, uint8_t value)
108  {
109  	if (address >= (unsigned long) mem_infos[id].max_size) {
110  		log_err("Error writing to memory ID: %d\n"
111  			"  Address (%lu) greater than maximum memory size",
112  			id, address);
113  		return;
114  	} else {
115  		mem_infos[id].buf[address] = value;
116  	}
117  }
118  
119  /* Write with a direct addressing mode at Address the new Value */
120  void
121  mem_write_direct(unsigned int address, unsigned char value)
122  {
123  	mem_write8(INT_MEM_ID, address, value);
124  }
125  
126  /* Write with an indirect addressing mode at Address the new Value */
127  void
128  mem_write_indirect(unsigned int address, unsigned char value)
129  {
130  	if (address > 0x7F) {
131  		mem_write8(EXT_MEM_ID, address, value);
132  		return;
133  	}
134  
135  	mem_write8(INT_MEM_ID, address, value);
136  }
137  
138  /* Write with a bit addressing mode at BitAddress the new Value */
139  void
140  mem_write_bit(uint8_t bit_address, uint8_t value)
141  {
142  	uint8_t byte_address;
143  	uint8_t bit_number;
144  	unsigned char byte_val, byte_mask;
145  
146  	mem_convert_bit_address(bit_address, &byte_address, &bit_number);
147  
148  	byte_mask = ((1 << bit_number) ^ 0xFF);
149  	byte_val = mem_read_direct(byte_address) & byte_mask;
150  	byte_val += value << bit_number;
151  	mem_write_direct(byte_address, byte_val);
152  }
153  
154  void
155  mem_sfr_write8(unsigned long address, uint8_t value)
156  {
157  	/* SFR registers are from addresses $80 to $FF. */
158  	mem_write8(INT_MEM_ID, address, value);
159  }
160  
161  void
162  mem_sfr_write_dptr(uint16_t value)
163  {
164  	mem_write8(INT_MEM_ID, _DPTRHIGH_, value >> 8);
165  	mem_write8(INT_MEM_ID, _DPTRLOW_, (uint8_t) value);
166  }
167  
168  uint8_t
169  mem_read8(enum mem_id_t id, unsigned long address)
170  {
171  	if (address >= (unsigned long) mem_infos[id].max_size) {
172  		log_err("Error reading from memory ID: %d\n"
173  			"  Address (%lu) greater than maximum memory size",
174  			id, address);
175  		return 0;
176  	} else {
177  		return mem_infos[id].buf[address];
178  	}
179  }
180  
181  /* Read with a direct addressing mode at Address */
182  unsigned char
183  mem_read_direct(unsigned int address)
184  {
185  	if (address > 0xFF)
186  		return mem_read8(EXT_MEM_ID, address);
187  	else
188  		return mem_read8(INT_MEM_ID, address);
189  }
190  
191  /* Read with a indirect addressing mode at Address */
192  unsigned char
193  mem_read_indirect(unsigned int address)
194  {
195  	if (address > 0x7F)
196  		return mem_read8(EXT_MEM_ID, address);
197  	else
198  		return mem_read8(INT_MEM_ID, address);
199  }
200  
201  /* Read with a bit addressing mode at bit_address */
202  unsigned char
203  mem_read_bit(uint8_t bit_address)
204  {
205  	uint8_t byte_address;
206  	uint8_t bit_number;
207  	unsigned char bit_value;
208  
209  	mem_convert_bit_address(bit_address, &byte_address, &bit_number);
210  
211  	bit_value = (mem_read_direct(byte_address) >> bit_number);
212  	bit_value &= 1;
213  	return bit_value;
214  }
215  
216  uint8_t
217  mem_sfr_read8(unsigned long address)
218  {
219  	/* SFR registers are from addresses $80 to $FF. */
220  	return mem_read8(INT_MEM_ID, address);
221  }
222  
223  uint16_t
224  mem_sfr_read_dptr(void)
225  {
226  	return (mem_read8(INT_MEM_ID, _DPTRHIGH_) << 8) +
227  		mem_read8(INT_MEM_ID, _DPTRLOW_);
228  }
229  
230  void
231  stack_push8(uint8_t value)
232  {
233  	uint8_t sp;
234  
235  	sp = mem_read8(INT_MEM_ID, _SP_);
236  
237  	mem_write8(INT_MEM_ID, ++sp, value);
238  	mem_write8(INT_MEM_ID, _SP_, sp); /* Save new stack pointer */
239  }
240  
241  void
242  stack_push16(uint16_t value)
243  {
244  	uint8_t sp;
245  
246  	sp = mem_read8(INT_MEM_ID, _SP_);
247  
248  	mem_write8(INT_MEM_ID, ++sp, (uint8_t) value); /* Write LSB */
249  	mem_write8(INT_MEM_ID, ++sp, value >> 8);      /* Write MSB */
250  	mem_write8(INT_MEM_ID, _SP_, sp); /* Save new stack pointer */
251  }
252  
253  uint8_t
254  stack_pop8(void)
255  {
256  	uint8_t sp;
257  	uint8_t value;
258  
259  	sp = mem_read8(INT_MEM_ID, _SP_);
260  
261  	value = mem_read8(INT_MEM_ID, sp--);
262  	mem_write8(INT_MEM_ID, _SP_, sp); /* Save new stack pointer */
263  
264  	return value;
265  }
266  
267  uint16_t
268  stack_pop16(void)
269  {
270  	uint8_t sp;
271  	uint16_t value;
272  
273  	sp = mem_read8(INT_MEM_ID, _SP_);
274  
275  	value = mem_read8(INT_MEM_ID, sp--) << 8; /* Read MSB */
276  	value |= mem_read8(INT_MEM_ID, sp--);     /* Read LSB */
277  	mem_write8(INT_MEM_ID, _SP_, sp); /* Save new stack pointer */
278  
279  	return value;
280  }
281  
282  /* Read a 16-bit address from PGM memory, starting at <base> offset */
283  uint16_t
284  pgm_read_addr16(uint16_t base)
285  {
286  	uint16_t addr;
287  
288  	addr = mem_read8(PGM_MEM_ID, base) << 8; /* MSB */
289  	addr |= mem_read8(PGM_MEM_ID, base + 1); /* LSB */
290  
291  	return addr;
292  }
293  
294  /* Dump memory */
295  void
296  mem_dump(unsigned int address, int size, enum mem_id_t id)
297  {
298  	int rc;
299  	int offset, col;
300  
301  	if (size == 0) {
302  		log_err("invalid size: 0");
303  		return;
304  	}
305  
306  	/* Validate start address. */
307  	rc = mem_check_address(id, address, DISPLAY_ERROR_YES);
308  	if (!rc) {
309  		/* Validate end address. */
310  		rc = mem_check_address(id, address + (size - 1),
311  				       DISPLAY_ERROR_NO);
312  		if (!rc)
313  			log_err("Trying to read beyond memory limit");
314  	}
315  
316  	if (!rc)
317  		return;
318  
319  	for (offset = 0; offset < size; offset += 16) {
320  		uint8_t data[16];
321  
322  		printf("%.4X ", address + offset);
323  
324  		for (col = 0; col < 16; col++) {
325  			data[col] = mem_read8(id, address + offset + col);
326  			printf(" %.2X", data[col]);
327  		}
328  		printf("  ");
329  
330  		/* Display any ASCII characters */
331  		for (col = 0; col < 16; col++) {
332  			if ((int) data[col] >= 32 &&
333  			    (int) data[col] <= 126)
334  				printf("%c", (char) data[col]);
335  			else
336  				printf(".");
337  		}
338  		printf("\n");
339  	}
340  }