#ifndef AVREMU_MEMORY_H_ #define AVREMU_MEMORY_H_ #include "util.h" #include #include 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_ */