summaryrefslogtreecommitdiffstats
path: root/emulator/memory.h
blob: ba309994022b01cb160c0e09a2b68a5baea2c5f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#ifndef AVREMU_MEMORY_H_
#define AVREMU_MEMORY_H_

#include "util.h"

#include <stdint.h>
#include <pthread.h>


typedef void (*io_write_handler_t)(uint16_t mem_offset, uint8_t old_val, uint8_t new_val);
typedef void (*io_read_handler_t)(uint16_t mem_offset);


/* ==== MEMORY SPACE LOCKING ====
 *
 * Accessing the register file:
 * 	From inside of the CPU the register file can
 * 	be accessed without taking any locks.
 * 	From outside of the CPU, the CPU must first be
 * 	trapped to synchronize the register file.
 *
 * Accessing the conventional IO space or the MMIO space:
 * 	The io_lock has to be acquired from any context.
 *
 * Accessing the SRAM memory space:
 * 	From inside of the CPU the SRAM can
 * 	be accessed without taking any locks.
 * 	From outside of the CPU, the CPU must first be
 * 	trapped to synchronize the SRAM.
 *
 * Exceptions:
 * 	The Stack Pointer is accessed locklessly from inside
 * 	of the CPU. From outside of the CPU, the CPU must first
 * 	be trapped to synchronize and lock the stack pointer data.
 */


/* Abtract I/O port identifiers. */
enum avr_io_port {
	IO_TWBR,
	IO_TWSR,
	IO_TWAR,
	IO_TWDR,
	IO_ADCL,
	IO_ADCH,
	IO_ADCSRA,
	IO_ADCSRB,
	IO_ADMUX,
	IO_ADCSR,
	IO_UBRRL,
	IO_UCSRB,
	IO_UCSRA,
	IO_UDR,
	IO_SPCR,
	IO_SPSR,
	IO_SPDR,
	IO_PIND,
	IO_DDRD,
	IO_PORTD,
	IO_PINC,
	IO_DDRC,
	IO_PORTC,
	IO_PINB,
	IO_DDRB,
	IO_PORTB,
	IO_EECR,
	IO_EEDR,
	IO_EEARL,
	IO_EEARH,
	IO_UCSRC,
	IO_UBRRH,
	IO_WDTCR,
	IO_ASSR,
	IO_OCR2,
	IO_TCNT2,
	IO_TCCR2,
	IO_ICR1L,
	IO_ICR1H,
	IO_OCR1BL,
	IO_OCR1BH,
	IO_OCR1AL,
	IO_OCR1AH,
	IO_TCNT1L,
	IO_TCNT1H,
	IO_TCCR1B,
	IO_TCCR1A,
	IO_SFIOR,
	IO_OSCAL,
	IO_TCNT0,
	IO_TCCR0,
	IO_MCUCSR,
	IO_MCUCR,
	IO_TWCR,
	IO_SPMCR,
	IO_TIFR,
	IO_TIFR0,
	IO_TIFR1,
	IO_TIFR2,
	IO_TIMSK,
	IO_GIFR,
	IO_GICR,
	IO_SPL,
	IO_SPH,
	IO_SREG,
	IO_PCIFR,
	IO_EIFR,
	IO_EIMSK,
	IO_GPIOR0,
	IO_GTCCR,
	IO_TCCR0A,
	IO_TCCR0B,
	IO_OCR0A,
	IO_OCR0B,
	IO_GPIOR1,
	IO_GPIOR2,
	IO_ACSR,
	IO_SMCR,
	IO_MCUSR,
	IO_SPMCSR,
	IO_WDRCSR,
	IO_CLKPR,
	IO_PRR,
	IO_PCICR,
	IO_EICRA,
	IO_PCMSK0,
	IO_PCMSK1,
	IO_PCMSK2,
	IO_TIMSK0,
	IO_TIMSK1,
	IO_TIMSK2,
	IO_DIDR0,
	IO_DIDR1,
	IO_TCCR1C,
	IO_TCCR2A,
	IO_TCCR2B,
	IO_OCR2A,
	IO_OCR2B,
	IO_TWAMR,
	IO_UCSR0A,
	IO_UCSR0B,
	IO_UCSR0C,
	IO_UBRR0L,
	IO_UBRR0H,
	IO_UDR0,
	NR_VIRT_IO_PORTS,
};

struct avr_memory {
	/* The whole memory area. */
	uint8_t *ram;
	/* Size of the whole memory region. */
	size_t size;
	/* Conventional IO space. */
	uint8_t *io;
	/* Size of the IO and MMIO space. */
	size_t iospace_size;
	/* The offset where the general purpose SRAM starts. */
	size_t sram_offset;

	/* Lock for the IO and MMIO space. */
	pthread_spinlock_t io_lock;

	/* The offset of the stack pointer in the IO space. */
	uint8_t sp_offset;

	/* Array of I/O access handlers. One for each I/O and MMIO address. */
	io_write_handler_t *io_write_handlers;
	io_read_handler_t *io_read_handlers;

	/* Map array for mapping abstract IO port IDs to their
	 * physical hardware address. */
	uint16_t physical_io_map[NR_VIRT_IO_PORTS];
};

/* Value for the physical_io_map when the port doesn't exist. */
#define IO_PORT_UNAVAILABLE	0xFFFF

/* IO memory always starts at the 32th byte. */
#define IO_MEM_OFFSET	32

extern struct avr_memory memory;


/* Map a virtual IO cookie to its physical address in the AVR memory space. */
static inline uint16_t io_virt_to_phys(enum avr_io_port virt)
{
	return memory.physical_io_map[virt];
}

static inline bool mem_offset_in_io_region(uint16_t offset)
{
	return ((offset >= IO_MEM_OFFSET) && (offset < memory.sram_offset));
}

static inline void memory_lock(uint16_t offset, uint8_t *lock_flags)
{
	if (mem_offset_in_io_region(offset)) {
		pthread_spin_lock(&memory.io_lock);
		*lock_flags = 1;
		return;
	}
	*lock_flags = 0;
}

static inline void memory_unlock(uint8_t lock_flags)
{
	if (lock_flags)
		pthread_spin_unlock(&memory.io_lock);
}


/* Register a handler for an I/O register access.
 * Note that the handler will be called from CPU thread context!
 * That means it will run in concurrency to the main worker process thread.
 * Use locking. */
int register_io_write_handler(io_write_handler_t handler, enum avr_io_port virt);
int register_io_read_handler(io_read_handler_t handler, enum avr_io_port virt);


int memory_initialize(void);
void memory_cleanup(void);



#endif /* AVREMU_MEMORY_H_ */
bues.ch cgit interface