Implemented base system for REV.A PCB.
This commit is contained in:
@@ -124,7 +124,6 @@ void Console::printMemory(uint16_t from, uint16_t to) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Console::loop() {
|
void Console::loop() {
|
||||||
HardwareSerial * serial = this->serial;
|
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
switch(this->state) {
|
switch(this->state) {
|
||||||
@@ -148,9 +147,7 @@ void Console::loop() {
|
|||||||
this->stateActive();
|
this->stateActive();
|
||||||
break;
|
break;
|
||||||
case CONSOLE_RUN:
|
case CONSOLE_RUN:
|
||||||
if(this->vm->halted == false) {
|
if(this->vm->halted) {
|
||||||
vm_step(this->vm);
|
|
||||||
} else {
|
|
||||||
serial->print("VM Halted. PC=0x");
|
serial->print("VM Halted. PC=0x");
|
||||||
serial->print(this->vm->PC, HEX);
|
serial->print(this->vm->PC, HEX);
|
||||||
serial->println(". Registers:");
|
serial->println(". Registers:");
|
||||||
@@ -223,7 +220,9 @@ void Console::stateActive() {
|
|||||||
serial->println("Console deactivated.");
|
serial->println("Console deactivated.");
|
||||||
this->state = CONSOLE_NONE;
|
this->state = CONSOLE_NONE;
|
||||||
} else if (this->inputBuffer->equals("r")) {
|
} else if (this->inputBuffer->equals("r")) {
|
||||||
|
serial->println("VM Running...");
|
||||||
this->vm->halted = false;
|
this->vm->halted = false;
|
||||||
|
this->vm->run = true;
|
||||||
this->state = CONSOLE_RUN;
|
this->state = CONSOLE_RUN;
|
||||||
} else if (this->inputBuffer->equals("s")) {
|
} else if (this->inputBuffer->equals("s")) {
|
||||||
this->vm->halted = false;
|
this->vm->halted = false;
|
||||||
@@ -365,6 +364,7 @@ void Console::stateExamine() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
serial->println(this->inputBuffer->c_str());
|
||||||
serial->println("Unknown command.");
|
serial->println("Unknown command.");
|
||||||
}
|
}
|
||||||
if (this->state == CONSOLE_EXAMINE) {
|
if (this->state == CONSOLE_EXAMINE) {
|
||||||
|
|||||||
176
arduino/Interface.cpp
Normal file
176
arduino/Interface.cpp
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
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 <Arduino.h>
|
||||||
|
#include "Interface.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
Interface::Interface(VM *vm, Memory *mem, ShiftInput *input, ShiftOutput *disp, int regSwitchPin) {
|
||||||
|
this->vm = vm;
|
||||||
|
this->mem = mem;
|
||||||
|
this->input = input;
|
||||||
|
this->disp = disp;
|
||||||
|
|
||||||
|
//Inputs
|
||||||
|
this->regSwitchPin = regSwitchPin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interface::init() {
|
||||||
|
pinMode(regSwitchPin, INPUT);
|
||||||
|
data = mem->read(addr);
|
||||||
|
|
||||||
|
//Lamp test
|
||||||
|
for(uint8_t i = 0; i < 16; i++) {
|
||||||
|
disp->output(i==0 ? 0xFF : 0x0);
|
||||||
|
disp->clockOutput();
|
||||||
|
delay(50);
|
||||||
|
}
|
||||||
|
for(uint8_t i = 0; i < 16; i++) {
|
||||||
|
disp->output(0xFF);
|
||||||
|
}
|
||||||
|
disp->clockOutput();
|
||||||
|
delay(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interface::loop() {
|
||||||
|
|
||||||
|
//Process inputs
|
||||||
|
|
||||||
|
uint8_t swLast = switchState;
|
||||||
|
if (input->updateInput()) {
|
||||||
|
uint8_t addrInputH = ~reverse8(input->getInput(0));
|
||||||
|
uint8_t addrInputL = ~reverse8(input->getInput(1));
|
||||||
|
uint8_t swInput = input->getInput(2);
|
||||||
|
uint16_t addrInput = (addrInputH << 8) + addrInputL;
|
||||||
|
//Check for buttons on rising edge
|
||||||
|
if ((swLast & SW_RUN) == 0 && (swInput & SW_RUN) == SW_RUN) {
|
||||||
|
if (vm->run) {
|
||||||
|
vm->run = false;
|
||||||
|
} else {
|
||||||
|
vm->run = true;
|
||||||
|
vm->halted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((swLast & SW_STEP) == 0 && (swInput & SW_STEP) == SW_STEP) {
|
||||||
|
if (vm->run == false) {
|
||||||
|
vm->halted = false;
|
||||||
|
vm_step(vm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((swLast & SW_RESET) == 0 && (swInput & SW_RESET) == SW_RESET) {
|
||||||
|
if (vm->run == false) {
|
||||||
|
vm_reset(vm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((swLast & SW_CLEAR) == 0 && (swInput & SW_CLEAR) == SW_CLEAR) {
|
||||||
|
if (vm->run == false) {
|
||||||
|
if (clearTimer == 0) {
|
||||||
|
clearTimer = millis() + 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((swLast & SW_CLEAR) == SW_CLEAR && (swInput & SW_CLEAR) == 0) {
|
||||||
|
clearTimer = 0;
|
||||||
|
}
|
||||||
|
else if ((swLast & SW_DEPOSIT) == 0 && (swInput & SW_DEPOSIT) == SW_DEPOSIT) {
|
||||||
|
data = addrInputH;
|
||||||
|
vm->writeAddr(addr, data);
|
||||||
|
}
|
||||||
|
else if ((swLast & SW_DEPOSIT_NEXT) == 0 && (swInput & SW_DEPOSIT_NEXT) == SW_DEPOSIT_NEXT) {
|
||||||
|
data = addrInputH;
|
||||||
|
vm->writeAddr(addr, data);
|
||||||
|
addr++;
|
||||||
|
}
|
||||||
|
else if ((swLast & SW_EXAMINE) == 0 && (swInput & SW_EXAMINE) == SW_EXAMINE) {
|
||||||
|
addr = addrInput;
|
||||||
|
data = mem->read(addr);
|
||||||
|
}
|
||||||
|
else if ((swLast & SW_EXAMINE_NEXT) == 0 && (swInput & SW_EXAMINE_NEXT) == SW_EXAMINE_NEXT) {
|
||||||
|
addr++;
|
||||||
|
data = mem->read(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
switchState = swInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vm->run) {
|
||||||
|
clearTimer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clearTimer > 0) {
|
||||||
|
if (clearTimer < millis()) {
|
||||||
|
vm_reset(vm);
|
||||||
|
disp->output16(0xFFFF);
|
||||||
|
for(uint8_t i = 0; i < 14; i++) {
|
||||||
|
disp->output((uint8_t)0);
|
||||||
|
}
|
||||||
|
disp->clockOutput();
|
||||||
|
mem->writeRange(0, 0, VM_MEM_SIZE);
|
||||||
|
addr = 0;
|
||||||
|
data = 0;
|
||||||
|
delay(500);
|
||||||
|
clearTimer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Update Display
|
||||||
|
|
||||||
|
//Address
|
||||||
|
disp->output((uint8_t)(addr & 0xFF));
|
||||||
|
disp->output((uint8_t)(addr >> 8));
|
||||||
|
|
||||||
|
//Run/Halt
|
||||||
|
uint8_t status = 0;
|
||||||
|
if (vm->run) {
|
||||||
|
status |= 0x80;
|
||||||
|
}
|
||||||
|
if (vm->halted) {
|
||||||
|
status |= 0x40;
|
||||||
|
}
|
||||||
|
disp->output(status);
|
||||||
|
|
||||||
|
//Data
|
||||||
|
disp->output(data);
|
||||||
|
|
||||||
|
//Program counter and Instruction
|
||||||
|
uint16_t pc = vm->PC;
|
||||||
|
uint16_t instr = (mem->read(pc) << 8) + mem->read(pc + 1);
|
||||||
|
// disp->output((uint8_t)0xF);
|
||||||
|
// disp->output((uint8_t)0xF);
|
||||||
|
// disp->output((uint8_t)0xF);
|
||||||
|
// disp->output((uint8_t)0xF);
|
||||||
|
disp->output16(instr);
|
||||||
|
disp->output16(pc);
|
||||||
|
|
||||||
|
//Registers
|
||||||
|
// for(uint8_t i = 0; i < 8; i++) {
|
||||||
|
// disp->output((uint8_t)0);
|
||||||
|
// }
|
||||||
|
short int reg;
|
||||||
|
if (digitalRead(regSwitchPin) == HIGH) {
|
||||||
|
//Output 8-F
|
||||||
|
for(reg=0xF; reg >= 0x8; reg--) {
|
||||||
|
disp->output(vm->R[reg]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//Output 0-F
|
||||||
|
for(reg=0x7; reg >= 0; reg--) {
|
||||||
|
disp->output(vm->R[reg]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
disp->clockOutput();
|
||||||
|
}
|
||||||
|
|
||||||
51
arduino/Interface.h
Normal file
51
arduino/Interface.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
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_INTERFACE_H
|
||||||
|
#define UVM_INTERFACE_H
|
||||||
|
|
||||||
|
#define SW_RUN 0x40
|
||||||
|
#define SW_STEP 0x80
|
||||||
|
#define SW_RESET 0x10
|
||||||
|
#define SW_CLEAR 0x20
|
||||||
|
#define SW_DEPOSIT 0x02
|
||||||
|
#define SW_DEPOSIT_NEXT 0x01
|
||||||
|
#define SW_EXAMINE 0x08
|
||||||
|
#define SW_EXAMINE_NEXT 0x04
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "VM.h"
|
||||||
|
#include "ShiftInput.h"
|
||||||
|
#include "ShiftOutput.h"
|
||||||
|
#include "Memory.h"
|
||||||
|
|
||||||
|
class Interface {
|
||||||
|
VM *vm;
|
||||||
|
Memory *mem;
|
||||||
|
ShiftInput *input;
|
||||||
|
ShiftOutput *disp;
|
||||||
|
int regSwitchPin = 0;
|
||||||
|
uint8_t switchState = 0;
|
||||||
|
uint16_t addr = 0;
|
||||||
|
uint8_t data = 0;
|
||||||
|
unsigned long int clearTimer = 0;
|
||||||
|
public:
|
||||||
|
Interface(VM *vm, Memory *mem, ShiftInput *input, ShiftOutput *disp, int regSwitchPin);
|
||||||
|
void init();
|
||||||
|
void loop();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -25,6 +25,7 @@ Memory::Memory(uint8_t csPin) {
|
|||||||
this->memSize = 0xFFFF;
|
this->memSize = 0xFFFF;
|
||||||
//Store spi setting
|
//Store spi setting
|
||||||
this->setting = SPISettings(20000000, MSBFIRST, SPI_MODE0);
|
this->setting = SPISettings(20000000, MSBFIRST, SPI_MODE0);
|
||||||
|
SPI.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Memory::start() {
|
void Memory::start() {
|
||||||
@@ -38,18 +39,23 @@ void Memory::end() {
|
|||||||
|
|
||||||
bool Memory::init() {
|
bool Memory::init() {
|
||||||
//Set mode to sequential access (should be default mode)
|
//Set mode to sequential access (should be default mode)
|
||||||
this->start();
|
this->setMode(MODE_SEQ);
|
||||||
SPI.transfer(INSTR_WRMR);
|
|
||||||
SPI.transfer(MODE_SEQ);
|
|
||||||
this->end();
|
|
||||||
|
|
||||||
//Verify that it was set
|
//Verify that it was set
|
||||||
|
return this->readMode() == MODE_SEQ;
|
||||||
|
}
|
||||||
|
void Memory::setMode(MemoryMode mode) {
|
||||||
|
this->start();
|
||||||
|
SPI.transfer(INSTR_WRMR);
|
||||||
|
SPI.transfer(mode);
|
||||||
|
this->end();
|
||||||
|
}
|
||||||
|
MemoryMode Memory::readMode() {
|
||||||
this->start();
|
this->start();
|
||||||
SPI.transfer(INSTR_RDMR);
|
SPI.transfer(INSTR_RDMR);
|
||||||
uint8_t mode = SPI.transfer(0);
|
MemoryMode mode = (MemoryMode)SPI.transfer(0);
|
||||||
this->end();
|
this->end();
|
||||||
|
return mode;
|
||||||
return mode == MODE_SEQ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t Memory::getSize() {
|
uint16_t Memory::getSize() {
|
||||||
@@ -126,6 +132,12 @@ bool Memory::test() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
MemoryCache::MemoryCache(uint8_t cacheElements, Memory& memory) {
|
||||||
|
this->memory = &memory;
|
||||||
|
this->cache = (MemoryCacheItem*)calloc(cacheElements, sizeof(MemoryCacheItem));
|
||||||
|
this->cacheElements = cacheElements;
|
||||||
|
}
|
||||||
uint8_t MemoryCache::getSize() {
|
uint8_t MemoryCache::getSize() {
|
||||||
return this->cacheElements;
|
return this->cacheElements;
|
||||||
}
|
}
|
||||||
@@ -135,12 +147,6 @@ MemoryCacheItem* MemoryCache::getItem(uint8_t index) {
|
|||||||
}
|
}
|
||||||
return NULL;
|
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) {
|
uint8_t MemoryCache::read(uint16_t addr) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
uint8_t data = 0;
|
uint8_t data = 0;
|
||||||
@@ -197,3 +203,9 @@ void MemoryCache::update(uint16_t addr, uint8_t data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MemoryCache::clear() {
|
||||||
|
for(uint8_t i = 0; i < this->cacheElements; i++) {
|
||||||
|
this->cache[i].valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ class Memory {
|
|||||||
Memory(uint8_t csPin);
|
Memory(uint8_t csPin);
|
||||||
uint16_t getSize();
|
uint16_t getSize();
|
||||||
void setSize(uint16_t memSize);
|
void setSize(uint16_t memSize);
|
||||||
|
void setMode(MemoryMode mode);
|
||||||
|
MemoryMode readMode();
|
||||||
bool init();
|
bool init();
|
||||||
uint8_t read(uint16_t addr);
|
uint8_t read(uint16_t addr);
|
||||||
void write(uint16_t addr, uint8_t data);
|
void write(uint16_t addr, uint8_t data);
|
||||||
@@ -72,6 +74,7 @@ class MemoryCache {
|
|||||||
MemoryCacheItem* getItem(uint8_t index);
|
MemoryCacheItem* getItem(uint8_t index);
|
||||||
uint8_t read(uint16_t addr);
|
uint8_t read(uint16_t addr);
|
||||||
void update(uint16_t addr, uint8_t data);
|
void update(uint16_t addr, uint8_t data);
|
||||||
|
void clear();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //UVM_MEMORY_H
|
#endif //UVM_MEMORY_H
|
||||||
|
|||||||
@@ -35,8 +35,11 @@ ShiftInput::ShiftInput(uint8_t chipCount, uint8_t loadPin, uint8_t clockPin, uin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* ShiftInput::getInput() {
|
uint8_t ShiftInput::getInput(uint8_t chip) {
|
||||||
return this->input;
|
if (chip <= this->chipCount) {
|
||||||
|
return this->input[chip];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ShiftInput::getChipCount() {
|
uint8_t ShiftInput::getChipCount() {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class ShiftInput {
|
|||||||
public:
|
public:
|
||||||
ShiftInput(uint8_t chipCount, uint8_t loadPin, uint8_t clockPin, uint8_t clockInhPin, uint8_t dataPin);
|
ShiftInput(uint8_t chipCount, uint8_t loadPin, uint8_t clockPin, uint8_t clockInhPin, uint8_t dataPin);
|
||||||
uint8_t getChipCount();
|
uint8_t getChipCount();
|
||||||
uint8_t *getInput();
|
uint8_t getInput(uint8_t chip);
|
||||||
bool updateInput();
|
bool updateInput();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
59
arduino/ShiftOutput.cpp
Normal file
59
arduino/ShiftOutput.cpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
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 <Arduino.h>
|
||||||
|
#include "ShiftOutput.h"
|
||||||
|
|
||||||
|
ShiftOutput::ShiftOutput(uint8_t enablePin, uint8_t clkPin, uint8_t rClkPin, uint8_t dataPin) {
|
||||||
|
this->enablePin = enablePin;
|
||||||
|
this->clkPin = clkPin;
|
||||||
|
this->rClkPin = rClkPin;
|
||||||
|
this->dataPin = dataPin;
|
||||||
|
|
||||||
|
pinMode(enablePin, OUTPUT);
|
||||||
|
digitalWrite(enablePin, HIGH);
|
||||||
|
pinMode(clkPin, OUTPUT);
|
||||||
|
digitalWrite(clkPin, LOW);
|
||||||
|
pinMode(rClkPin, OUTPUT);
|
||||||
|
digitalWrite(rClkPin, LOW);
|
||||||
|
pinMode(dataPin, OUTPUT);
|
||||||
|
digitalWrite(dataPin, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShiftOutput::enable() {
|
||||||
|
digitalWrite(this->enablePin, LOW);
|
||||||
|
}
|
||||||
|
void ShiftOutput::disable() {
|
||||||
|
digitalWrite(this->enablePin, HIGH);
|
||||||
|
}
|
||||||
|
void ShiftOutput::output(uint8_t data, bool clockOutput) {
|
||||||
|
shiftOut(this->dataPin, this->clkPin, LSBFIRST, data);
|
||||||
|
if (clockOutput) {
|
||||||
|
this->clockOutput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ShiftOutput::output16(uint16_t data, bool clockOutput) {
|
||||||
|
shiftOut(this->dataPin, this->clkPin, LSBFIRST, data & 0xFF);
|
||||||
|
shiftOut(this->dataPin, this->clkPin, LSBFIRST, (data >> 8));
|
||||||
|
if (clockOutput) {
|
||||||
|
this->clockOutput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void ShiftOutput::clockOutput() {
|
||||||
|
digitalWrite(this->rClkPin, HIGH);
|
||||||
|
digitalWrite(this->rClkPin, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
42
arduino/ShiftOutput.h
Normal file
42
arduino/ShiftOutput.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
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_SHIFTOUTPUT_H
|
||||||
|
#define UVM_SHIFTOUTPUT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class ShiftOutput {
|
||||||
|
uint8_t enablePin;
|
||||||
|
uint8_t clkPin;
|
||||||
|
uint8_t rClkPin;
|
||||||
|
uint8_t dataPin;
|
||||||
|
public:
|
||||||
|
ShiftOutput(uint8_t enablePin, uint8_t clkPin, uint8_t rClkPin, uint8_t dataPin);
|
||||||
|
void enable();
|
||||||
|
void disable();
|
||||||
|
inline void output(uint8_t data) {
|
||||||
|
output(data, false);
|
||||||
|
}
|
||||||
|
inline void output16(uint16_t data) {
|
||||||
|
output16(data, false);
|
||||||
|
}
|
||||||
|
void output(uint8_t data, bool rclk);
|
||||||
|
void output16(uint16_t data, bool rclk);
|
||||||
|
void clockOutput();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //UVM_SHIFTOUTPUT_H
|
||||||
16
arduino/VM.c
16
arduino/VM.c
@@ -31,6 +31,7 @@ void vm_reset(VM *vm) {
|
|||||||
memset(vm->R, 0, sizeof(uint8_t) * VM_REG_SIZE);
|
memset(vm->R, 0, sizeof(uint8_t) * VM_REG_SIZE);
|
||||||
vm->PC = 0;
|
vm->PC = 0;
|
||||||
vm->carry = 0;
|
vm->carry = 0;
|
||||||
|
vm->run = false;
|
||||||
vm->halted = false;
|
vm->halted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +117,7 @@ void vm_step(VM *vm) {
|
|||||||
vm->error(VM_ERR_MISALIGN);
|
vm->error(VM_ERR_MISALIGN);
|
||||||
}
|
}
|
||||||
vm->halted = true;
|
vm->halted = true;
|
||||||
|
vm->run = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint16_t raw = (vm->readAddr(PC, true) << 8) + vm->readAddr(PC + 1, true);
|
uint16_t raw = (vm->readAddr(PC, true) << 8) + vm->readAddr(PC + 1, true);
|
||||||
@@ -123,6 +125,7 @@ void vm_step(VM *vm) {
|
|||||||
inst.op = (uint8_t) (raw >> 12);
|
inst.op = (uint8_t) (raw >> 12);
|
||||||
|
|
||||||
if (vm->halted) {
|
if (vm->halted) {
|
||||||
|
vm->run = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,22 +222,25 @@ void vm_step(VM *vm) {
|
|||||||
break;
|
break;
|
||||||
case OP_JMP:
|
case OP_JMP:
|
||||||
vm_decode_Q(&inst, raw);
|
vm_decode_Q(&inst, raw);
|
||||||
vm->PC = vm_get_rx(vm, inst.rd);
|
rd = vm_get_rx(vm, inst.rd);
|
||||||
|
vm->PC = rd;
|
||||||
break;
|
break;
|
||||||
case OP_JEQ:
|
case OP_JEQ:
|
||||||
vm_decode_S(&inst, raw);
|
vm_decode_S(&inst, raw);
|
||||||
rx = vm_get_r(vm, inst.rx);
|
rx = vm_get_r(vm, inst.rx);
|
||||||
ry = vm_get_r(vm, inst.ry);
|
ry = vm_get_r(vm, inst.ry);
|
||||||
|
rd = vm_get_rx(vm, inst.rd);
|
||||||
if (rx == ry) {
|
if (rx == ry) {
|
||||||
vm->PC = vm_get_rx(vm, inst.rd);
|
vm->PC = rd;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OP_JLT:
|
case OP_JLT:
|
||||||
vm_decode_S(&inst, raw);
|
vm_decode_S(&inst, raw);
|
||||||
rx = vm_get_r(vm, inst.rx);
|
rx = vm_get_r(vm, inst.rx);
|
||||||
ry = vm_get_r(vm, inst.ry);
|
ry = vm_get_r(vm, inst.ry);
|
||||||
|
rd = vm_get_rx(vm, inst.rd);
|
||||||
if (rx < ry) {
|
if (rx < ry) {
|
||||||
vm->PC = vm_get_rx(vm, inst.rd);
|
vm->PC = rd;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OP_HLT:
|
case OP_HLT:
|
||||||
@@ -248,4 +254,8 @@ void vm_step(VM *vm) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
vm_put_r(vm, inst.rd, rd);
|
vm_put_r(vm, inst.rd, rd);
|
||||||
|
|
||||||
|
if (vm->halted) {
|
||||||
|
vm->run = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ struct VM_t {
|
|||||||
uint8_t R[VM_REG_SIZE];
|
uint8_t R[VM_REG_SIZE];
|
||||||
uint16_t PC;
|
uint16_t PC;
|
||||||
uint8_t carry;
|
uint8_t carry;
|
||||||
|
bool run;
|
||||||
bool halted;
|
bool halted;
|
||||||
uint8_t (*readAddr)(uint16_t addr, bool instruction);
|
uint8_t (*readAddr)(uint16_t addr, bool instruction);
|
||||||
void (*writeAddr)(uint16_t addr, uint8_t data);
|
void (*writeAddr)(uint16_t addr, uint8_t data);
|
||||||
|
|||||||
@@ -16,22 +16,31 @@ limitations under the License.
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Example Programs
|
* Example Programs
|
||||||
* Hello World: 0x311833021210c0323401411412103416e4203406d400000048656c6c6f20576f726c640a
|
* Hello World: 311833021210c0323401411412103416e4203406d400000048656c6c6f20576f726c640a
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
//Options
|
||||||
|
//#define TEST_DESTRUCTIVE
|
||||||
|
|
||||||
#include "VM.h"
|
#include "VM.h"
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "ShiftInput.h"
|
#include "ShiftInput.h"
|
||||||
|
#include "ShiftOutput.h"
|
||||||
|
#include "Interface.h"
|
||||||
|
#include "pins.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
//Expecting a Microchip 23LCV512 connected over MOSI/MISO/MCLK
|
||||||
|
Memory mem(PIN_MEMORY_SEL);
|
||||||
|
MemoryCache ICache(64, mem);
|
||||||
|
MemoryCache DCache(32, mem);
|
||||||
|
|
||||||
VM vm;
|
VM vm;
|
||||||
Console console(&vm);
|
Console console(&vm);
|
||||||
ShiftInput buttons(1, 14, 15, 0, 16);
|
ShiftInput inputs(3, PIN_INP_LOAD, PIN_INP_CLK, 0, PIN_INP_SER);
|
||||||
|
ShiftOutput disp(PIN_DISP_EN, PIN_DISP_CLK, PIN_DISP_RCLK, PIN_DISP_OUT);
|
||||||
//Expecting a Microchip 23LCV512 connected over MOSI/MISO/MCLK
|
Interface io(&vm, &mem, &inputs, &disp, PIN_SW_REG);
|
||||||
Memory mem(10);
|
|
||||||
MemoryCache ICache(64, mem);
|
|
||||||
MemoryCache DCache(32, mem);
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
//Setup VM
|
//Setup VM
|
||||||
@@ -41,15 +50,48 @@ void setup() {
|
|||||||
vm.readAddr = vm_read_addr;
|
vm.readAddr = vm_read_addr;
|
||||||
vm.writeAddr = vm_write_addr;
|
vm.writeAddr = vm_write_addr;
|
||||||
|
|
||||||
|
//Display
|
||||||
|
for(uint8_t i = 0; i < 16; i++) {
|
||||||
|
disp.output((uint8_t)0, true);
|
||||||
|
}
|
||||||
|
disp.clockOutput();
|
||||||
|
disp.enable();
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
io.init();
|
||||||
|
|
||||||
|
//Disable input inhibit lines (Layout issue on Rev.A board)
|
||||||
|
pinMode(PIN_INP_ADDR_INH, OUTPUT);
|
||||||
|
pinMode(PIN_INP_SW_INH, OUTPUT);
|
||||||
|
digitalWrite(PIN_INP_ADDR_INH, LOW);
|
||||||
|
digitalWrite(PIN_INP_SW_INH, LOW);
|
||||||
|
|
||||||
//Start serial
|
//Start serial
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
console.setSerial(&Serial);
|
console.setSerial(&Serial);
|
||||||
|
|
||||||
|
//Speed control
|
||||||
|
pinMode(PIN_SPEED, INPUT);
|
||||||
|
|
||||||
//Init memory
|
//Init memory
|
||||||
SPI.begin();
|
|
||||||
mem.setSize(VM_MEM_SIZE);
|
mem.setSize(VM_MEM_SIZE);
|
||||||
if (!mem.init()) {
|
if (!mem.init()) {
|
||||||
Serial.println("Memory failed to init!");
|
Serial.println("Memory failed to init!");
|
||||||
|
Serial.print("Tried to set MODE_SEQ. Current mode is ");
|
||||||
|
switch(mem.readMode()) {
|
||||||
|
case MODE_BYTE:
|
||||||
|
Serial.println("MODE_BYTE");
|
||||||
|
break;
|
||||||
|
case MODE_PAGE:
|
||||||
|
Serial.println("MODE_PAGE");
|
||||||
|
break;
|
||||||
|
case MODE_SEQ:
|
||||||
|
Serial.println("MODE_SEQ");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Serial.println(mem.readMode());
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef TEST_DESTRUCTIVE
|
#ifdef TEST_DESTRUCTIVE
|
||||||
Serial.print("Testing ");
|
Serial.print("Testing ");
|
||||||
@@ -68,19 +110,25 @@ void setup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
unsigned long int nextRun = 0;
|
||||||
console.loop();
|
|
||||||
|
|
||||||
if (buttons.updateInput()) {
|
void loop() {
|
||||||
uint8_t *input = buttons.getInput();
|
if (vm.run) {
|
||||||
for(uint8_t i = 0; i < buttons.getChipCount(); i++) {
|
if (nextRun == 0 || nextRun < millis()) {
|
||||||
Serial.print("Button Group ");
|
vm_step(&vm);
|
||||||
Serial.print(i);
|
int delayTime = analogRead(PIN_SPEED);
|
||||||
Serial.print(" = ");
|
if (delayTime < 10) {
|
||||||
Serial.print(input[i], BIN);
|
nextRun = 0;
|
||||||
Serial.println();
|
} else {
|
||||||
|
nextRun = millis() + delayTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
nextRun = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.loop();
|
||||||
|
io.loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_print_error(uint8_t err) {
|
void vm_print_error(uint8_t err) {
|
||||||
@@ -140,22 +188,3 @@ void vm_write_addr(uint16_t addr, uint8_t data) {
|
|||||||
DCache.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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
41
arduino/pins.h
Normal file
41
arduino/pins.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
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_PINS_H
|
||||||
|
#define UVM_PINS_H
|
||||||
|
|
||||||
|
//Display / Shift register output
|
||||||
|
#define PIN_DISP_EN 8
|
||||||
|
#define PIN_DISP_CLK 16
|
||||||
|
#define PIN_DISP_RCLK 17
|
||||||
|
#define PIN_DISP_OUT 15
|
||||||
|
|
||||||
|
//Inputs
|
||||||
|
#define PIN_SPEED 14
|
||||||
|
#define PIN_SW_REG 7
|
||||||
|
#define PIN_INP_SER 2
|
||||||
|
#define PIN_INP_CLK 3
|
||||||
|
#define PIN_INP_ADDR_INH 4
|
||||||
|
#define PIN_INP_SW_INH 5
|
||||||
|
#define PIN_INP_LOAD 6
|
||||||
|
|
||||||
|
//I/O
|
||||||
|
#define PIN_IO_INT 9
|
||||||
|
|
||||||
|
//Memory
|
||||||
|
#define PIN_MEMORY_SEL 10
|
||||||
|
|
||||||
|
#endif
|
||||||
24
arduino/util.c
Normal file
24
arduino/util.c
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
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 "util.h"
|
||||||
|
|
||||||
|
uint8_t reverse8(register uint8_t b) {
|
||||||
|
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
||||||
|
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
||||||
|
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
32
arduino/util.h
Normal file
32
arduino/util.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
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_UTIL_H
|
||||||
|
#define UVM_UTIL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t reverse8(uint8_t b);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user