Created
June 9, 2015 21:01
-
-
Save safiire/04e98b2b5cf19fedd065 to your computer and use it in GitHub Desktop.
Manipulation of Memory Mapped Registers using C++ Templates (Technique from Olivier Gillet's Avril AVR Library)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdint.h> | |
//// Create some pretend Memory Mapped Registers | |
volatile uint64_t memory_mapped_registers[] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; | |
#define bit_depth uint64_t | |
#define mmio_byte(mem_addr) (*(volatile bit_depth *)(mem_addr)) | |
//// Create 8 fake registers | |
#define R0 mmio_byte(memory_mapped_registers + 0) | |
#define R1 mmio_byte(memory_mapped_registers + 1) | |
#define R2 mmio_byte(memory_mapped_registers + 2) | |
#define R3 mmio_byte(memory_mapped_registers + 3) | |
#define R4 mmio_byte(memory_mapped_registers + 4) | |
#define R5 mmio_byte(memory_mapped_registers + 5) | |
#define R6 mmio_byte(memory_mapped_registers + 6) | |
#define R7 mmio_byte(memory_mapped_registers + 7) | |
//// A struct wrapper around a register | |
#define IORegister(reg) \ | |
struct reg##Register { \ | |
static volatile bit_depth *ptr(){ \ | |
return ® \ | |
} \ | |
reg##Register &operator=(const bit_depth &value){ \ | |
*ptr() = value; \ | |
return *this; \ | |
} \ | |
}; | |
IORegister(R0); | |
IORegister(R1); | |
IORegister(R2); | |
IORegister(R3); | |
IORegister(R4); | |
IORegister(R5); | |
IORegister(R6); | |
IORegister(R7); | |
//// | |
// Control of one bit in a register | |
template <typename Register, uint8_t bit> | |
struct BitInRegister { | |
static void clear(){ | |
*Register::ptr() &= ~(1 << bit); | |
} | |
static void set(){ | |
*Register::ptr() |= (1 << bit); | |
} | |
static void toggle(){ | |
*Register::ptr() ^= (1 << bit); | |
} | |
static bit_depth value(){ | |
return *Register::ptr() & (1 <<bit) ? 1 : 0; | |
} | |
}; | |
//// | |
// A resource that can make us get pizza for dinner, by specifying bits in the registers | |
template <typename PizzaEnableBit, typename DinnerTimeBit, typename FullOfFoodBit> | |
struct FoodController { | |
typedef PizzaEnableBit Pizza; | |
typedef DinnerTimeBit Dinner; | |
typedef FullOfFoodBit Full; | |
static inline void eat_pizza_for_dinner(){ | |
Pizza::set(); | |
Dinner::set(); | |
} | |
static inline void pizza_done(){ | |
Pizza::clear(); | |
Dinner::clear(); | |
Full::set(); | |
} | |
}; | |
//// Shorthand type that knows about these specific bits. | |
typedef FoodController< BitInRegister<R4Register, 5>, | |
BitInRegister<R1Register, 2>, BitInRegister<R7Register, 7> > PizzaController; | |
int main(void){ | |
PizzaController::eat_pizza_for_dinner(); | |
for(int i = 0; i < 8; i++){ | |
printf("R%d: %lld\n", i, memory_mapped_registers[i]); | |
} | |
PizzaController::pizza_done(); | |
for(int i = 0; i < 8; i++){ | |
printf("R%d: %lld\n", i, memory_mapped_registers[i]); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment