WIP const generics

Former-commit-id: 2c38215fb57de66bfce26cfa7e61c460bd2954ac
Former-commit-id: 8fe5cc4fdc58b1155590dbfd6546b280fcdcc259
This commit is contained in:
Michel Heily 2021-06-30 01:25:44 +03:00 committed by MichelOS
parent 1545be7b4f
commit b3c3c70bce
3 changed files with 47 additions and 56 deletions

View file

@ -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, " ];")?;

View 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,

View file

@ -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;
} }