From 43428a27aa2212782e2c11368080b5a83e026bee Mon Sep 17 00:00:00 2001 From: Sam Stevens Date: Fri, 26 Oct 2018 23:30:27 +0100 Subject: [PATCH] Added TTL based LRU memory cache. --- arduino/arduino.ino | 40 ++++++++++++++++++++----- arduino/console.cpp | 5 ++-- arduino/memory.cpp | 72 +++++++++++++++++++++++++++++++++++++++++++++ arduino/memory.h | 20 +++++++++++++ arduino/vm.c | 4 +-- arduino/vm.h | 2 +- 6 files changed, 131 insertions(+), 12 deletions(-) diff --git a/arduino/arduino.ino b/arduino/arduino.ino index 50f8236..559a883 100644 --- a/arduino/arduino.ino +++ b/arduino/arduino.ino @@ -28,6 +28,8 @@ Console console(&vm); //Expecting a Microchip 23LCV512 connected over MOSI/MISO/MCLK Memory mem(20000000, MSBFIRST, SPI_MODE0, 4); +MemoryCache ICache(64, mem); +MemoryCache DCache(32, mem); void setup() { //Setup VM @@ -47,7 +49,6 @@ void setup() { if (!mem.init()) { Serial.println("Memory failed to init!"); } else { - mem.writeRange(0x55, 0, VM_MEM_SIZE); #ifdef TEST_DESTRUCTIVE Serial.print("Testing "); Serial.print(mem.getSize(), DEC); @@ -67,7 +68,6 @@ void setup() { void loop() { console.loop(); - } void vm_print_error(uint8_t err) { @@ -113,10 +113,36 @@ uint8_t vm_syscall(VM* vm, uint8_t callno, uint8_t imm) { return 0; } -uint8_t vm_read_addr(uint16_t addr) { - return mem.read(addr); -} -void vm_write_addr(uint16_t addr, uint8_t data) { - mem.write(addr, data); +uint8_t vm_read_addr(uint16_t addr, bool instruction) { + if (instruction) { + return ICache.read(addr); + } else { + return DCache.read(addr); + } +} + +void vm_write_addr(uint16_t addr, uint8_t data) { + mem.write(addr, data); + ICache.update(addr, data); + DCache.update(addr, data); +} + +void print_cache_state(MemoryCache& cache) { + for(uint8_t i = 0; i < cache.getSize(); i++) { + MemoryCacheItem* item = cache.getItem(i); + + Serial.print(i); + Serial.print(": "); + if (item->valid) { + Serial.print(item->addr, HEX); + Serial.print("="); + Serial.print(item->data, HEX); + Serial.print(" TTL "); + Serial.print(item->ttl); + Serial.println(""); + } else { + Serial.println("Nil"); + } + } } diff --git a/arduino/console.cpp b/arduino/console.cpp index 5cfb898..ff8482d 100644 --- a/arduino/console.cpp +++ b/arduino/console.cpp @@ -83,7 +83,7 @@ void Console::printMemory(uint16_t from, uint16_t to) { serial->print(i, HEX); serial->print(" "); } - uint8_t m = this->vm->readAddr(i); + uint8_t m = this->vm->readAddr(i, false); if (m < 0x10) { serial->print("0"); } @@ -235,7 +235,8 @@ void Console::stateView() { this->printRegisters(false); //Memory - this->printMemory(0, VM_MEM_SIZE-1); + this->printMemory(0, 0xFF); + serial->println("Output limited to 00-FF"); this->state = CONSOLE_ACTIVATE; }//Console::stateView diff --git a/arduino/memory.cpp b/arduino/memory.cpp index b131aa9..52592ca 100644 --- a/arduino/memory.cpp +++ b/arduino/memory.cpp @@ -125,3 +125,75 @@ bool Memory::test() { return true; } + +uint8_t MemoryCache::getSize() { + return this->cacheElements; +} +MemoryCacheItem* MemoryCache::getItem(uint8_t index) { + if (index < this->cacheElements) { + return &this->cache[index]; + } + return NULL; +} + +MemoryCache::MemoryCache(uint8_t cacheElements, Memory& memory) { + this->memory = &memory; + this->cache = (MemoryCacheItem*)calloc(cacheElements, sizeof(MemoryCacheItem)); + this->cacheElements = cacheElements; +} +uint8_t MemoryCache::read(uint16_t addr) { + bool found = false; + uint8_t data = 0; + //Find in cache + for(uint8_t i = 0; i < this->cacheElements; i++) { + if (this->cache[i].valid) { + if (this->cache[i].addr == addr) { + if (this->cache[i].ttl < UINT8_MAX - 1) { + this->cache[i].ttl = UINT8_MAX; + } + data = this->cache[i].data; + found = true; + } + } + } + if (found) { + return data; + } + //Not found, read from memory and add to cache + data = this->memory->read(addr); + + //Decrement TTLs + for(uint8_t i = 0; i < this->cacheElements; i++) { + if (this->cache[i].ttl > 0) { + this->cache[i].ttl--; + } + } + + uint8_t foundTTL = UINT8_MAX; + uint8_t cacheSlot = 0; + for(uint8_t i = 0; i < this->cacheElements; i++) { + if (!this->cache[i].valid) { + cacheSlot = i; + break; + } + if (this->cache[i].ttl < foundTTL) { + cacheSlot = i; + } + } + + this->cache[cacheSlot].addr = addr; + this->cache[cacheSlot].data = data; + this->cache[cacheSlot].ttl = UINT8_MAX; + this->cache[cacheSlot].valid = true; + + return data; +} +void MemoryCache::update(uint16_t addr, uint8_t data) { + for(uint8_t i = 0; i < this->cacheElements; i++) { + if (this->cache[i].valid && this->cache[i].addr == addr) { + this->cache[i].data = data; + break; + } + } +} + diff --git a/arduino/memory.h b/arduino/memory.h index 9e2aba9..1404494 100644 --- a/arduino/memory.h +++ b/arduino/memory.h @@ -54,4 +54,24 @@ class Memory { bool test(); }; +struct MemoryCacheItem_t { + uint16_t addr; + uint8_t data; + uint8_t ttl; + bool valid; +}; +typedef struct MemoryCacheItem_t MemoryCacheItem; + +class MemoryCache { + MemoryCacheItem *cache = NULL; + Memory *memory = NULL; + uint8_t cacheElements = 0; + public: + MemoryCache(uint8_t cacheElements, Memory& memory); + uint8_t getSize(); + MemoryCacheItem* getItem(uint8_t index); + uint8_t read(uint16_t addr); + void update(uint16_t addr, uint8_t data); +}; + #endif //UVM_MEMORY_H diff --git a/arduino/vm.c b/arduino/vm.c index f300ec6..73c45d2 100644 --- a/arduino/vm.c +++ b/arduino/vm.c @@ -98,7 +98,7 @@ void vm_step(VM *vm) { vm->halted = true; return; } - uint16_t raw = (vm->readAddr(PC) << 8) + vm->readAddr(PC + 1); + uint16_t raw = (vm->readAddr(PC, true) << 8) + vm->readAddr(PC + 1, true); vm->PC += 2; inst.op = (uint8_t) (raw >> 12); @@ -117,7 +117,7 @@ void vm_step(VM *vm) { temp16 = x; temp16 += inst.imm; if (temp16 < VM_MEM_SIZE) { - d = vm->readAddr(temp16); + d = vm->readAddr(temp16, false); } else { if (vm->error != NULL) { vm->error(VM_ERR_OUT_OF_BOUNDS); diff --git a/arduino/vm.h b/arduino/vm.h index 8988413..98d8590 100644 --- a/arduino/vm.h +++ b/arduino/vm.h @@ -62,7 +62,7 @@ struct VM_t { uint8_t PC; uint8_t carry; bool halted; - uint8_t (*readAddr)(uint16_t addr); + uint8_t (*readAddr)(uint16_t addr, bool instruction); void (*writeAddr)(uint16_t addr, uint8_t data); uint8_t (*syscall)(struct VM_t* vm, uint8_t callno, uint8_t imm); void (*error)(uint8_t err);