WIP const generics
Former-commit-id: 2c38215fb57de66bfce26cfa7e61c460bd2954ac Former-commit-id: 8fe5cc4fdc58b1155590dbfd6546b280fcdcc259
This commit is contained in:
parent
1545be7b4f
commit
b3c3c70bce
|
@ -98,7 +98,7 @@ impl BitAsInt<u32> for u32 {}
|
||||||
/// |_Cond__|1_1_1_0|CPopc|L|__CRn__|__Rd___|__CP#__|_CP__|1|__CRm__| CoRegTrans
|
/// |_Cond__|1_1_1_0|CPopc|L|__CRn__|__Rd___|__CP#__|_CP__|1|__CRm__| CoRegTrans
|
||||||
/// |_Cond__|1_1_1_1|_____________Ignored_by_Processor______________| SWI
|
/// |_Cond__|1_1_1_1|_____________Ignored_by_Processor______________| SWI
|
||||||
/// ```
|
/// ```
|
||||||
fn arm_decode(i: u32) -> &'static str {
|
fn arm_decode(i: u32) -> String {
|
||||||
const T: bool = true;
|
const T: bool = true;
|
||||||
const F: bool = false;
|
const F: bool = false;
|
||||||
|
|
||||||
|
@ -107,25 +107,25 @@ fn arm_decode(i: u32) -> &'static str {
|
||||||
0b00 => {
|
0b00 => {
|
||||||
/* DataProcessing and friends */
|
/* DataProcessing and friends */
|
||||||
|
|
||||||
let result: Option<&str> = match (i.bit_range(23..26), i.bit_range(4..8)) {
|
let result: Option<String> = match (i.bit_range(23..26), i.bit_range(4..8)) {
|
||||||
(0b000, 0b1001) => {
|
(0b000, 0b1001) => {
|
||||||
if 0b0 == i.ibit(22) {
|
if 0b0 == i.ibit(22) {
|
||||||
Some("Multiply")
|
Some(String::from("exec_arm_mul_mla"))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(0b001, 0b1001) => Some("MultiplyLong"),
|
(0b001, 0b1001) => Some(String::from("exec_arm_mull_mlal")),
|
||||||
(0b010, 0b1001) => {
|
(0b010, 0b1001) => {
|
||||||
if 0b00 == i.bit_range(20..22) {
|
if 0b00 == i.bit_range(20..22) {
|
||||||
Some("SingleDataSwap")
|
Some(String::from("exec_arm_swp"))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(0b010, 0b0001) => {
|
(0b010, 0b0001) => {
|
||||||
if 0b010 == i.bit_range(20..23) {
|
if 0b010 == i.bit_range(20..23) {
|
||||||
Some("BranchExchange")
|
Some(format!("exec_arm_bx"))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -135,8 +135,8 @@ fn arm_decode(i: u32) -> &'static str {
|
||||||
|
|
||||||
result.unwrap_or_else(|| {
|
result.unwrap_or_else(|| {
|
||||||
match (i.ibit(25), i.ibit(22), i.ibit(7), i.ibit(4)) {
|
match (i.ibit(25), i.ibit(22), i.ibit(7), i.ibit(4)) {
|
||||||
(0, 0, 1, 1) => "HalfwordDataTransferRegOffset",
|
(0, 0, 1, 1) => String::from("exec_arm_ldr_str_hs_reg"),
|
||||||
(0, 1, 1, 1) => "HalfwordDataTransferImmediateOffset",
|
(0, 1, 1, 1) => String::from("exec_arm_ldr_str_hs_imm"),
|
||||||
_ => {
|
_ => {
|
||||||
let set_cond_flags = i.bit(20);
|
let set_cond_flags = i.bit(20);
|
||||||
// PSR Transfers are encoded as a subset of Data Processing,
|
// PSR Transfers are encoded as a subset of Data Processing,
|
||||||
|
@ -144,13 +144,17 @@ fn arm_decode(i: u32) -> &'static str {
|
||||||
let is_op_not_touching_rd = i.bit_range(21..25) & 0b1100 == 0b1000;
|
let is_op_not_touching_rd = i.bit_range(21..25) & 0b1100 == 0b1000;
|
||||||
if !set_cond_flags && is_op_not_touching_rd {
|
if !set_cond_flags && is_op_not_touching_rd {
|
||||||
if i.bit(21) {
|
if i.bit(21) {
|
||||||
// Since bit-16 is ignored and we can't know statically if this is a MoveToStatus or MoveToFlags
|
// Since bit-16 is ignored and we can't know statically if this is a exec_arm_transfer_to_status or exec_arm_transfer_to_status
|
||||||
"MoveToStatus"
|
String::from("exec_arm_transfer_to_status")
|
||||||
} else {
|
} else {
|
||||||
"MoveFromStatus"
|
String::from("exec_arm_mrs")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
"DataProcessing"
|
format!("exec_arm_data_processing::<{OP}, {IMM}, {SET_FLAGS}, {SHIFT_BY_REG}>",
|
||||||
|
OP=i.bit_range(21..25),
|
||||||
|
IMM=i.bit(25),
|
||||||
|
SET_FLAGS=i.bit(20),
|
||||||
|
SHIFT_BY_REG=i.bit(4))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,21 +162,21 @@ fn arm_decode(i: u32) -> &'static str {
|
||||||
}
|
}
|
||||||
0b01 => {
|
0b01 => {
|
||||||
match (i.bit(25), i.bit(4)) {
|
match (i.bit(25), i.bit(4)) {
|
||||||
(_, F) | (F, T) => "SingleDataTransfer",
|
(_, F) | (F, T) => String::from("exec_arm_ldr_str"),
|
||||||
(T, T) => "Undefined", /* Possible ARM11 but we don't implement these */
|
(T, T) => String::from("arm_undefined"), /* Possible ARM11 but we don't implement these */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0b10 => match i.bit(25) {
|
0b10 => match i.bit(25) {
|
||||||
F => "BlockDataTransfer",
|
F => String::from("exec_arm_ldm_stm"),
|
||||||
T => "BranchLink",
|
T => format!("exec_arm_b_bl::<{LINK}>", LINK = i.bit(24)),
|
||||||
},
|
},
|
||||||
0b11 => {
|
0b11 => {
|
||||||
match (i.ibit(25), i.ibit(24), i.ibit(4)) {
|
match (i.ibit(25), i.ibit(24), i.ibit(4)) {
|
||||||
(0b0, _, _) => "Undefined", /* CoprocessorDataTransfer not implemented */
|
(0b0, _, _) => String::from("arm_undefined"), /* CoprocessorDataTransfer not implemented */
|
||||||
(0b1, 0b0, 0b0) => "Undefined", /* CoprocessorDataOperation not implemented */
|
(0b1, 0b0, 0b0) => String::from("arm_undefined"), /* CoprocessorDataOperation not implemented */
|
||||||
(0b1, 0b0, 0b1) => "Undefined", /* CoprocessorRegisterTransfer not implemented */
|
(0b1, 0b0, 0b1) => String::from("arm_undefined"), /* CoprocessorRegisterTransfer not implemented */
|
||||||
(0b1, 0b1, _) => "SoftwareInterrupt",
|
(0b1, 0b1, _) => String::from("exec_arm_swi"),
|
||||||
_ => "Undefined",
|
_ => String::from("arm_undefined"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
@ -205,27 +209,6 @@ fn thumb_format_to_handler(thumb_fmt: &str) -> &'static str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arm_format_to_handler(arm_fmt: &str) -> &'static str {
|
|
||||||
match arm_fmt {
|
|
||||||
"BranchExchange" => "exec_arm_bx",
|
|
||||||
"BranchLink" => "exec_arm_b_bl",
|
|
||||||
"DataProcessing" => "exec_arm_data_processing",
|
|
||||||
"SoftwareInterrupt" => "exec_arm_swi",
|
|
||||||
"SingleDataTransfer" => "exec_arm_ldr_str",
|
|
||||||
"HalfwordDataTransferImmediateOffset" => "exec_arm_ldr_str_hs_imm",
|
|
||||||
"HalfwordDataTransferRegOffset" => "exec_arm_ldr_str_hs_reg",
|
|
||||||
"BlockDataTransfer" => "exec_arm_ldm_stm",
|
|
||||||
"MoveFromStatus" => "exec_arm_mrs",
|
|
||||||
"MoveToStatus" => "exec_arm_transfer_to_status",
|
|
||||||
"MoveToFlags" => "exec_arm_transfer_to_status",
|
|
||||||
"Multiply" => "exec_arm_mul_mla",
|
|
||||||
"MultiplyLong" => "exec_arm_mull_mlal",
|
|
||||||
"SingleDataSwap" => "exec_arm_swp",
|
|
||||||
"Undefined" => "arm_undefined",
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_thumb_lut(file: &mut fs::File) -> Result<(), std::io::Error> {
|
fn generate_thumb_lut(file: &mut fs::File) -> Result<(), std::io::Error> {
|
||||||
writeln!(file, "impl<I: MemoryInterface> Core<I> {{")?;
|
writeln!(file, "impl<I: MemoryInterface> Core<I> {{")?;
|
||||||
writeln!(
|
writeln!(
|
||||||
|
@ -261,17 +244,16 @@ fn generate_arm_lut(file: &mut fs::File) -> Result<(), std::io::Error> {
|
||||||
" pub const ARM_LUT: [ArmInstructionInfo<I>; 4096] = ["
|
" pub const ARM_LUT: [ArmInstructionInfo<I>; 4096] = ["
|
||||||
)?;
|
)?;
|
||||||
for i in 0..4096 {
|
for i in 0..4096 {
|
||||||
let arm_fmt = arm_decode(((i & 0xff0) << 16) | ((i & 0x00f) << 4));
|
let handler_name = arm_decode(((i & 0xff0) << 16) | ((i & 0x00f) << 4));
|
||||||
let handler_name = arm_format_to_handler(arm_fmt);
|
|
||||||
writeln!(
|
writeln!(
|
||||||
file,
|
file,
|
||||||
" /* {:#x} */
|
" /* {:#x} */
|
||||||
ArmInstructionInfo {{
|
ArmInstructionInfo {{
|
||||||
handler_fn: Core::{},
|
handler_fn: Core::{},
|
||||||
#[cfg(feature = \"debugger\")]
|
#[cfg(feature = \"debugger\")]
|
||||||
fmt: ArmFormat::{},
|
fmt: ArmFormat::Undefined,
|
||||||
}} ,",
|
}} ,",
|
||||||
i, handler_name, arm_fmt
|
i, handler_name
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
writeln!(file, " ];")?;
|
writeln!(file, " ];")?;
|
||||||
|
|
|
@ -3,7 +3,7 @@ use bit::BitIndex;
|
||||||
use super::memory::MemoryInterface;
|
use super::memory::MemoryInterface;
|
||||||
use super::{Core, REG_PC};
|
use super::{Core, REG_PC};
|
||||||
|
|
||||||
#[derive(Debug, Primitive, PartialEq)]
|
#[derive(Debug, Primitive, Eq, PartialEq)]
|
||||||
pub enum AluOpCode {
|
pub enum AluOpCode {
|
||||||
AND = 0b0000,
|
AND = 0b0000,
|
||||||
EOR = 0b0001,
|
EOR = 0b0001,
|
||||||
|
|
|
@ -43,11 +43,10 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
|
|
||||||
/// Branch and Branch with Link (B, BL)
|
/// Branch and Branch with Link (B, BL)
|
||||||
/// Execution Time: 2S + 1N
|
/// Execution Time: 2S + 1N
|
||||||
pub fn exec_arm_b_bl(&mut self, insn: u32) -> CpuAction {
|
pub fn exec_arm_b_bl<const LINK: bool>(&mut self, insn: u32) -> CpuAction {
|
||||||
if insn.link_flag() {
|
if LINK {
|
||||||
self.set_reg(REG_LR, (self.pc_arm() + (self.word_size() as u32)) & !0b1);
|
self.set_reg(REG_LR, (self.pc_arm() + (self.word_size() as u32)) & !0b1);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pc = (self.pc as i32).wrapping_add(insn.branch_offset()) as u32 & !1;
|
self.pc = (self.pc as i32).wrapping_add(insn.branch_offset()) as u32 & !1;
|
||||||
|
|
||||||
self.reload_pipeline32(); // Implies 2S + 1N
|
self.reload_pipeline32(); // Implies 2S + 1N
|
||||||
|
@ -165,9 +164,16 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
///
|
///
|
||||||
/// Cycles: 1S+x+y (from GBATEK)
|
/// Cycles: 1S+x+y (from GBATEK)
|
||||||
/// Add x=1I cycles if Op2 shifted-by-register. Add y=1S+1N cycles if Rd=R15.
|
/// Add x=1I cycles if Op2 shifted-by-register. Add y=1S+1N cycles if Rd=R15.
|
||||||
pub fn exec_arm_data_processing(&mut self, insn: u32) -> CpuAction {
|
pub fn exec_arm_data_processing<
|
||||||
|
const OP: u8,
|
||||||
|
const IMM: bool,
|
||||||
|
const SET_FLAGS: bool,
|
||||||
|
const SHIFT_BY_REG: bool,
|
||||||
|
>(
|
||||||
|
&mut self,
|
||||||
|
insn: u32,
|
||||||
|
) -> CpuAction {
|
||||||
use AluOpCode::*;
|
use AluOpCode::*;
|
||||||
|
|
||||||
let rn = insn.bit_range(16..20) as usize;
|
let rn = insn.bit_range(16..20) as usize;
|
||||||
let rd = insn.bit_range(12..16) as usize;
|
let rd = insn.bit_range(12..16) as usize;
|
||||||
let mut op1 = if rn == REG_PC {
|
let mut op1 = if rn == REG_PC {
|
||||||
|
@ -175,11 +181,14 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
} else {
|
} else {
|
||||||
self.get_reg(rn)
|
self.get_reg(rn)
|
||||||
};
|
};
|
||||||
let mut s_flag = insn.set_cond_flag();
|
let mut s_flag = SET_FLAGS;
|
||||||
let opcode = insn.opcode();
|
let opcode =
|
||||||
|
AluOpCode::from_u8(OP).unwrap_or_else(|| unsafe { std::hint::unreachable_unchecked() });
|
||||||
|
|
||||||
|
// println!("{:?} {} {} {}, {:?} {} {} {}", insn.opcode(), insn.bit(25), insn.set_cond_flags(), insn.bit(4), opcode, IMM, SET_FLAGS, SHIFT_BY_REG);
|
||||||
|
|
||||||
let mut carry = self.cpsr.C();
|
let mut carry = self.cpsr.C();
|
||||||
let op2 = if insn.bit(25) {
|
let op2 = if IMM {
|
||||||
let immediate = insn & 0xff;
|
let immediate = insn & 0xff;
|
||||||
let rotate = 2 * insn.bit_range(8..12);
|
let rotate = 2 * insn.bit_range(8..12);
|
||||||
// TODO refactor out
|
// TODO refactor out
|
||||||
|
@ -187,7 +196,7 @@ impl<I: MemoryInterface> Core<I> {
|
||||||
} else {
|
} else {
|
||||||
let reg = insn & 0xf;
|
let reg = insn & 0xf;
|
||||||
|
|
||||||
let shift_by = if insn.bit(4) {
|
let shift_by = if SHIFT_BY_REG {
|
||||||
if rn == REG_PC {
|
if rn == REG_PC {
|
||||||
op1 += 4;
|
op1 += 4;
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue