mirror of
https://github.com/guilhermewerner/machine
synced 2025-06-16 05:04:18 +00:00
32 bits
This commit is contained in:
Binary file not shown.
@ -4,11 +4,8 @@ use ::Machine::*;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut vm = Machine::New(0x00);
|
let mut vm = Machine::New([0, 0, 0, 0]);
|
||||||
|
let code = fs::read("Examples/Simple.bin").unwrap();
|
||||||
let bytecode = fs::read("Examples/Simple.bin").unwrap();
|
vm.LoadProgram(&code);
|
||||||
|
|
||||||
vm.LoadProgram(&bytecode, 0x00);
|
|
||||||
|
|
||||||
vm.Execute();
|
vm.Execute();
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,28 @@
|
|||||||
use crate::Machine;
|
use crate::Machine;
|
||||||
|
|
||||||
pub fn Nothing(vm: &mut Machine) -> bool {
|
pub fn Nothing(vm: &mut Machine) -> bool {
|
||||||
vm.WalkAddress(1);
|
vm.Next();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn LoadRegister(vm: &mut Machine) -> bool {
|
pub fn LoadRegister(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
let addr = vm.ReadWord(None);
|
||||||
|
let val = vm.ReadWord(Some(addr));
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
vm.registry.Set(reg, val);
|
||||||
let addr = vm.GetMemory(pc + 2);
|
vm.Walk(5);
|
||||||
|
|
||||||
let val = vm.GetMemory(addr);
|
|
||||||
|
|
||||||
vm.SetRegister(reg, val);
|
|
||||||
vm.WalkAddress(3);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn SaveRegister(vm: &mut Machine) -> bool {
|
pub fn SaveRegister(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let addr = vm.ReadWord(None);
|
||||||
|
let reg = vm.ReadByte(None);
|
||||||
|
let val = vm.registry.Get(reg);
|
||||||
|
|
||||||
let addr = vm.GetMemory(pc + 1);
|
vm.WriteWord(Some(addr), val);
|
||||||
let reg = vm.GetMemory(pc + 2);
|
vm.Walk(5);
|
||||||
|
|
||||||
let val = vm.GetRegister(reg);
|
|
||||||
|
|
||||||
vm.SetMemory(addr, val);
|
|
||||||
vm.WalkAddress(3);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -39,136 +33,131 @@ pub fn Move(_vm: &mut Machine) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn Add(vm: &mut Machine) -> bool {
|
pub fn Add(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 + op2);
|
vm.registry.Set(reg, (op1 + op2).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn AddAssign(vm: &mut Machine) -> bool {
|
pub fn AddAssign(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg1 = vm.ReadByte(None);
|
||||||
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
vm.registry.Set(reg1, (op1 + op2).to_be_bytes());
|
||||||
|
vm.Walk(2);
|
||||||
let op1 = vm.GetRegister(reg);
|
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 2));
|
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 + op2);
|
|
||||||
vm.WalkAddress(3);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Subtract(vm: &mut Machine) -> bool {
|
pub fn Subtract(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 - op2);
|
vm.registry.Set(reg, (op1 - op2).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn SubtractAssign(vm: &mut Machine) -> bool {
|
pub fn SubtractAssign(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg1 = vm.ReadByte(None);
|
||||||
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
vm.registry.Set(reg1, (op1 - op2).to_be_bytes());
|
||||||
|
vm.Walk(2);
|
||||||
let op1 = vm.GetRegister(reg);
|
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 2));
|
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 - op2);
|
|
||||||
vm.WalkAddress(3);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Multiply(vm: &mut Machine) -> bool {
|
pub fn Multiply(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 * op2);
|
vm.registry.Set(reg, (op1 * op2).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn MultiplyAssign(vm: &mut Machine) -> bool {
|
pub fn MultiplyAssign(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg1 = vm.ReadByte(None);
|
||||||
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
vm.registry.Set(reg1, (op1 * op2).to_be_bytes());
|
||||||
|
vm.Walk(2);
|
||||||
let op1 = vm.GetRegister(reg);
|
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 2));
|
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 * op2);
|
|
||||||
vm.WalkAddress(3);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Divide(vm: &mut Machine) -> bool {
|
pub fn Divide(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 / op2);
|
vm.registry.Set(reg, (op1 / op2).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn DivideAssign(vm: &mut Machine) -> bool {
|
pub fn DivideAssign(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg1 = vm.ReadByte(None);
|
||||||
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
vm.registry.Set(reg1, (op1 / op2).to_be_bytes());
|
||||||
|
vm.Walk(2);
|
||||||
let op1 = vm.GetRegister(reg);
|
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 2));
|
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 / op2);
|
|
||||||
vm.WalkAddress(3);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Remainder(vm: &mut Machine) -> bool {
|
pub fn Remainder(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 % op2);
|
vm.registry.Set(reg, (op1 % op2).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn RemainderAssign(vm: &mut Machine) -> bool {
|
pub fn RemainderAssign(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg1 = vm.ReadByte(None);
|
||||||
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
vm.registry.Set(reg1, (op1 % op2).to_be_bytes());
|
||||||
|
vm.Walk(2);
|
||||||
let op1 = vm.GetRegister(reg);
|
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 2));
|
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 % op2);
|
|
||||||
vm.WalkAddress(3);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
@ -179,220 +168,217 @@ pub fn Neg(_vm: &mut Machine) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn And(vm: &mut Machine) -> bool {
|
pub fn And(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 & op2);
|
vm.registry.Set(reg, (op1 & op2).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn AndAssign(vm: &mut Machine) -> bool {
|
pub fn AndAssign(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg1 = vm.ReadByte(None);
|
||||||
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
vm.registry.Set(reg1, (op1 & op2).to_be_bytes());
|
||||||
|
vm.Walk(2);
|
||||||
let op1 = vm.GetRegister(reg);
|
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 2));
|
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 & op2);
|
|
||||||
vm.WalkAddress(3);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Or(vm: &mut Machine) -> bool {
|
pub fn Or(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 | op2);
|
vm.registry.Set(reg, (op1 | op2).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn OrAssign(vm: &mut Machine) -> bool {
|
pub fn OrAssign(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg1 = vm.ReadByte(None);
|
||||||
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
vm.registry.Set(reg1, (op1 | op2).to_be_bytes());
|
||||||
|
vm.Walk(2);
|
||||||
let op1 = vm.GetRegister(reg);
|
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 2));
|
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 | op2);
|
|
||||||
vm.WalkAddress(3);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Xor(vm: &mut Machine) -> bool {
|
pub fn Xor(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 ^ op2);
|
vm.registry.Set(reg, (op1 ^ op2).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn XorAssign(vm: &mut Machine) -> bool {
|
pub fn XorAssign(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg1 = vm.ReadByte(None);
|
||||||
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
vm.registry.Set(reg1, (op1 ^ op2).to_be_bytes());
|
||||||
|
vm.Walk(2);
|
||||||
let op1 = vm.GetRegister(reg);
|
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 2));
|
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 ^ op2);
|
|
||||||
vm.WalkAddress(3);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Not(vm: &mut Machine) -> bool {
|
pub fn Not(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
let op = u32::from_be_bytes(vm.registry.Get(reg));
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
vm.registry.Set(reg, (!op).to_be_bytes());
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
vm.Walk(2);
|
||||||
|
|
||||||
vm.SetRegister(reg, !op1);
|
|
||||||
vm.WalkAddress(3);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ShiftLeft(vm: &mut Machine) -> bool {
|
pub fn ShiftLeft(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 << 1);
|
vm.registry.Set(reg, (op1 << 1).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ShiftLeftAssign(vm: &mut Machine) -> bool {
|
pub fn ShiftLeftAssign(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg1 = vm.ReadByte(None);
|
||||||
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
vm.registry.Set(reg1, (op1 << 1).to_be_bytes());
|
||||||
let op1 = vm.GetRegister(reg);
|
vm.Walk(2);
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 << 1);
|
|
||||||
vm.WalkAddress(2);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ShiftRight(vm: &mut Machine) -> bool {
|
pub fn ShiftRight(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 >> 1);
|
vm.registry.Set(reg, (op1 >> 1).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ShiftRightAssign(vm: &mut Machine) -> bool {
|
pub fn ShiftRightAssign(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg1 = vm.ReadByte(None);
|
||||||
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
vm.registry.Set(reg1, (op1 >> 1).to_be_bytes());
|
||||||
let op1 = vm.GetRegister(reg);
|
vm.Walk(2);
|
||||||
|
|
||||||
vm.SetRegister(reg, op1 >> 1);
|
|
||||||
vm.WalkAddress(2);
|
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Equals(vm: &mut Machine) -> bool {
|
pub fn Equals(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, (op1 == op2) as u8);
|
vm.registry.Set(reg, ((op1 == op2) as u32).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn NotEquals(vm: &mut Machine) -> bool {
|
pub fn NotEquals(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, (op1 != op2) as u8);
|
vm.registry.Set(reg, ((op1 != op2) as u32).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn LessThan(vm: &mut Machine) -> bool {
|
pub fn LessThan(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, (op1 < op2) as u8);
|
vm.registry.Set(reg, ((op1 < op2) as u32).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn LessEquals(vm: &mut Machine) -> bool {
|
pub fn LessEquals(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, (op1 <= op2) as u8);
|
vm.registry.Set(reg, ((op1 <= op2) as u32).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GreaterThan(vm: &mut Machine) -> bool {
|
pub fn GreaterThan(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, (op1 > op2) as u8);
|
vm.registry.Set(reg, ((op1 > op2) as u32).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GreaterEquals(vm: &mut Machine) -> bool {
|
pub fn GreaterEquals(vm: &mut Machine) -> bool {
|
||||||
let pc = vm.GetAddress();
|
let reg = vm.ReadByte(None);
|
||||||
|
|
||||||
let reg = vm.GetMemory(pc + 1);
|
let reg1 = vm.ReadByte(None);
|
||||||
let op1 = vm.GetRegister(vm.GetMemory(pc + 2));
|
let op1 = u32::from_be_bytes(vm.registry.Get(reg1));
|
||||||
let op2 = vm.GetRegister(vm.GetMemory(pc + 3));
|
let reg2 = vm.ReadByte(None);
|
||||||
|
let op2 = u32::from_be_bytes(vm.registry.Get(reg2));
|
||||||
|
|
||||||
vm.SetRegister(reg, (op1 >= op2) as u8);
|
vm.registry.Set(reg, ((op1 >= op2) as u32).to_be_bytes());
|
||||||
vm.WalkAddress(4);
|
vm.Walk(3);
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
5
Source/Limits.rs
Normal file
5
Source/Limits.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub const REGISTER_COUNT: usize = 16;
|
||||||
|
|
||||||
|
pub const STACK_SIZE: usize = 64;
|
||||||
|
|
||||||
|
pub const HEAP_LIMIT: usize = 256;
|
@ -1,33 +1,36 @@
|
|||||||
use std::panic;
|
|
||||||
|
|
||||||
use crate::Instructions::*;
|
use crate::Instructions::*;
|
||||||
use crate::Operations::*;
|
use crate::Operations::*;
|
||||||
|
use crate::Types::*;
|
||||||
|
use crate::{Memory, Registry, Stack, HEAP_LIMIT, STACK_SIZE};
|
||||||
|
|
||||||
pub const ADDRESS_COUNT: usize = 256;
|
#[allow(dead_code)]
|
||||||
pub const REGISTER_COUNT: usize = 16;
|
|
||||||
|
|
||||||
pub struct Machine {
|
pub struct Machine {
|
||||||
program: usize,
|
pub(crate) program_counter: usize,
|
||||||
registers: [u8; REGISTER_COUNT],
|
pub(crate) registry: Registry,
|
||||||
memory: [u8; ADDRESS_COUNT],
|
pub(crate) stack_pointer: usize,
|
||||||
|
pub(crate) link_register: usize,
|
||||||
|
pub(crate) stack: Stack,
|
||||||
|
pub(crate) memory_pointer: usize,
|
||||||
|
pub(crate) heap: Memory,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
impl Machine {
|
impl Machine {
|
||||||
/// Create a machine with program counter.
|
pub fn New(address: Word) -> Self {
|
||||||
pub fn New(pc: u8) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
program: pc as usize,
|
program_counter: u32::from_be_bytes(address) as usize,
|
||||||
registers: [0; REGISTER_COUNT],
|
registry: Registry::default(),
|
||||||
memory: [0; ADDRESS_COUNT],
|
stack_pointer: 0,
|
||||||
|
link_register: 0,
|
||||||
|
stack: Stack::New(STACK_SIZE),
|
||||||
|
memory_pointer: 0,
|
||||||
|
heap: Memory::New(HEAP_LIMIT),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn LoadProgram(&mut self, buffer: &[u8], offset: u8) {
|
pub fn LoadProgram(&mut self, buffer: &[u8]) {
|
||||||
let mut i = offset as usize;
|
for (addr, data) in buffer.to_vec().drain(..).enumerate() {
|
||||||
|
self.heap.WriteByte(addr as u32, data);
|
||||||
for elem in buffer.to_vec().drain(..) {
|
|
||||||
self.memory[i] = elem;
|
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,10 +38,10 @@ impl Machine {
|
|||||||
let mut running = true;
|
let mut running = true;
|
||||||
|
|
||||||
while running {
|
while running {
|
||||||
//self.PrintMemory();
|
self.registry.Print();
|
||||||
self.PrintRegisters();
|
|
||||||
|
|
||||||
let opcode = self.memory[self.program];
|
let opcode = self.heap.ReadByte(self.program_counter as u32);
|
||||||
|
self.memory_pointer = self.program_counter + 1;
|
||||||
|
|
||||||
running = match opcode {
|
running = match opcode {
|
||||||
NOP => Nothing(&mut self),
|
NOP => Nothing(&mut self),
|
||||||
@ -79,77 +82,55 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
pub(crate) fn ReadByte(&mut self, addr: Option<Word>) -> Byte {
|
||||||
fn PrintRegisters(&self) {
|
let mut mp = self.memory_pointer as u32;
|
||||||
for data in self.registers.iter() {
|
|
||||||
print!("{:02x} ", data);
|
if let Some(addr) = addr {
|
||||||
|
mp = u32::from_be_bytes(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!();
|
self.memory_pointer = (mp + 1) as usize;
|
||||||
|
self.heap.ReadByte(mp)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
pub(crate) fn WriteByte(&mut self, addr: Option<Word>, value: Byte) {
|
||||||
fn PrintMemory(&self) {
|
let mut mp = self.memory_pointer as u32;
|
||||||
let mut address = 0;
|
|
||||||
|
|
||||||
for data in self.memory.iter() {
|
if let Some(addr) = addr {
|
||||||
if address % 8 == 0 {
|
mp = u32::from_be_bytes(addr);
|
||||||
println!();
|
};
|
||||||
}
|
|
||||||
|
|
||||||
print!("{:02x} ", data);
|
self.memory_pointer = (mp + 1) as usize;
|
||||||
|
self.heap.WriteByte(mp, value);
|
||||||
|
}
|
||||||
|
|
||||||
address += 1;
|
pub(crate) fn ReadWord(&mut self, addr: Option<Word>) -> Word {
|
||||||
|
let mut mp = self.memory_pointer as u32;
|
||||||
|
|
||||||
|
if let Some(addr) = addr {
|
||||||
|
mp = u32::from_be_bytes(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!();
|
self.memory_pointer = (mp + 4) as usize;
|
||||||
|
self.heap.ReadWord(mp as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetMemory(&self, addr: u8) -> u8 {
|
pub(crate) fn WriteWord(&mut self, addr: Option<Word>, value: Word) {
|
||||||
let index = addr as usize;
|
let mut mp = self.memory_pointer as u32;
|
||||||
|
|
||||||
if index < ADDRESS_COUNT {
|
if let Some(addr) = addr {
|
||||||
self.memory[index]
|
mp = u32::from_be_bytes(addr);
|
||||||
} else {
|
|
||||||
panic!("Invalid Address!")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.memory_pointer = (mp + 4) as usize;
|
||||||
|
self.heap.WriteWord(mp as u32, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn SetMemory(&mut self, addr: u8, val: u8) {
|
pub(crate) fn Next(&mut self) {
|
||||||
let index = addr as usize;
|
self.program_counter += 1;
|
||||||
|
|
||||||
if index < ADDRESS_COUNT {
|
|
||||||
self.memory[index] = val;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn GetRegister(&self, reg: u8) -> u8 {
|
pub(crate) fn Walk(&mut self, bytes: Byte) {
|
||||||
let index = reg as usize;
|
self.program_counter += bytes as usize;
|
||||||
|
|
||||||
if index < REGISTER_COUNT {
|
|
||||||
self.registers[index]
|
|
||||||
} else {
|
|
||||||
panic!("Invalid Register!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn SetRegister(&mut self, reg: u8, val: u8) {
|
|
||||||
let index = reg as usize;
|
|
||||||
|
|
||||||
if index < REGISTER_COUNT {
|
|
||||||
self.registers[index] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn GetAddress(&self) -> u8 {
|
|
||||||
self.program as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn WalkAddress(&mut self, bytes: i8) {
|
|
||||||
self.program += bytes as usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn SetAddress(&mut self, addr: u8) {
|
|
||||||
self.program = addr as usize;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
56
Source/Memory.rs
Normal file
56
Source/Memory.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use crate::Types::*;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
pub struct Memory {
|
||||||
|
storage: Vec<u8>,
|
||||||
|
capacity: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Memory {
|
||||||
|
pub fn New(limit: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
storage: Vec::with_capacity(limit),
|
||||||
|
capacity: limit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn Flush(&mut self) {
|
||||||
|
self.storage.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ReadByte(&mut self, addr: u32) -> Byte {
|
||||||
|
let index = addr as usize;
|
||||||
|
*self.storage.get(index).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn WriteByte(&mut self, addr: u32, value: Byte) {
|
||||||
|
let index = addr as usize;
|
||||||
|
|
||||||
|
if index < self.capacity {
|
||||||
|
self.storage.push(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ReadWord(&mut self, addr: u32) -> Word {
|
||||||
|
let mut index = addr as usize;
|
||||||
|
|
||||||
|
const BYTES: usize = mem::size_of::<Word>();
|
||||||
|
let mut buffer = [0; BYTES];
|
||||||
|
|
||||||
|
for i in 0..BYTES {
|
||||||
|
buffer[i] = *self.storage.get(index).unwrap_or(&0);
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn WriteWord(&mut self, addr: u32, value: Word) {
|
||||||
|
let index = addr as usize;
|
||||||
|
|
||||||
|
if index < self.capacity {
|
||||||
|
self.storage.extend(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,47 +0,0 @@
|
|||||||
/// **0x00** - r0
|
|
||||||
pub const REGISTER_0: u8 = 0x00;
|
|
||||||
|
|
||||||
/// **0x01** - r1
|
|
||||||
pub const REGISTER_1: u8 = 0x01;
|
|
||||||
|
|
||||||
/// **0x02** - r2
|
|
||||||
pub const REGISTER_2: u8 = 0x02;
|
|
||||||
|
|
||||||
/// **0x03** - r3
|
|
||||||
pub const REGISTER_3: u8 = 0x03;
|
|
||||||
|
|
||||||
/// **0x04** - r4
|
|
||||||
pub const REGISTER_4: u8 = 0x04;
|
|
||||||
|
|
||||||
/// **0x05** - r5
|
|
||||||
pub const REGISTER_5: u8 = 0x05;
|
|
||||||
|
|
||||||
/// **0x06** - r6
|
|
||||||
pub const REGISTER_6: u8 = 0x06;
|
|
||||||
|
|
||||||
/// **0x07** - r7
|
|
||||||
pub const REGISTER_7: u8 = 0x07;
|
|
||||||
|
|
||||||
/// **0x08** - r8
|
|
||||||
pub const REGISTER_8: u8 = 0x08;
|
|
||||||
|
|
||||||
/// **0x09** - r9
|
|
||||||
pub const REGISTER_9: u8 = 0x09;
|
|
||||||
|
|
||||||
/// **0x10** - r10
|
|
||||||
pub const REGISTER_10: u8 = 0x10;
|
|
||||||
|
|
||||||
/// **0x11** - r11
|
|
||||||
pub const REGISTER_11: u8 = 0x11;
|
|
||||||
|
|
||||||
/// **0x12** - r12
|
|
||||||
pub const REGISTER_12: u8 = 0x12;
|
|
||||||
|
|
||||||
/// **0x13** - r13
|
|
||||||
pub const REGISTER_13: u8 = 0x13;
|
|
||||||
|
|
||||||
/// **0x14** - r14
|
|
||||||
pub const REGISTER_14: u8 = 0x14;
|
|
||||||
|
|
||||||
/// **0x15** - r15
|
|
||||||
pub const REGISTER_15: u8 = 0x15;
|
|
35
Source/Registry.rs
Normal file
35
Source/Registry.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use crate::Types::*;
|
||||||
|
use crate::REGISTER_COUNT;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Registry {
|
||||||
|
registers: [Word; REGISTER_COUNT],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Registry {
|
||||||
|
pub fn Get(&mut self, index: u8) -> Word {
|
||||||
|
let index = index as usize;
|
||||||
|
|
||||||
|
if index < REGISTER_COUNT {
|
||||||
|
self.registers[index]
|
||||||
|
} else {
|
||||||
|
panic!("Invalid Register!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn Set(&mut self, index: u8, value: Word) {
|
||||||
|
let index = index as usize;
|
||||||
|
|
||||||
|
if index < REGISTER_COUNT {
|
||||||
|
self.registers[index] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn Print(&self) {
|
||||||
|
for r in self.registers.iter() {
|
||||||
|
print!("{:02X}{:02X}{:02X}{:02X} ", r[0], r[1], r[2], r[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
50
Source/Stack.rs
Normal file
50
Source/Stack.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use crate::Types::*;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
pub struct Stack {
|
||||||
|
storage: Vec<u8>,
|
||||||
|
capacity: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stack {
|
||||||
|
pub fn New(size: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
storage: Vec::with_capacity(size),
|
||||||
|
capacity: size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn Flush(&mut self) {
|
||||||
|
self.storage.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn PushByte(&mut self, item: Byte) {
|
||||||
|
if self.storage.len() + 1 < self.capacity {
|
||||||
|
self.storage.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn PopByte(&mut self) -> Byte {
|
||||||
|
self.storage.pop().unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn PushWord(&mut self, item: Word) {
|
||||||
|
const BYTES: usize = mem::size_of::<Word>();
|
||||||
|
|
||||||
|
if self.storage.len() + BYTES < self.capacity {
|
||||||
|
self.storage.extend(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn PopWord(&mut self) -> Word {
|
||||||
|
const BYTES: usize = mem::size_of::<Word>();
|
||||||
|
let mut buffer = [0; BYTES];
|
||||||
|
|
||||||
|
for i in 0..BYTES {
|
||||||
|
buffer[i] = self.storage.pop().unwrap_or(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
5
Source/Types.rs
Normal file
5
Source/Types.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
/// Canonical byte type.
|
||||||
|
pub type Byte = u8;
|
||||||
|
|
||||||
|
/// Canonical data and address type.
|
||||||
|
pub type Word = [u8; 4];
|
@ -1,9 +1,26 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
mod Instructions;
|
mod Instructions;
|
||||||
|
|
||||||
pub mod Operations;
|
pub mod Operations;
|
||||||
pub mod Registers;
|
pub mod Types;
|
||||||
|
|
||||||
|
#[path = "Limits.rs"]
|
||||||
|
mod _Limits;
|
||||||
|
pub use self::_Limits::*;
|
||||||
|
|
||||||
#[path = "Machine.rs"]
|
#[path = "Machine.rs"]
|
||||||
mod _Machine;
|
mod _Machine;
|
||||||
pub use self::_Machine::*;
|
pub use self::_Machine::*;
|
||||||
|
|
||||||
|
#[path = "Memory.rs"]
|
||||||
|
mod _Memory;
|
||||||
|
pub use self::_Memory::*;
|
||||||
|
|
||||||
|
#[path = "Registry.rs"]
|
||||||
|
mod _Registry;
|
||||||
|
pub use self::_Registry::*;
|
||||||
|
|
||||||
|
#[path = "Stack.rs"]
|
||||||
|
mod _Stack;
|
||||||
|
pub use self::_Stack::*;
|
||||||
|
Reference in New Issue
Block a user