|
@@ -0,0 +1,168 @@
|
|
|
|
+use super::{expr::Variable, value::Value, Addr, Register};
|
|
|
|
+use std::rc::Rc;
|
|
|
|
+
|
|
|
|
+#[derive(Clone, Debug, PartialEq)]
|
|
|
|
+/// OpCode for a register based virtual machine
|
|
|
|
+///
|
|
|
|
+/// The OpCode is a simple enum that represents the operations that can be performed on the register
|
|
|
|
+/// based Virtual Machine.
|
|
|
|
+pub enum OpCode {
|
|
|
|
+ // Data Movement Instructions
|
|
|
|
+ /// LOAD <destination> <value>
|
|
|
|
+ /// Load a value into a register.
|
|
|
|
+ LOAD(Register, Rc<Value>),
|
|
|
|
+
|
|
|
|
+ /// Request an external source for a given information
|
|
|
|
+ /// LOAD <destination> <value>
|
|
|
|
+ /// Load the <value> variable name from an external source which is unknown at compile time.
|
|
|
|
+ /// The value is stored in the given register
|
|
|
|
+ LOAD_EXTERNAL(Register, Variable),
|
|
|
|
+
|
|
|
|
+ /// CPY <destination> <source>
|
|
|
|
+ /// Copy the value from the source register to the destination register.
|
|
|
|
+ CPY(Register, Register),
|
|
|
|
+
|
|
|
|
+ /// MOV <destination> <source>
|
|
|
|
+ /// Move the value from the source register to the destination register.
|
|
|
|
+ MOV(Register, Register),
|
|
|
|
+
|
|
|
|
+ // Arithmetic Operations
|
|
|
|
+ /// ADD <destination> <source1> <source2>
|
|
|
|
+ /// Add the values in source1 and source2, store the result in destination.
|
|
|
|
+ ADD(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// SUB <destination> <source1> <source2>
|
|
|
|
+ /// Subtract the value in source2 from the value in source1, store the result in destination.
|
|
|
|
+ SUB(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// MUL <destination> <source1> <source2>
|
|
|
|
+ /// Multiply the values in source1 and source2, store the result in destination.
|
|
|
|
+ MUL(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// DIV <destination> <source1> <source2>
|
|
|
|
+ /// Divide the value in source1 by the value in source2, store the result in destination.
|
|
|
|
+ DIV(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// MOD <destination> <source1> <source2>
|
|
|
|
+ /// Calculate the remainder of source1 divided by source2, store the result in destination.
|
|
|
|
+ MOD(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// NEG <destination> <source>
|
|
|
|
+ /// Negate the value in the source register, store the result in destination.
|
|
|
|
+ NEG(Register, Register),
|
|
|
|
+
|
|
|
|
+ // Logical Operations
|
|
|
|
+ /// AND <destination> <source1> <source2>
|
|
|
|
+ /// Perform a bitwise AND on the values in source1 and source2, store the result in
|
|
|
|
+ /// destination.
|
|
|
|
+ AND(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// OR <destination> <source1> <source2>
|
|
|
|
+ /// Perform a bitwise OR on the values in source1 and source2, store the result in destination.
|
|
|
|
+ OR(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// XOR <destination> <source1> <source2>
|
|
|
|
+ /// Perform a bitwise XOR on the values in source1 and source2, store the result in
|
|
|
|
+ /// destination.
|
|
|
|
+ XOR(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// NOT <destination> <source>
|
|
|
|
+ /// Perform a bitwise NOT on the value in the source register, store the result in destination.
|
|
|
|
+ NOT(Register, Register),
|
|
|
|
+
|
|
|
|
+ /// SHL <destination> <source> <value>
|
|
|
|
+ /// Shift the value in the source register left by the specified number of bits, store the
|
|
|
|
+ /// result in destination.
|
|
|
|
+ SHL(Register, Register, Value),
|
|
|
|
+
|
|
|
|
+ /// SHR <destination> <source> <value>
|
|
|
|
+ /// Shift the value in the source register right by the specified number of bits, store the
|
|
|
|
+ /// result in destination.
|
|
|
|
+ SHR(Register, Register, Value),
|
|
|
|
+
|
|
|
|
+ /// EQ <destination> <source1> <source2>
|
|
|
|
+ /// Check if source1 is equal to source2, store the result in destination (1 if true, 0 if
|
|
|
|
+ /// false).
|
|
|
|
+ EQ(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// NE <destination> <source1> <source2>
|
|
|
|
+ /// Check if source1 is not equal to source2, store the result in destination (1 if true, 0 if
|
|
|
|
+ /// false).
|
|
|
|
+ NE(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// LT <destination> <source1> <source2>
|
|
|
|
+ /// Check if source1 is less than source2, store the result in destination (1 if true, 0 if
|
|
|
|
+ /// false).
|
|
|
|
+ LT(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// LE <destination> <source1> <source2>
|
|
|
|
+ /// Check if source1 is less than or equal to source2, store the result in destination (1 if
|
|
|
|
+ /// true, 0 if false).
|
|
|
|
+ LE(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// GT <destination> <source1> <source2>
|
|
|
|
+ /// Check if source1 is greater than source2, store the result in destination (1 if true, 0 if
|
|
|
|
+ /// false).
|
|
|
|
+ GT(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ /// GE <destination> <source1> <source2>
|
|
|
|
+ /// Check if source1 is greater than or equal to source2, store the result in destination (1 if
|
|
|
|
+ /// true, 0 if false).
|
|
|
|
+ GE(Register, Register, Register),
|
|
|
|
+
|
|
|
|
+ // Branching Operations
|
|
|
|
+ /// LABEL <address>
|
|
|
|
+ /// Adds a label to the this part of the code
|
|
|
|
+ LABEL(Addr),
|
|
|
|
+
|
|
|
|
+ /// JMP <address>
|
|
|
|
+ /// Jump to the specified address. Addresses are custom tags through a LABEL.
|
|
|
|
+ JMP(Addr),
|
|
|
|
+
|
|
|
|
+ /// JEQ <register> <address>
|
|
|
|
+ /// Jump to the address if the value in the register is true (non-zero).
|
|
|
|
+ JEQ(Register, Addr),
|
|
|
|
+
|
|
|
|
+ /// JNE <register> <address>
|
|
|
|
+ /// Jump to the address if the value in the register is false (zero).
|
|
|
|
+ JNE(Register, Addr),
|
|
|
|
+
|
|
|
|
+ // Control Operation
|
|
|
|
+ /// HLT
|
|
|
|
+ /// Halt the execution.
|
|
|
|
+ HLT(Register),
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl ToString for OpCode {
|
|
|
|
+ fn to_string(&self) -> String {
|
|
|
|
+ match self {
|
|
|
|
+ OpCode::LOAD(r, v) => format!("LOAD {:?} {:?}", r, v),
|
|
|
|
+ OpCode::LOAD_EXTERNAL(r, v) => format!("LOAD_EXTERNAL {:?} {:?}", r, v),
|
|
|
|
+ OpCode::CPY(r1, r2) => format!("CPY {:?} {:?}", r1, r2),
|
|
|
|
+ OpCode::MOV(r1, r2) => format!("MOV {:?} {:?}", r1, r2),
|
|
|
|
+ OpCode::ADD(r1, r2, r3) => format!("ADD {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::SUB(r1, r2, r3) => format!("SUB {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::MUL(r1, r2, r3) => format!("MUL {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::DIV(r1, r2, r3) => format!("DIV {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::MOD(r1, r2, r3) => format!("MOD {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::NEG(r1, r2) => format!("NEG {:?} {:?}", r1, r2),
|
|
|
|
+ OpCode::AND(r1, r2, r3) => format!("AND {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::OR(r1, r2, r3) => format!("OR {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::XOR(r1, r2, r3) => format!("XOR {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::NOT(r1, r2) => format!("NOT {:?} {:?}", r1, r2),
|
|
|
|
+ OpCode::SHL(r1, r2, v) => format!("SHL {:?} {:?} {:?}", r1, r2, v),
|
|
|
|
+ OpCode::SHR(r1, r2, v) => format!("SHR {:?} {:?} {:?}", r1, r2, v),
|
|
|
|
+ OpCode::EQ(r1, r2, r3) => format!("EQ {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::NE(r1, r2, r3) => format!("NE {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::LT(r1, r2, r3) => format!("LT {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::LE(r1, r2, r3) => format!("LE {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::GT(r1, r2, r3) => format!("GT {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::GE(r1, r2, r3) => format!("GE {:?} {:?} {:?}", r1, r2, r3),
|
|
|
|
+ OpCode::LABEL(a) => format!("LABEL {:?}:", a),
|
|
|
|
+ OpCode::JMP(a) => format!("JMP {:?}", a),
|
|
|
|
+ OpCode::JEQ(r, a) => format!("JEQ {:?} {:?}", r, a),
|
|
|
|
+ OpCode::JNE(r, a) => format!("JNE {:?} {:?}", r, a),
|
|
|
|
+ OpCode::HLT(r) => format!("HLT {:?}", r),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|