Rearranaged opcode order
- Rearranaged opcodes to match Iridium's - Grabbed the get_test_vm() function from the Iridium 1 source to keep up with the tutorial - Specifications page with details regarding Iridium and Corten's instruction set list
This commit is contained in:
parent
ee08374252
commit
c1bdbc78c5
4 changed files with 68 additions and 28 deletions
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
 [](https://travis-ci.org/tonytins/corten) [](https://ci.appveyor.com/project/tonytins/corten) [](https://codecov.io/gh/tonytins/corten)
|
 [](https://travis-ci.org/tonytins/corten) [](https://ci.appveyor.com/project/tonytins/corten) [](https://codecov.io/gh/tonytins/corten)
|
||||||
|
|
||||||
A stack-based virtual machine initially based on [So you want to build a language VM](https://blog.subnetzero.io/post/building-language-vm-part-01/) tutorial.
|
Corten is a stack-based virtual machine written in Rust.
|
||||||
|
|
||||||
|
## Specifications
|
||||||
|
|
||||||
|
See [specifications](docs/spec.md) page.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
|
|
20
docs/spec.md
Normal file
20
docs/spec.md
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Specifications
|
||||||
|
|
||||||
|
## Iridium
|
||||||
|
|
||||||
|
Corten is based on Fletcher Haynes's [So you want to build a language VM](https://blog.subnetzero.io/post/building-language-vm-part-01/) tutorial. His virtual machine used for the tutorial is known as [Iridium](https://github.com/fhaynes/iridium). Despite it's origins, it does aim to be full a fledged virtual machine and is already on it's [third iteration](https://gitlab.com/fletchercp/iridium3) with support for SSH, PIDs and Strings. Corten aims to be Iridium 1-compatible.
|
||||||
|
|
||||||
|
## Instruction Set
|
||||||
|
|
||||||
|
| Register | Opcode |
|
||||||
|
| --- | --- |
|
||||||
|
| 0 | LOAD |
|
||||||
|
| 1 | ADD |
|
||||||
|
| 2 | SUB |
|
||||||
|
| 3 | MUL |
|
||||||
|
| 4 | DIV |
|
||||||
|
| 6 | HLT |
|
||||||
|
| 5 | JMP |
|
||||||
|
| 8 | JMPF |
|
||||||
|
| 9 | JMPB |
|
||||||
|
| _ | IGL |
|
|
@ -6,6 +6,7 @@ pub enum Opcode {
|
||||||
IGL,
|
IGL,
|
||||||
LOAD,
|
LOAD,
|
||||||
ADD,
|
ADD,
|
||||||
|
SUB,
|
||||||
MUL,
|
MUL,
|
||||||
DIV,
|
DIV,
|
||||||
JMP,
|
JMP,
|
||||||
|
@ -14,12 +15,13 @@ pub enum Opcode {
|
||||||
impl From<u8> for Opcode {
|
impl From<u8> for Opcode {
|
||||||
fn from(vm: u8) -> Self {
|
fn from(vm: u8) -> Self {
|
||||||
match vm {
|
match vm {
|
||||||
0 => Opcode::HLT,
|
0 => Opcode::LOAD,
|
||||||
1 => Opcode::LOAD,
|
1 => Opcode::ADD,
|
||||||
2 => Opcode::JMP,
|
2 => Opcode::SUB,
|
||||||
3 => Opcode::ADD,
|
3 => Opcode::MUL,
|
||||||
4 => Opcode::MUL,
|
4 => Opcode::DIV,
|
||||||
5 => Opcode::DIV,
|
6 => Opcode::HLT,
|
||||||
|
7 => Opcode::JMP,
|
||||||
_ => Opcode::IGL,
|
_ => Opcode::IGL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
56
src/vm.rs
56
src/vm.rs
|
@ -1,3 +1,4 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
use crate::instruction::Opcode;
|
use crate::instruction::Opcode;
|
||||||
|
|
||||||
pub struct VM {
|
pub struct VM {
|
||||||
|
@ -53,7 +54,7 @@ impl VM {
|
||||||
match self.decode_opcode() {
|
match self.decode_opcode() {
|
||||||
Opcode::LOAD => {
|
Opcode::LOAD => {
|
||||||
let reg = self.next_8_bits() as usize;
|
let reg = self.next_8_bits() as usize;
|
||||||
let num = self.next_16_bits() as u32;
|
let num = self.next_16_bits() as u16;
|
||||||
self.registers[reg] = num as i32;
|
self.registers[reg] = num as i32;
|
||||||
}
|
}
|
||||||
Opcode::HLT => {
|
Opcode::HLT => {
|
||||||
|
@ -83,6 +84,11 @@ impl VM {
|
||||||
let target = self.registers[self.next_8_bits() as usize];
|
let target = self.registers[self.next_8_bits() as usize];
|
||||||
self.pc = target as usize;
|
self.pc = target as usize;
|
||||||
}
|
}
|
||||||
|
Opcode::SUB => {
|
||||||
|
let reg1 = self.registers[self.next_8_bits() as usize];
|
||||||
|
let reg2 = self.registers[self.next_8_bits() as usize];
|
||||||
|
self.registers[self.next_8_bits() as usize] = reg1 - reg2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -92,6 +98,14 @@ impl VM {
|
||||||
mod vm_tests {
|
mod vm_tests {
|
||||||
use crate::vm::*;
|
use crate::vm::*;
|
||||||
|
|
||||||
|
fn get_test_vm() -> VM {
|
||||||
|
let mut test_vm = VM::new();
|
||||||
|
test_vm.registers[0] = 5;
|
||||||
|
test_vm.registers[1] = 10;
|
||||||
|
|
||||||
|
test_vm
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_crate_vm() {
|
fn test_crate_vm() {
|
||||||
let test_vm = VM::new();
|
let test_vm = VM::new();
|
||||||
|
@ -100,37 +114,37 @@ mod vm_tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_opcode_hlt() {
|
fn test_opcode_hlt() {
|
||||||
let mut test_vm = VM::new();
|
let mut vm = get_test_vm();
|
||||||
let test_bytes = vec![0, 0, 0, 0];
|
let test_bytes = vec![6, 0, 0, 0];
|
||||||
test_vm.program = test_bytes;
|
vm.program = test_bytes;
|
||||||
test_vm.run_once();
|
vm.run_once();
|
||||||
assert_eq!(test_vm.pc, 1);
|
assert_eq!(vm.pc, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_opcode_igl() {
|
fn test_opcode_igl() {
|
||||||
let mut test_vm = VM::new();
|
let mut vm = get_test_vm();
|
||||||
let test_bytes = vec![200, 0, 0, 0];
|
let test_bytes = vec![200, 0, 0, 0];
|
||||||
test_vm.program = test_bytes;
|
vm.program = test_bytes;
|
||||||
test_vm.run_once();
|
vm.run_once();
|
||||||
assert_eq!(test_vm.pc, 1);
|
assert_eq!(vm.pc, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_jmp_opcode() {
|
fn test_jmp_opcode() {
|
||||||
let mut test_vm = VM::new();
|
let mut vm = get_test_vm();
|
||||||
test_vm.registers[0] = 1;
|
vm.registers[0] = 1;
|
||||||
test_vm.program = vec![7, 0, 0, 0];
|
vm.program = vec![7, 0, 0, 0];
|
||||||
test_vm.run_once();
|
vm.run_once();
|
||||||
assert_eq!(test_vm.pc, 1);
|
assert_eq!(vm.pc, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*#[test]
|
#[test]
|
||||||
fn test_load_opcode() {
|
fn test_load_opcode() {
|
||||||
let mut test_vm = VM::new();
|
let mut vm = get_test_vm();
|
||||||
// 500 is represented this way in little endian format
|
// 500 is represented this way in little endian format
|
||||||
test_vm.program = vec![0, 0, 1, 244];
|
vm.program = vec![0, 0, 1, 244];
|
||||||
test_vm.run();
|
vm.run();
|
||||||
assert_eq!(test_vm.registers[0], 500);
|
assert_eq!(vm.registers[0], 500);
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue