Skip to content

Instantly share code, notes, and snippets.

@SethDusek
Last active December 31, 2017 22:15
Show Gist options
  • Save SethDusek/07a8976d1e5de0cf22580494f5c5af38 to your computer and use it in GitHub Desktop.
Save SethDusek/07a8976d1e5de0cf22580494f5c5af38 to your computer and use it in GitHub Desktop.
use CPU;
use instruction::*;
#[derive(InstructionInfo)]
#[opcode = 0x02]
pub struct Add;
impl Instruction for Add {
fn run(cpu: &mut CPU, instr: Instr) -> Option<u16> {
let a: u16;
let pc = instr.arg_b(cpu).is_pc(
match instr.arg_a(cpu) {
Ptr(ptr) => a = *ptr,
Val(val) => a = val,
_ => a = 0
}
let mut arg_b = instr.arg_b(cpu);
if let Ptr(ptr) = arg_b { //Don't write if it's a literal
if arg_b.is_pc(&cpu) {
return Some(*ptr+a)
}
*ptr+=a;
}
None
}
}
Compiling dcpu v0.1.0 (file:///home/kamal/rust/dcpu16/dcpu)
warning: unused variable: `cycles`
--> dcpu/src/lib.rs:57:29
|
57 | pub fn cycle(&mut self, cycles: u64) {// currently a noop
| ^^^^^^
|
= note: #[warn(unused_variables)] on by default
= note: to avoid this warning, consider using `_cycles` instead
error[E0382]: use of partially moved value: `arg_b`
--> dcpu/src/instructions/add.rs:18:16
|
17 | if let Ptr(ptr) = arg_b { //Don't write if it's a literal
| --- value moved here
18 | if arg_b.is_pc(&cpu) {
| ^^^^^ value used here after move
|
= note: move occurs because `(arg_b:instruction::Argument::Ptr).0` has type `&mut u16`, which does not implement the `Copy` trait
error[E0502]: cannot borrow `cpu` as immutable because `*cpu` is also borrowed as mutable
--> dcpu/src/instructions/add.rs:18:29
|
16 | let mut arg_b = instr.arg_b(cpu);
| --- mutable borrow occurs here
17 | if let Ptr(ptr) = arg_b { //Don't write if it's a literal
18 | if arg_b.is_pc(&cpu) {
| ^^^ immutable borrow occurs here
...
24 | }
| - mutable borrow ends here
warning: variable does not need to be mutable
--> dcpu/src/instructions/add.rs:16:13
|
16 | let mut arg_b = instr.arg_b(cpu);
| ---^^^^^^
| |
| help: remove this `mut`
|
= note: #[warn(unused_mut)] on by default
error: aborting due to 2 previous errors
error: Could not compile `dcpu`.
To learn more, run the command again with --verbose.
#[derive(Copy, Clone)]
pub struct Instr(u16, bool);
///Argument type for DCPU
#[derive(Debug)]
pub enum Argument<'a> {
Ptr(&'a mut u16),
Val(u16),
None
}
impl <'a> Argument <'a> {
///Derefs a Ptr into a value, or does nothing if it's a value
pub fn into_val(self) -> Self {
if let Ptr(ptr) = self {
Argument::Val(*ptr)
}
else {
self
}
}
///Returns true if the pointer points to PC
pub fn is_pc(&self, cpu: &::CPU) -> bool {
if let Ptr(ref ptr) = *self {
::std::ptr::eq(*ptr as *const _, cpu.pc as *const _)
}
else { false }
}
}
pub use self::Argument::{Ptr, Val};
impl Instr {
pub fn new(instr: u16) -> Self {
let mut special = false;
if (instr & 0b11111) == 0 {
special = true;
}
Instr(instr, special)
}
pub fn opcode(self) -> u8 {
if !self.1 {
(self.0 & 0b11111) as u8
}
else {
(self.0 & (0b11111 << 5)) as u8
}
}
///Returns the word that this Instr represents
pub fn word(self) -> u16 {
self.0
}
fn a(self) -> u8 {
((self.0 >> 10) & 0b111111) as u8
}
fn b(self) -> Option<u8> {
if !self.1 {
Some(((self.0 >> 5) & 0b11111) as u8)
}
else { None }
}
fn parse_arg(cpu: &mut ::CPU, arg: u8) -> Argument {
match arg {
0x00..0x07 => Ptr(&mut cpu.registers()[arg]),
0x08..0x0f => Ptr(&mut cpu.memory[cpu.registers()[arg-8] as usize]), //[register]
0x10..0x17 => Ptr(&mut cpu.memory[(cpu.registers()[arg-10] + cpu.next().word()) as usize]), // [register + next word]
0x19 => Ptr(&mut cpu.memory[cpu.sp as usize]),
0x1b => Ptr(&mut cpu.sp),
0x1c => Ptr(&mut cpu.pc),
0x1d => Ptr(&mut cpu.excess),
0x1e => Ptr(&mut cpu.memory[cpu.next().word() as usize]),
0x1f => Val(cpu.next().word()),
_ => Argument::None
}
}
pub fn arg_a(self, cpu: &mut ::CPU) -> Argument {
let arg = self.a();
match arg {
0x18 => Val(cpu.pop()),
0x20..0x3f => Val((arg as u16).wrapping_sub(0x21)),
_ => Self::parse_arg(cpu, arg)
}.into_val()
}
pub fn arg_b(self, cpu: &mut ::CPU) -> Argument {
if self.1 == true {
return Argument::None
}
let arg = self.b().unwrap();
match arg {
0x18 => {cpu.sp-=1; Ptr(&mut cpu.memory[cpu.sp as usize])},
_ => Self::parse_arg(cpu, arg)
}
}
gen_instructions!(::instructions::Add);
}
//trait that instructions should implement with Instruction
//TODO: improve the design, take feedback, etc
pub trait InstructionInfo {
const OPCODE: u8;
const NAME: &'static str;
const SPECIAL: bool;
//responsible for proper cycles itself
const CYCLES: Option<u64>;
}
pub trait Instruction: InstructionInfo {
///Run the instruction. The return type is the program counter. If it is None, the DCPU will
///automatically increase the program counter by 1
fn run(cpu: &mut ::CPU, instr: Instr) -> Option<u16>;
}
#![feature(exclusive_range_pattern)]
#![feature(attr_literals)]
#[macro_use]
extern crate dcpu_macros;
pub mod registers;
#[macro_use]
mod macros;
pub mod instruction;
pub mod instructions;
pub use instruction::Instr;
use registers::*;
pub struct CPU {
pub sp: u16,
pub registers: Registers,
pub pc: u16,
pub excess: u16,
pub memory: [u16; 0x10000],
pub interrupt_address: u16
}
impl CPU {
pub fn new() -> Self {
CPU {
sp: 0xffff,
registers: Registers::new(),
pc: 0,
excess: 0,
memory: [0; 0x10000],
interrupt_address: 0
}
}
pub fn registers(&mut self) -> &mut Registers {
&mut self.registers
}
pub fn push(&mut self, val: u16) {
self.sp-=1;
self.memory[self.sp as usize] = val;
}
pub fn pop(&mut self) -> u16 {
let val = self.peek();
self.sp+=1;
val
}
pub fn peek(&self) -> u16 {
self.memory[self.sp as usize]
}
///Returns the next instruction
pub fn next(&mut self) -> Instr {
self.sp+=1;
Instr::new(self.memory[self.sp as usize])
}
pub fn cycle(&mut self, cycles: u64) {// currently a noop
}
}
mod add;
pub use self::add::Add;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment