Fixed bug with VM assigning wrong opcode
- Fixed a bug with VM assigning wrong opcode. After doing a little digging into the Iridium 1 source code (skipping to the next part of the tutorial), I discovered I had to have implement from() function in both directions. I.e. the Opcode outputs integer and integer outputs an Opcode. Derp moment in retrospective since I already had it done for the former but this is a learning experience. - Moved Opcode enum to assembler module.
This commit is contained in:
parent
afb68e46b3
commit
853188b010
8 changed files with 92 additions and 66 deletions
|
@ -1,6 +1,6 @@
|
||||||
# Corten
|
# Corten
|
||||||
|
|
||||||
Corten is a stack-based virtual machine written in Rust as a hobby. It's based on the [Iridium 1](docs/spec.md#Iridium) architecture from Fletcher Haynes's [So you want to build a language VM](https://blog.subnetzero.io/post/building-language-vm-part-01/).
|
Corten is a Corten [MIPS64 Release 6](https://en.wikipedia.org/wiki/MIPS_architecture#MIPS32/MIPS64_Release_6) virtual machine written in Rust as a hobby based on Fletcher Haynes's [So you want to build a language VM](https://blog.subnetzero.io/post/building-language-vm-part-01/).
|
||||||
|
|
||||||
## Build Status
|
## Build Status
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Welcome
|
# Welcome
|
||||||
|
|
||||||
Corten is a stack-based virtual machine written in Rust as a hobby. It's based on the [Iridium 1](spec.md#Iridium) architecture from Fletcher Haynes's [So you want to build a language VM](https://blog.subnetzero.io/post/building-language-vm-part-01/).
|
Corten is a Corten [MIPS64 Release 6](https://en.wikipedia.org/wiki/MIPS_architecture#MIPS32/MIPS64_Release_6) virtual machine written in Rust as a hobby based on Fletcher Haynes's [So you want to build a language VM](https://blog.subnetzero.io/post/building-language-vm-part-01/).
|
||||||
|
|
||||||
## Specifications
|
## Specifications
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## Iridium
|
## 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) and is based on the [MIPS64 Release 6](https://en.wikipedia.org/wiki/MIPS_architecture#MIPS32/MIPS64_Release_6) architecture. Corten aims to be Iridium 1-compatible.
|
Corten [MIPS64 Release 6](https://en.wikipedia.org/wiki/MIPS_architecture#MIPS32/MIPS64_Release_6) virtual machine based on Fletcher Haynes's [So you want to build a language VM](https://blog.subnetzero.io/post/building-language-vm-part-01/) tutorial.
|
||||||
|
|
||||||
## Instruction Set
|
## Instruction Set
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,91 @@ pub mod operand_parser;
|
||||||
pub mod program_parser;
|
pub mod program_parser;
|
||||||
pub mod register_parser;
|
pub mod register_parser;
|
||||||
|
|
||||||
use crate::instruction::Opcode;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
Opcode { code: Opcode },
|
Opcode { code: Opcode },
|
||||||
Register { reg_num: u8 },
|
Register { reg_num: u8 },
|
||||||
Number { value: i32 },
|
Number { value: i32 },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub enum Opcode {
|
||||||
|
HLT,
|
||||||
|
IGL,
|
||||||
|
LOAD,
|
||||||
|
ADD,
|
||||||
|
SUB,
|
||||||
|
MUL,
|
||||||
|
DIV,
|
||||||
|
/// Equal
|
||||||
|
EQ,
|
||||||
|
/// Not equal
|
||||||
|
NEQ,
|
||||||
|
/// Greater then
|
||||||
|
GT,
|
||||||
|
/// Less then
|
||||||
|
LT,
|
||||||
|
/// Greater then or equal to
|
||||||
|
GTE,
|
||||||
|
/// less then or equal
|
||||||
|
LTE,
|
||||||
|
/// jump if equal
|
||||||
|
JMPE,
|
||||||
|
/// Jump
|
||||||
|
JMP,
|
||||||
|
/// Jump forward
|
||||||
|
JMPF,
|
||||||
|
/// Jump backward
|
||||||
|
JMPB,
|
||||||
|
NOP,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u8> for Opcode {
|
||||||
|
fn from(vm: u8) -> Self {
|
||||||
|
match vm {
|
||||||
|
0 => Opcode::LOAD,
|
||||||
|
1 => Opcode::ADD,
|
||||||
|
2 => Opcode::SUB,
|
||||||
|
3 => Opcode::MUL,
|
||||||
|
4 => Opcode::DIV,
|
||||||
|
5 => Opcode::HLT,
|
||||||
|
6 => Opcode::JMP,
|
||||||
|
7 => Opcode::JMPF,
|
||||||
|
8 => Opcode::JMPB,
|
||||||
|
9 => Opcode::EQ,
|
||||||
|
10 => Opcode::NEQ,
|
||||||
|
11 => Opcode::GTE,
|
||||||
|
12 => Opcode::GT,
|
||||||
|
13 => Opcode::LTE,
|
||||||
|
14 => Opcode::LT,
|
||||||
|
15 => Opcode::JMPE,
|
||||||
|
16 => Opcode::NOP,
|
||||||
|
_ => Opcode::IGL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Opcode> for u8 {
|
||||||
|
fn from(op: Opcode) -> Self {
|
||||||
|
match op {
|
||||||
|
Opcode::LOAD => 0,
|
||||||
|
Opcode::ADD => 1,
|
||||||
|
Opcode::SUB => 2,
|
||||||
|
Opcode::MUL => 3,
|
||||||
|
Opcode::DIV => 4,
|
||||||
|
Opcode::HLT => 5,
|
||||||
|
Opcode::JMP => 6,
|
||||||
|
Opcode::JMPF => 7,
|
||||||
|
Opcode::JMPB => 8,
|
||||||
|
Opcode::EQ => 9,
|
||||||
|
Opcode::NEQ => 10,
|
||||||
|
Opcode::GTE => 11,
|
||||||
|
Opcode::LTE => 12,
|
||||||
|
Opcode::LT => 13,
|
||||||
|
Opcode::GT => 14,
|
||||||
|
Opcode::JMPE => 15,
|
||||||
|
Opcode::NOP => 16,
|
||||||
|
Opcode::IGL => 100,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ impl AssemblerInstruction {
|
||||||
match self.opcode.to_owned() {
|
match self.opcode.to_owned() {
|
||||||
Token::Opcode { code } => match code {
|
Token::Opcode { code } => match code {
|
||||||
_ => {
|
_ => {
|
||||||
results.push(code as u8);
|
results.push(code.into());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -30,6 +30,7 @@ impl AssemblerInstruction {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
for operand in vec![&self.op1, &self.op2, &self.op3] {
|
for operand in vec![&self.op1, &self.op2, &self.op3] {
|
||||||
match operand {
|
match operand {
|
||||||
Some(t) => AssemblerInstruction::extract_operand(t, &mut results),
|
Some(t) => AssemblerInstruction::extract_operand(t, &mut results),
|
||||||
|
@ -81,7 +82,7 @@ named!(pub instruction_one<CompleteStr, AssemblerInstruction>,
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod instruction_parser_test {
|
mod instruction_parser_test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::instruction::Opcode;
|
use crate::assembler::Opcode;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_instruction_form_one() {
|
fn test_parse_instruction_form_one() {
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
use nom::*;
|
use nom::*;
|
||||||
use nom::{digit, types::CompleteStr};
|
use nom::{digit, types::CompleteStr};
|
||||||
|
|
||||||
use crate::assembler::Token;
|
use crate::assembler::{Token, Opcode};
|
||||||
use crate::instruction::Opcode;
|
|
||||||
|
|
||||||
named!(pub opcode_load<CompleteStr, Token>,
|
named!(pub opcode_load<CompleteStr, Token>,
|
||||||
do_parse!(tag!("load") >> (Token::Opcode{code: Opcode::LOAD}))
|
do_parse!(tag!("load") >> (Token::Opcode{code: Opcode::LOAD}))
|
||||||
|
|
|
@ -1,61 +1,6 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
use crate::assembler::Opcode;
|
||||||
pub enum Opcode {
|
|
||||||
HLT,
|
|
||||||
IGL,
|
|
||||||
LOAD,
|
|
||||||
ADD,
|
|
||||||
SUB,
|
|
||||||
MUL,
|
|
||||||
DIV,
|
|
||||||
/// Equal
|
|
||||||
EQ,
|
|
||||||
/// Not equal
|
|
||||||
NEQ,
|
|
||||||
/// Greater then
|
|
||||||
GT,
|
|
||||||
/// Less then
|
|
||||||
LT,
|
|
||||||
/// Greater then or equal to
|
|
||||||
GTE,
|
|
||||||
/// less then or equal
|
|
||||||
LTE,
|
|
||||||
/// jump if equal
|
|
||||||
JMPE,
|
|
||||||
/// Jump
|
|
||||||
JMP,
|
|
||||||
/// Jump forward
|
|
||||||
JMPF,
|
|
||||||
/// Jump backward
|
|
||||||
JMPB,
|
|
||||||
NOP,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<u8> for Opcode {
|
|
||||||
fn from(vm: u8) -> Self {
|
|
||||||
match vm {
|
|
||||||
0 => Opcode::LOAD,
|
|
||||||
1 => Opcode::ADD,
|
|
||||||
2 => Opcode::SUB,
|
|
||||||
3 => Opcode::MUL,
|
|
||||||
4 => Opcode::DIV,
|
|
||||||
5 => Opcode::HLT,
|
|
||||||
6 => Opcode::JMP,
|
|
||||||
7 => Opcode::JMPF,
|
|
||||||
8 => Opcode::JMPB,
|
|
||||||
9 => Opcode::EQ,
|
|
||||||
10 => Opcode::NEQ,
|
|
||||||
11 => Opcode::GTE,
|
|
||||||
12 => Opcode::GT,
|
|
||||||
13 => Opcode::LTE,
|
|
||||||
14 => Opcode::LT,
|
|
||||||
15 => Opcode::JMPE,
|
|
||||||
16 => Opcode::NOP,
|
|
||||||
_ => Opcode::IGL,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Instruction {
|
pub struct Instruction {
|
||||||
|
@ -71,6 +16,7 @@ impl Instruction {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod instruction_tests {
|
mod instruction_tests {
|
||||||
use crate::instruction::*;
|
use crate::instruction::*;
|
||||||
|
use crate::assembler::Opcode;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_crate_hlt() {
|
fn test_crate_hlt() {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use crate::instruction::Opcode;
|
use crate::assembler::Opcode;
|
||||||
|
|
||||||
pub struct VM {
|
pub struct VM {
|
||||||
/// Array that simulates the hardware register
|
/// Array that simulates the hardware register
|
||||||
|
|
Reference in a new issue