Skip to content

Commit

Permalink
cpu: implement interrupt vector table, improves #40
Browse files Browse the repository at this point in the history
  • Loading branch information
martinlindhe committed Feb 13, 2018
1 parent 4341fcc commit 3bd36c9
Show file tree
Hide file tree
Showing 25 changed files with 170 additions and 43 deletions.
1 change: 0 additions & 1 deletion debugger/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use gdk::prelude::*;
use gdk_pixbuf;
use cairo;

use dustbox::memory::Memory;
use dustbox::cpu::CPU;
use dustbox::cpu;
use dustbox::cpu::register::{R8, R16, SR};
Expand Down
Binary file modified docs/render/demo_256/256_alpc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/render/demo_256/256_fire17.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/render/demo_256/256_lava.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/render/demo_256/256_miracle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/render/demo_256/256_plasmexp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/render/demo_256/256_specifi.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/render/demo_256/256_wd95.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/render/demo_256/256_x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/render/demo_512/512_legend.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/render/demo_512/512_morales.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/render/games_com/game_galaxian.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions src/bios.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,72 @@
// dosbox-x: src/hardware/bios.cpp

use cpu::CPU;
use cpu::flags::Flags;
use memory::mmu::MMU;

#[derive(Clone)]
pub struct BIOS {
pub flags_flat: u32, // the FLAGS register offset on stack while in interrupt
}

const BIOS_SEGMENT: u16 = 0xF000;
const EQUIPMENT_WORD: u16 = 0x21;
const EQUIPMENT_WORD_ADDR: u16 = 0x410;

impl BIOS {
pub fn new() -> Self {
// XXX see ROMBIOS_Init in dosbox-x
BIOS {
flags_flat: 0,
}
}

// manipulates the FLAGS register on stack while in a interrupt
pub fn set_flag(&mut self, mmu: &mut MMU, flag_mask: u16, flag_value: bool) {
if self.flags_flat == 0 {
panic!("bios: set_flag with 0 flags_flat");
}
let mut flags = mmu.memory.borrow().read_u16(self.flags_flat);
if flag_value {
flags = flags | flag_mask;
} else {
flags = flags & !flag_mask;
}
mmu.memory.borrow_mut().write_u16(self.flags_flat, flags);
}

pub fn init(&mut self, mut mmu: &mut MMU) {
self.init_ivt(&mut mmu);
self.write_configuration_data_table(&mut mmu);
}

fn init_ivt(&mut self, mmu: &mut MMU) {
const IRET: u8 = 0xCF;
for irq in 0..0xFF {
self.write_ivt_entry(mmu, irq, BIOS_SEGMENT, irq as u16);
mmu.write_u8(BIOS_SEGMENT, irq as u16, IRET);
}
}

fn write_ivt_entry(&self, mmu: &mut MMU, number: u8, seg: u16, offset: u16) {
let _seg = 0;
let _offset = (number as u16) * 4;
mmu.write_u16(_seg, _offset, offset);
mmu.write_u16(_seg, _offset + 2, seg);
}

// initializes the Configuration Data Table
fn write_configuration_data_table(&self, mmu: &mut MMU) {
const ADDR: u16 = 0xE6F5;
mmu.write_u16(BIOS_SEGMENT, ADDR + 0, 8); // table size
mmu.write_u8(BIOS_SEGMENT, ADDR + 2, 0xFC); // model: AT
mmu.write_u8(BIOS_SEGMENT, ADDR + 3, 0); // submodel
mmu.write_u8(BIOS_SEGMENT, ADDR + 4, 0); // BIOS revision
mmu.write_u8(BIOS_SEGMENT, ADDR + 5, 0b00000000); // feature byte 1
mmu.write_u8(BIOS_SEGMENT, ADDR + 6, 0b00000000); // feature byte 2
mmu.write_u8(BIOS_SEGMENT, ADDR + 7, 0b00000000); // feature byte 3
mmu.write_u8(BIOS_SEGMENT, ADDR + 8, 0b00000000); // feature byte 4
mmu.write_u8(BIOS_SEGMENT, ADDR + 9, 0b00000000); // feature byte 5
mmu.write_u16(BIOS_SEGMENT, EQUIPMENT_WORD_ADDR, EQUIPMENT_WORD);
}
}
41 changes: 34 additions & 7 deletions src/cpu/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ impl CPU {
};
self.set_r16(&R16::DI, di);
}
Op::Int() => {
Op::Int => {
let int = self.read_parameter_imm(&op.params.dst);
self.int(&mut hw, int as u8);
}
Expand Down Expand Up @@ -1204,6 +1204,14 @@ impl CPU {
self.flags.overflow = bit15 ^ bit14 != 0;
}
}
Op::Iret => {
self.ip = self.pop16(&mut hw.mmu);
let cs = self.pop16(&mut hw.mmu);
self.set_sr(&SR::CS, cs);
let flags = self.pop16(&mut hw.mmu);
self.flags.set_u16(flags);
hw.bios.flags_flat = 0;
}
Op::Retf => {
if op.params.count() == 1 {
// 1 argument: pop imm16 bytes from stack
Expand All @@ -1222,10 +1230,6 @@ impl CPU {
let sp = self.get_r16(&R16::SP) + imm16;
self.set_r16(&R16::SP, sp);
}
if self.get_r16(&R16::SP) == 0xFFFE {
println!("retn called at end of stack, ending program after {} instructions", self.instruction_count);
self.fatal_error = true;
}
self.ip = self.pop16(&mut hw.mmu);
}
Op::Rol8 => {
Expand Down Expand Up @@ -1888,6 +1892,10 @@ impl CPU {
let (segment, offset) = match *p {
Parameter::Ptr16(seg, imm) => (self.segment(seg), imm),
Parameter::Ptr16Amode(_, ref amode) => self.get_amode_addr(amode),
Parameter::Ptr16AmodeS8(_, ref amode, imms) => {
let (seg, off) = self.get_amode_addr(amode);
(seg, ((off as i32) + (imms as i32)) as u16)
}
_ => panic!("unhandled parameter {:?}", p),
};

Expand Down Expand Up @@ -2117,8 +2125,27 @@ impl CPU {
self.flags.set_parity(al as usize);
}

// execute interrupt
fn int(&mut self, mut hw: &mut Hardware, int: u8) {
fn int(&mut self, hw: &mut Hardware, int: u8) {
let flags = self.flags.u16();
self.push16(&mut hw.mmu, flags);
hw.bios.flags_flat = MMU::to_flat(self.get_sr(&SR::SS), self.get_r16(&R16::SP));

self.flags.interrupt = false;
self.flags.trap = false;
let cs = self.get_sr(&SR::CS);
let ip = self.ip;
self.push16(&mut hw.mmu, cs);
self.push16(&mut hw.mmu, ip);
let base = 0;
let idx = (int as u16) << 2;
let ip = hw.mmu.read_u16(base, idx);
let cs = hw.mmu.read_u16(base, idx + 2);
// println!("int: jumping to interrupt handler for interrupt {:02X} pos at {:04X}:{:04X} = {:04X}:{:04X}", int, base, idx, cs, ip);
self.ip = ip;
self.set_sr(&SR::CS, cs);
}

pub fn handle_interrupt(&mut self, mut hw: &mut Hardware, int: u8) {
match int {
0x03 => {
// debugger interrupt
Expand Down
47 changes: 38 additions & 9 deletions src/cpu/cpu_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -777,13 +777,35 @@ fn can_execute_lds() {
0xBB, 0x00, 0x60, // mov bx,0x6000
0xC7, 0x07, 0x22, 0x11, // mov word [bx],0x1122
0xC7, 0x47, 0x02, 0x88, 0x66, // mov word [bx+0x2],0x6688
0xC5, 0x17, // lds dx,[bx] NOTE: will corrupt DS, breaking further execution
0x8C, 0xD9, // mov cx,ds ; backup ds
0xC5, 0x17, // lds dx,[bx] loads ds and dx with values pointed to at [bx]
0x8C, 0xD8, // mov ax,ds ; save new ds in ax
0x8E, 0xD9, // mov ds,cx ; restore ds
];
machine.load_com(&code);

machine.execute_instructions(4);
machine.execute_instructions(7);
assert_eq!(0x1122, machine.cpu.get_r16(&R16::DX));
assert_eq!(0x6688, machine.cpu.get_sr(&SR::DS));
assert_eq!(0x6688, machine.cpu.get_r16(&R16::AX)); // holds the changed DS value
}

#[test]
fn can_execute_lds_2() {
let mut machine = Machine::new();
let code: Vec<u8> = vec![
0xBB, 0x00, 0x60, // mov bx,0x6000
0xC7, 0x47, 0x06, 0x22, 0x11, // mov word [bx+0x6],0x1122
0xC7, 0x47, 0x08, 0x88, 0x66, // mov word [bx+0x8],0x6688
0x8C, 0xD9, // mov cx,ds ; backup ds
0xC5, 0x57, 0x06, // lds dx,[bx+0x6] loads ds and dx with values pointed to at [bx+6]
0x8C, 0xD8, // mov ax,ds ; save new ds in ax
0x8E, 0xD9, // mov ds,cx ; restore ds
];
machine.load_com(&code);

machine.execute_instructions(7);
assert_eq!(0x1122, machine.cpu.get_r16(&R16::DX));
assert_eq!(0x6688, machine.cpu.get_r16(&R16::AX)); // holds the changed DS value
}

#[test]
Expand Down Expand Up @@ -1731,19 +1753,26 @@ fn can_execute_imul16_3_args() {
assert_eq!(0xF100, machine.cpu.get_r16(&R16::AX));
// 3887
}
/*

#[test]
fn can_execute_int() {
fn can_execute_int_iret() {
// should hit a default interrupt handler (iret) for int 0x72
let mut machine = Machine::new();
let code: Vec<u8> = vec![
0xCD, 0x21, // int 0x21
0xCD, 0x72, // int 0x72
];
machine.load_com(&code);

machine.execute_instruction(); // should now be in interrupt vector table ...
assert_eq!(0x0079, machine.cpu.ip);
assert_eq!(0x085F, machine.cpu.get_sr(&SR::CS));
machine.execute_instruction();
assert_eq!(0xF000, machine.cpu.get_sr(&SR::CS));
assert_eq!(0x0072, machine.cpu.ip);

machine.execute_instruction(); // IRET
assert_eq!(0x085F, machine.cpu.get_sr(&SR::CS));
assert_eq!(0x0102, machine.cpu.ip);
}
*/

#[test]
fn can_execute_xlatb() {
let mut machine = Machine::new();
Expand Down
8 changes: 4 additions & 4 deletions src/cpu/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -908,16 +908,16 @@ impl Decoder {
}
0xCB => op.command = Op::Retf,
0xCC => {
op.command = Op::Int();
op.command = Op::Int;
op.params.dst = Parameter::Imm8(3);
}
0xCD => {
// int imm8
op.command = Op::Int();
op.command = Op::Int;
op.params.dst = Parameter::Imm8(self.read_u8(mmu));
}
0xCE => op.command = Op::Into(),
0xCF => op.command = Op::Iret(),
0xCF => op.command = Op::Iret,
0xD0 => {
// bit shift byte by 1
let x = self.read_mod_reg_rm(mmu);
Expand Down Expand Up @@ -1092,7 +1092,7 @@ impl Decoder {
return (op, length + 1)
}
0xF1 => {
op.command = Op::Int();
op.command = Op::Int;
op.params.dst = Parameter::Imm8(1);
}
0xF2 => {
Expand Down
2 changes: 1 addition & 1 deletion src/cpu/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl Encoder {
out.extend(self.encode_rm(&op.params.dst, op.command.feff_index()));
}
}
Op::Int() => {
Op::Int => {
if let Parameter::Imm8(imm) = op.params.dst {
if imm == 1 {
out.push(0xF1);
Expand Down
2 changes: 1 addition & 1 deletion src/cpu/encoder_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ fn can_encode_bitshift_instructions() {

#[test]
fn can_encode_int() {
let op = Instruction::new1(Op::Int(), Parameter::Imm8(0x21));
let op = Instruction::new1(Op::Int, Parameter::Imm8(0x21));
assert_encdec(&op, "int 0x21", vec!(0xCD, 0x21));
}

Expand Down
18 changes: 9 additions & 9 deletions src/cpu/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ pub struct Flags {
}

// XXX make use of flag mask
const FLAG_CF: u16 = 0x0000_0001;
const FLAG_PF: u16 = 0x0000_0004;
const FLAG_AF: u16 = 0x0000_0010;
const FLAG_ZF: u16 = 0x0000_0040;
const FLAG_SF: u16 = 0x0000_0080;
const FLAG_TF: u16 = 0x0000_0100;
const FLAG_IF: u16 = 0x0000_0200;
const FLAG_DF: u16 = 0x0000_0400;
const FLAG_OF: u16 = 0x0000_0800;
pub const FLAG_CF: u16 = 0x0000_0001;
pub const FLAG_PF: u16 = 0x0000_0004;
pub const FLAG_AF: u16 = 0x0000_0010;
pub const FLAG_ZF: u16 = 0x0000_0040;
pub const FLAG_SF: u16 = 0x0000_0080;
pub const FLAG_TF: u16 = 0x0000_0100;
pub const FLAG_IF: u16 = 0x0000_0200;
pub const FLAG_DF: u16 = 0x0000_0400;
pub const FLAG_OF: u16 = 0x0000_0800;

static PARITY_LOOKUP: [u16; 256] = [
FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF,
Expand Down
8 changes: 6 additions & 2 deletions src/cpu/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,12 @@ impl Instruction {
}

fn hide_segment_prefix(&self) -> bool {
self.command == Op::Add8 ||
self.command == Op::Add16 ||
self.command == Op::Add8 || self.command == Op::Add16 ||
self.command == Op::Adc8 || self.command == Op::Adc16 ||
self.command == Op::Sub8 || self.command == Op::Sub16 ||
self.command == Op::Sbb8 || self.command == Op::Sbb16 ||
self.command == Op::Inc8 || self.command == Op::Inc16 ||
self.command == Op::Dec8 || self.command == Op::Dec16 ||
self.command == Op::Mov8 ||
self.command == Op::Mov16
}
Expand Down
4 changes: 2 additions & 2 deletions src/cpu/op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ pub enum Op {
Inc16,
Insb,
Insw,
Int(),
Int,
Into(),
Iret(),
Iret,
Ja,
Jc,
Jcxz,
Expand Down
2 changes: 1 addition & 1 deletion src/gpu/gpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ impl GPU {
0x8000
}

pub fn init_rom_memory(&mut self, mut mmu: &mut MMU) {
pub fn init(&mut self, mut mmu: &mut MMU) {
let rom_base = 0xC000;

let video_bios_size = self.video_bios_size();
Expand Down
7 changes: 6 additions & 1 deletion src/hardware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ use gpu::GPU;
use memory::mmu::MMU;
use pit::PIT;
use pic::PIC;
use bios::BIOS;

pub struct Hardware {
pub gpu: GPU,
pub mmu: MMU,
pub bios: BIOS,
pub pit: PIT,
pub pic: PIC,
pub pic2: PIC, // secondary pic
Expand All @@ -15,10 +17,13 @@ impl Hardware {
pub fn new() -> Self {
let mut mmu = MMU::new();
let mut gpu = GPU::new();
gpu.init_rom_memory(&mut mmu);
let mut bios = BIOS::new();
bios.init(&mut mmu);
gpu.init(&mut mmu);
Hardware {
mmu: mmu,
gpu: gpu,
bios: bios,
pit: PIT::new(),
pic: PIC::new(),
pic2: PIC::new(),
Expand Down
9 changes: 5 additions & 4 deletions src/interrupt/int16.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use hardware::Hardware;
use cpu::CPU;
use cpu::register::{R8, R16};
use cpu::flags;

// keyboard related interrupts
pub fn handle(cpu: &mut CPU, _hw: &mut Hardware) {
pub fn handle(cpu: &mut CPU, hw: &mut Hardware) {
match cpu.get_r8(&R8::AH) {
0x00 => {
// KEYBOARD - GET KEYSTROKE
Expand All @@ -21,8 +22,8 @@ pub fn handle(cpu: &mut CPU, _hw: &mut Hardware) {
// AH = BIOS scan code
// AL = ASCII character

//println!("XXX impl KEYBOARD - CHECK FOR KEYSTROKE");
cpu.flags.zero = true;
// println!("XXX impl KEYBOARD - CHECK FOR KEYSTROKE");
hw.bios.set_flag(&mut hw.mmu, flags::FLAG_ZF, true);
}
0x11 => {
// KEYBOARD - CHECK FOR ENHANCED KEYSTROKE (enh kbd support only)
Expand All @@ -32,7 +33,7 @@ pub fn handle(cpu: &mut CPU, _hw: &mut Hardware) {
// AH = BIOS scan code
// AL = ASCII character
println!("XXX impl KEYBOARD - CHECK FOR ENHANCED KEYSTROKE");
cpu.flags.zero = true;
hw.bios.set_flag(&mut hw.mmu, flags::FLAG_ZF, true);
}
_ => {
println!("int16 error: unknown ah={:02X}, ax={:04X}",
Expand Down
Loading

0 comments on commit 3bd36c9

Please sign in to comment.