Instruction'ların Çalıştırılması
Artık bellekten instructionları okuyup kendi tipimiz olan Instruction
'a
dönüştürdüğümüze göre, çalıştırma aşamasına geçebiliriz. Instructionların
tam olarak ne yaptıklarını ayrıntılı olarak
Instruction Yapısı'nda tanımlamıştık. Şimdi bu
enum
'un tüm bileşenlerini işleyeceğimiz bir match
deyimi tanımlayalım.
Her bir instruction program counter'ı (self.pc
) değiştireceğinden,
match
deyimimiz, her bir işlemden sonra program counter'ın yeni değerini
dönüyor.
Bunun dışında Rust'a ait range operatörünü bir çok yerde kullanıyoruz.
Farklı bir syntax olarak 0..=x
gözünüze çarpabilir. Bu range operatörü 0
dan x + 1'e kadar sayıları oluşturmaya yarıyor.
CHIP-8'de her bir instruction 2 byte olduğundan, bir çok instruction program counter'ı 2 byte arttırıyor. Bir sonraki instruction'ı atlamamız gereken durumlarda ise program counter, 4 byte arttırılıyor.
Bunun dışında overflow olabilecek toplama ve çıkarma işlemlerinde, +
veya
-
operatörlerini direkt kullanmak yerine,
overflow_add
ve
overflow_sub
metodlarını kullanacağız. Rust
güvenli bir dil olduğundan overflow durumlarında panikleyerek çıkar.
overflow_add
ve overflow_sub
metodları istediğimiz gibi
toplama ve çıkarma işlemini yaptıktan sonra, overflow olursa bu durumu da
dönüyorlar. Zaten CHIP-8'de overflow durumları da F
registerinde
saklandığı için, bu durumu kolayca F
registerine atayabiliriz.
fn instruction_calistir(&mut self, instruction: Instruction) {
self.pc = match instruction {
Instruction::ClearDisplay => {
self.display.clear();
self.pc + 2
}
Instruction::Return => {
self.sp -= 1;
self.stack[self.sp as usize] + 2
}
Instruction::Jump(addr) => addr,
Instruction::Call(addr) => {
self.stack[self.sp as usize] = self.pc as u16;
self.sp += 1;
addr
}
Instruction::SkipIfEqualsByte(x, v) => {
if self.v[x] == v {
self.pc + 4
} else {
self.pc + 2
}
}
Instruction::SkipIfNotEqualsByte(x, v) => {
if self.v[x] != v {
self.pc + 4
} else {
self.pc + 2
}
}
Instruction::SkipIfEqual(x, y) => {
if self.v[x] == self.v[y] {
self.pc + 4
} else {
self.pc + 2
}
}
Instruction::LoadByte(x, v) => {
self.v[x] = v;
self.pc + 2
}
Instruction::AddByte(x, v) => {
let (res, _) = self.v[x].overflowing_add(v);
self.v[x] = res;
self.pc + 2
}
Instruction::Move(x, y) => {
self.v[x] = self.v[y];
self.pc + 2
}
Instruction::Or(x, y) => {
self.v[x] |= self.v[y];
self.pc + 2
}
Instruction::And(x, y) => {
self.v[x] &= self.v[y];
self.pc + 2
}
Instruction::Xor(x, y) => {
self.v[x] ^= self.v[y];
self.pc + 2
}
Instruction::Add(x, y) => {
let (res, overflow) = self.v[x].overflowing_add(self.v[y]);
self.v[x] = res;
self.v[0x0F] = if overflow { 1 } else { 0 };
self.pc + 2
}
Instruction::Sub(x, y) => {
let (res, overflow) = self.v[x].overflowing_sub(self.v[y]);
self.v[x] = res;
self.v[0x0F] = if overflow { 0 } else { 1 };
self.pc + 2
}
Instruction::ShiftRight(x) => {
self.v[0x0F] = self.v[x] & 0x1;
self.v[x] >>= 1;
self.pc + 2
}
Instruction::ReverseSub(x, y) => {
self.v[0x0F] = if self.v[x] > self.v[y] { 0 } else { 1 };
self.v[x] = self.v[y] - self.v[x];
self.pc + 2
}
Instruction::ShiftLeft(x) => {
self.v[0x0F] = self.v[x] >> 7;
self.v[x] <<= 1;
self.pc + 2
}
Instruction::SkipIfNotEqual(x, y) => {
if self.v[x] != self.v[y] {
self.pc + 4
} else {
self.pc + 2
}
}
Instruction::LoadI(addr) => {
self.i = addr;
self.pc + 2
}
Instruction::JumpPlusZero(addr) => addr + (self.v[0] as u16),
Instruction::Random(x, val) => {
self.v[x] = val & rand::random::<u8>();
self.pc + 2
}
Instruction::Draw(x, y, n) => {
let from = self.i as usize;
let to = from + n as usize;
let x = self.v[x];
let y = self.v[y];
self.v[0x0F] = self
.display
.draw(x as usize, y as usize, &self.memory[from..to]);
self.pc + 2
}
Instruction::SkipIfPressed(x) => {
if self
.keyboard
.pressed_key()
.map_or(false, |key| key == self.v[x])
{
self.pc + 4
} else {
self.pc + 2
}
}
Instruction::SkipIfNotPressed(x) => {
if self
.keyboard
.pressed_key()
.map_or(false, |key| key == self.v[x])
{
self.pc + 2
} else {
self.pc + 4
}
}
Instruction::LoadDelayTimer(x) => {
self.v[x] = self.delay_timer;
self.pc + 2
}
Instruction::WaitForKeyPress(x) => {
if let Some(key) = self.keyboard.pressed_key() {
self.v[x] = key;
self.pc + 2
} else {
self.pc
}
}
Instruction::SetDelayTimer(x) => {
self.delay_timer = self.v[x];
self.pc + 2
}
Instruction::SetSoundTimer(x) => {
self.sound_timer = self.v[x];
self.pc + 2
}
Instruction::AddToI(x) => {
self.i += self.v[x] as u16;
self.pc + 2
}
Instruction::LoadSprite(x) => {
self.i = self.v[x] as u16 * 5;
self.pc + 2
}
Instruction::BCDRepresentation(x) => {
self.memory[self.i as usize] = self.v[x] / 100;
self.memory[self.i as usize + 1] = (self.v[x] / 10) % 10;
self.memory[self.i as usize + 2] = (self.v[x] % 100) % 10;
self.pc + 2
}
Instruction::StoreRegisters(x) => {
for i in 0..=x {
self.memory[self.i as usize + i] = self.v[i]
}
self.i += x as u16 + 1;
self.pc + 2
}
Instruction::LoadRegisters(x) => {
for i in 0..=x {
self.v[i] = self.memory[self.i as usize + i];
}
self.i += x as u16 + 1;
self.pc + 2
}
};
}