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:
Anthony Foxclaw 2020-02-06 19:57:38 -05:00
parent ee08374252
commit c1bdbc78c5
4 changed files with 68 additions and 28 deletions

View file

@ -2,7 +2,11 @@
![Rust](https://github.com/tonytins/corten/workflows/Rust/badge.svg) [![Build Status](https://travis-ci.org/tonytins/corten.svg?branch=master)](https://travis-ci.org/tonytins/corten) [![Build status](https://ci.appveyor.com/api/projects/status/ffru6ik26j2b87ko?svg=true)](https://ci.appveyor.com/project/tonytins/corten) [![codecov](https://codecov.io/gh/tonytins/corten/branch/master/graph/badge.svg)](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

20
docs/spec.md Normal file
View 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 |

View file

@ -6,6 +6,7 @@ pub enum Opcode {
IGL,
LOAD,
ADD,
SUB,
MUL,
DIV,
JMP,
@ -14,12 +15,13 @@ pub enum Opcode {
impl From<u8> for Opcode {
fn from(vm: u8) -> Self {
match vm {
0 => Opcode::HLT,
1 => Opcode::LOAD,
2 => Opcode::JMP,
3 => Opcode::ADD,
4 => Opcode::MUL,
5 => Opcode::DIV,
0 => Opcode::LOAD,
1 => Opcode::ADD,
2 => Opcode::SUB,
3 => Opcode::MUL,
4 => Opcode::DIV,
6 => Opcode::HLT,
7 => Opcode::JMP,
_ => Opcode::IGL,
}
}

View file

@ -1,3 +1,4 @@
#![allow(dead_code)]
use crate::instruction::Opcode;
pub struct VM {
@ -53,7 +54,7 @@ impl VM {
match self.decode_opcode() {
Opcode::LOAD => {
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;
}
Opcode::HLT => {
@ -83,6 +84,11 @@ impl VM {
let target = self.registers[self.next_8_bits() 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
}
@ -92,6 +98,14 @@ impl VM {
mod vm_tests {
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]
fn test_crate_vm() {
let test_vm = VM::new();
@ -100,37 +114,37 @@ mod vm_tests {
#[test]
fn test_opcode_hlt() {
let mut test_vm = VM::new();
let test_bytes = vec![0, 0, 0, 0];
test_vm.program = test_bytes;
test_vm.run_once();
assert_eq!(test_vm.pc, 1);
let mut vm = get_test_vm();
let test_bytes = vec![6, 0, 0, 0];
vm.program = test_bytes;
vm.run_once();
assert_eq!(vm.pc, 1);
}
#[test]
fn test_opcode_igl() {
let mut test_vm = VM::new();
let mut vm = get_test_vm();
let test_bytes = vec![200, 0, 0, 0];
test_vm.program = test_bytes;
test_vm.run_once();
assert_eq!(test_vm.pc, 1);
vm.program = test_bytes;
vm.run_once();
assert_eq!(vm.pc, 1);
}
#[test]
fn test_jmp_opcode() {
let mut test_vm = VM::new();
test_vm.registers[0] = 1;
test_vm.program = vec![7, 0, 0, 0];
test_vm.run_once();
assert_eq!(test_vm.pc, 1);
let mut vm = get_test_vm();
vm.registers[0] = 1;
vm.program = vec![7, 0, 0, 0];
vm.run_once();
assert_eq!(vm.pc, 1);
}
/*#[test]
#[test]
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
test_vm.program = vec![0, 0, 1, 244];
test_vm.run();
assert_eq!(test_vm.registers[0], 500);
}*/
vm.program = vec![0, 0, 1, 244];
vm.run();
assert_eq!(vm.registers[0], 500);
}
}