Implemented vm memory using external 23LCV512 chip.

Todo: implement extended registers
This commit is contained in:
2018-10-24 21:59:51 +01:00
parent 600be14336
commit 52a70e7931
6 changed files with 237 additions and 13 deletions

View File

@@ -21,16 +21,48 @@ limitations under the License.
#include "vm.h"
#include "console.h"
#include "memory.h"
VM vm;
Console console(&vm);
//Expecting a Microchip 23LCV512 connected over MOSI/MISO/MCLK
Memory mem(20000000, MSBFIRST, SPI_MODE0, 4);
void setup() {
//Setup VM
vm_reset(&vm);
vm.error = vm_print_error;
vm.syscall = vm_syscall;
Serial.begin(1200);
vm.readAddr = vm_read_addr;
vm.writeAddr = vm_write_addr;
//Start serial
Serial.begin(9600);
console.setSerial(&Serial);
//Init memory
SPI.begin();
mem.setSize(VM_MEM_SIZE);
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);
Serial.print(" bytes memory... ");
unsigned long startTime = millis();
if (mem.test()) {
Serial.println("OK");
} else {
Serial.println("ERROR!");
}
Serial.print("Tested in ");
Serial.print(millis() - startTime, DEC);
Serial.println("ms");
#endif
}
}
void loop() {
@@ -45,7 +77,8 @@ void vm_print_error(uint8_t err) {
Serial.println("Halted. PC misaligned.");
break;
case VM_ERR_UNKNOWN_OP:
Serial.println("Halted. Unknown instruction. (this should never happen)");
//Will only happen if an instruction is not handled in the vm
Serial.println("Halted. Unknown instruction.");
break;
case VM_ERR_OUT_OF_BOUNDS:
Serial.println("Halted. Operation out of bounds.");
@@ -80,3 +113,10 @@ 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);
}

View File

@@ -83,7 +83,7 @@ void Console::printMemory(uint16_t from, uint16_t to) {
serial->print(i, HEX);
serial->print(" ");
}
uint8_t m = this->vm->M[i];
uint8_t m = this->vm->readAddr(i);
if (m < 0x10) {
serial->print("0");
}
@@ -95,8 +95,8 @@ void Console::printMemory(uint16_t from, uint16_t to) {
void Console::loop() {
HardwareSerial * serial = this->serial;
int i;
uint32_t i;
switch(this->state) {
case CONSOLE_NONE:
serial->println("Press Enter to activate console.");
@@ -155,7 +155,7 @@ void Console::loop() {
case CONSOLE_CLEAR:
vm_reset(this->vm);
for(i = 0; i < VM_MEM_SIZE; i++) {
this->vm->M[i] = 0;
this->vm->writeAddr(i, 0);
}
serial->println("VM Reset & Memory Cleared");
this->state = CONSOLE_ACTIVATE;
@@ -315,7 +315,7 @@ void Console::stateExamine() {
for(int i = 0; i < x.length(); i += 2) {
value = this->hexToDec(x.substring(i, i+2));
if (value >= 0 && value <= 255) {
this->vm->M[location++] = value;
this->vm->writeAddr(location++, value);
} else {
serial->println(i);
serial->println(x.substring(i, i+2));

127
arduino/memory.cpp Normal file
View File

@@ -0,0 +1,127 @@
/*
Copyright 2018 Sam Stevens
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "memory.h"
Memory::Memory(uint32_t clock, uint8_t bitOrder, uint8_t dataMode, uint8_t csPin) {
//Set cs pin high
this->csPin = csPin;
pinMode(csPin, OUTPUT);
digitalWrite(csPin, HIGH);
//Default to 64k ram
this->memSize = 0xFFFF;
//Store spi setting
this->setting = SPISettings(clock, bitOrder, dataMode);
}
void Memory::start() {
digitalWrite(this->csPin, LOW);
SPI.beginTransaction(this->setting);
}
void Memory::end() {
SPI.endTransaction();
digitalWrite(this->csPin, HIGH);
}
bool Memory::init() {
//Set mode to sequential access (should be default mode)
this->start();
SPI.transfer(INSTR_WRMR);
SPI.transfer(MODE_SEQ);
this->end();
//Verify that it was set
this->start();
SPI.transfer(INSTR_RDMR);
uint8_t mode = SPI.transfer(0);
this->end();
return mode == MODE_SEQ;
}
uint16_t Memory::getSize() {
return this->memSize;
}
void Memory::setSize(uint16_t memSize) {
this->memSize = memSize;
}
uint8_t Memory::read(uint16_t addr) {
this->start();
SPI.transfer(INSTR_READ);
SPI.transfer16(addr);
uint8_t data = SPI.transfer(0);
this->end();
return data;
}
void Memory::write(uint16_t addr, uint8_t data) {
this->start();
SPI.transfer(INSTR_WRITE);
SPI.transfer16(addr);
SPI.transfer(data);
this->end();
}
void Memory::writeRange(uint8_t data, uint16_t from, uint16_t to) {
if (from > to) {
return;
}
this->start();
SPI.transfer(INSTR_WRITE);
SPI.transfer16(from);
for(uint32_t i = from; i < to; i++) {
SPI.transfer(data);
}
this->end();
}
bool Memory::verifyRange(uint8_t data, uint16_t from, uint16_t to) {
if (from > to) {
return false;
}
this->start();
SPI.transfer(INSTR_READ);
SPI.transfer16(from);
bool ok = true;
for(uint32_t i = from; i < to; i++) {
if (SPI.transfer(0) != data) {
ok = false;
break;
}
}
this->end();
return ok;
}
bool Memory::test() {
//write 0x55 (01010101)
this->writeRange(0x55, 0, this->memSize);
//verify
if (!this->verifyRange(0x55, 0, this->memSize)) {
return false;
}
//write zeros
this->writeRange(0, 0, this->memSize);
//verify zeros
if (!this->verifyRange(0, 0, this->memSize)) {
return false;
}
return true;
}

57
arduino/memory.h Normal file
View File

@@ -0,0 +1,57 @@
/*
Copyright 2018 Sam Stevens
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef UVM_MEMORY_H
#define UVM_MEMORY_H
#include <SPI.h>
enum MemoryMode_t {
MODE_BYTE = 0x00,
MODE_PAGE = 0x80,
MODE_SEQ = 0x40
};
typedef enum MemoryMode_t MemoryMode;
enum MemoryInstruction_t {
INSTR_READ = 0x03,
INSTR_WRITE = 0x02,
INSTR_EDIO = 0x3B,
INSTR_RESIO = 0xFF,
INSTR_RDMR = 0x05,
INSTR_WRMR = 0x01
};
typedef enum MemoryInstruction_t MemoryInstruction;
class Memory {
SPISettings setting;
uint8_t csPin;
uint16_t memSize;
void start();
void end();
public:
Memory(uint32_t clock, uint8_t bitOrder, uint8_t dataMode, uint8_t csPin);
uint16_t getSize();
void setSize(uint16_t memSize);
bool init();
uint8_t read(uint16_t addr);
void write(uint16_t addr, uint8_t data);
void writeRange(uint8_t data, uint16_t from, uint16_t to) ;
bool verifyRange(uint8_t data, uint16_t from, uint16_t to);
bool test();
};
#endif //UVM_MEMORY_H

View File

@@ -36,7 +36,6 @@ void vm_reset(VM *vm) {
void vm_clear(VM *vm) {
vm_reset(vm);
memset(&vm->M, 0, VM_MEM_SIZE);
}
inline uint8_t vm_get_r(VM *vm, uint8_t r) {
@@ -99,7 +98,7 @@ void vm_step(VM *vm) {
vm->halted = true;
return;
}
uint16_t raw = (vm->M[PC] << 8) + vm->M[PC + 1];
uint16_t raw = (vm->readAddr(PC) << 8) + vm->readAddr(PC + 1);
vm->PC += 2;
inst.op = (uint8_t) (raw >> 12);
@@ -118,7 +117,7 @@ void vm_step(VM *vm) {
temp16 = x;
temp16 += inst.imm;
if (temp16 < VM_MEM_SIZE) {
d = vm->M[temp16];
d = vm->readAddr(temp16);
} else {
if (vm->error != NULL) {
vm->error(VM_ERR_OUT_OF_BOUNDS);
@@ -132,7 +131,7 @@ void vm_step(VM *vm) {
temp16 = vm_get_r(vm, inst.rd);
temp16 += inst.imm;
if (temp16 < VM_MEM_SIZE) {
vm->M[temp16] = x;
vm->writeAddr(temp16, x);
} else {
if (vm->error != NULL) {
vm->error(VM_ERR_OUT_OF_BOUNDS);

View File

@@ -20,7 +20,7 @@ limitations under the License.
#include <stdint.h>
#include <stdbool.h>
#define VM_MEM_SIZE 256
#define VM_MEM_SIZE 0xFFFF
#define VM_REG_SIZE 16
#define OP_HLT 0x0
@@ -60,9 +60,10 @@ typedef struct VM_Instruction_t VM_Instruction;
struct VM_t {
uint8_t R[VM_REG_SIZE];
uint8_t PC;
uint8_t M[VM_MEM_SIZE];
uint8_t carry;
bool halted;
uint8_t (*readAddr)(uint16_t addr);
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);
};