Merge pull request #42 from encounter/updates

Sync @encounter's improvements
This commit is contained in:
Richard Patel 2022-11-15 03:15:35 +01:00 committed by GitHub
commit fa42bb6c9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 2380 additions and 292 deletions

View File

@ -7,7 +7,7 @@ pub struct FormattedIns(pub Ins);
impl Display for FormattedIns { impl Display for FormattedIns {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let simple = self.0.clone().simplified(); let simple = self.0.clone().simplified();
write!(f, "{}{}", simple.mnemonic, simple.ins.suffix())?; write!(f, "{}{}", simple.mnemonic, simple.suffix)?;
let mut writing_offset = false; let mut writing_offset = false;
for (i, arg) in simple.args.iter().enumerate() { for (i, arg) in simple.args.iter().enumerate() {
if i == 0 { if i == 0 {

File diff suppressed because it is too large Load Diff

View File

@ -104,11 +104,97 @@ field_arg!(FPR, u8, "f{}");
// Segment register. // Segment register.
field_arg!(SR, u8); field_arg!(SR, u8);
// Special-purpose register. // Special-purpose register.
field_arg!(SPR, u16); field_arg_no_display!(SPR, u16);
impl Display for SPR {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(match self.0 {
1 => "XER",
8 => "LR",
9 => "CTR",
18 => "DSISR",
19 => "DAR",
22 => "DEC",
25 => "SDR1",
26 => "SRR0",
27 => "SRR1",
272 => "SPRG0",
273 => "SPRG1",
274 => "SPRG2",
275 => "SPRG3",
282 => "EAR",
287 => "PVR",
528 => "IBAT0U",
529 => "IBAT0L",
530 => "IBAT1U",
531 => "IBAT1L",
532 => "IBAT2U",
533 => "IBAT2L",
534 => "IBAT3U",
535 => "IBAT3L",
536 => "DBAT0U",
537 => "DBAT0L",
538 => "DBAT1U",
539 => "DBAT1L",
540 => "DBAT2U",
541 => "DBAT2L",
542 => "DBAT3U",
543 => "DBAT3L",
912 => "GQR0",
913 => "GQR1",
914 => "GQR2",
915 => "GQR3",
916 => "GQR4",
917 => "GQR5",
918 => "GQR6",
919 => "GQR7",
920 => "HID2",
921 => "WPAR",
922 => "DMA_U",
923 => "DMA_L",
936 => "UMMCR0",
937 => "UPMC1",
938 => "UPMC2",
939 => "USIA",
940 => "UMMCR1",
941 => "UPMC3",
942 => "UPMC4",
943 => "USDA",
952 => "MMCR0",
953 => "PMC1",
954 => "PMC2",
955 => "SIA",
956 => "MMCR1",
957 => "PMC3",
958 => "PMC4",
959 => "SDA",
1008 => "HID0",
1009 => "HID1",
1010 => "IABR",
1013 => "DABR",
1017 => "L2CR",
1019 => "ICTC",
1020 => "THRM1",
1021 => "THRM2",
1022 => "THRM3",
_ => return write!(f, "{}", self.0),
})
}
}
// Condition register field. // Condition register field.
field_arg!(CRField, u8, "cr{}"); field_arg!(CRField, u8, "cr{}");
// Condition register bit (index + condition case). // Condition register bit (index + condition case).
field_arg!(CRBit, u8, "{}"); field_arg_no_display!(CRBit, u8);
impl Display for CRBit {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let cr = self.0 >> 2;
let cc = self.0 & 3;
if cr != 0 {
write!(f, "4*{}+", CRField(cr))?;
}
const CR_NAMES: [&str; 4] = ["lt", "gt", "eq", "so"];
f.write_str(CR_NAMES[cc as usize])
}
}
// Paired-single graphics quantization register // Paired-single graphics quantization register
field_arg!(GQR, u8, "qr{}"); field_arg!(GQR, u8, "qr{}");
// Unsigned immediate. // Unsigned immediate.
@ -129,8 +215,6 @@ impl Display for Bit {
// Unsigned opaque argument. // Unsigned opaque argument.
field_arg!(OpaqueU, u32); field_arg!(OpaqueU, u32);
const SPR_LR: usize = 16;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Argument { pub enum Argument {
GPR(GPR), GPR(GPR),
@ -287,12 +371,10 @@ impl Ins {
self.branch_offset().and_then(|offset| { self.branch_offset().and_then(|offset| {
if self.field_AA() { if self.field_AA() {
Some(offset as u32) Some(offset as u32)
} else if offset < 0 {
self.addr.checked_sub((-offset) as u32)
} else { } else {
if offset < 0 { self.addr.checked_add(offset as u32)
self.addr.checked_sub((-offset) as u32)
} else {
self.addr.checked_add(offset as u32)
}
} }
}) })
} }
@ -333,12 +415,13 @@ impl Ins {
pub struct SimplifiedIns { pub struct SimplifiedIns {
pub ins: Ins, pub ins: Ins,
pub mnemonic: &'static str, pub mnemonic: &'static str,
pub suffix: String,
pub args: Vec<Argument>, pub args: Vec<Argument>,
} }
impl Display for SimplifiedIns { impl Display for SimplifiedIns {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}{} ", self.mnemonic, self.ins.suffix())?; write!(f, "{}{} ", self.mnemonic, self.suffix)?;
let mut writing_offset = false; let mut writing_offset = false;
for (i, argument) in self.args.iter().enumerate() { for (i, argument) in self.args.iter().enumerate() {
write!(f, "{}", argument)?; write!(f, "{}", argument)?;
@ -363,6 +446,7 @@ impl SimplifiedIns {
pub(crate) fn basic_form(ins: Ins) -> Self { pub(crate) fn basic_form(ins: Ins) -> Self {
Self { Self {
mnemonic: ins.op.mnemonic(), mnemonic: ins.op.mnemonic(),
suffix: ins.suffix(),
args: ins args: ins
.fields() .fields()
.iter() .iter()

View File

@ -95,6 +95,7 @@ fn test_ins_b() {
assert_asm!(0x4BE03C99, "bl -0x1fc368"); assert_asm!(0x4BE03C99, "bl -0x1fc368");
assert_asm!(0x4BDC1A59, "bl -0x23e5a8"); assert_asm!(0x4BDC1A59, "bl -0x23e5a8");
assert_asm!(0x48000063, "bla 0x60"); assert_asm!(0x48000063, "bla 0x60");
assert_asm!(0x48000002, "ba 0x0");
} }
#[test] #[test]
@ -121,18 +122,29 @@ fn test_ins_bc() {
assert_asm!(0x418502E4, "bgt cr1, 0x2e4"); assert_asm!(0x418502E4, "bgt cr1, 0x2e4");
assert_asm!(0x419A0138, "beq cr6, 0x138"); assert_asm!(0x419A0138, "beq cr6, 0x138");
assert_asm!(0x419C0008, "blt cr7, 0x8"); assert_asm!(0x419C0008, "blt cr7, 0x8");
assert_asm!(0x4240FFF0, "bdz -0x10");
assert_asm!(0x4200F560, "bdnz -0xaa0"); assert_asm!(0x4200F560, "bdnz -0xaa0");
assert_asm!(0x40010014, "bdnzf gt, 0x14");
assert_asm!(0x40410035, "bdzfl gt, 0x34");
assert_asm!(0x41430023, "bdztla so, 0x20");
assert_asm!(0x4108FFE3, "bdnztla 4*cr2+lt, -0x20");
assert_asm!(0x40A20008, "bne+ 0x8");
} }
#[test] #[test]
fn test_ins_bcctr() { fn test_ins_bcctr() {
assert_asm!(0x4E800420, "bctr"); assert_asm!(0x4E800420, "bctr");
assert_asm!(0x4E800421, "bctrl"); assert_asm!(0x4E800421, "bctrl");
assert_asm!(0x4D820420, "beqctr");
assert_asm!(0x4D8D0421, "bgtctrl cr3");
assert_asm!(0x4DA20420, "beqctr+");
assert_asm!(0x4DB90421, "bgtctrl+ cr6");
} }
#[test] #[test]
fn test_ins_bclr() { fn test_ins_bclr() {
assert_asm!(0x4C800020, "bgelr"); assert_asm!(0x4C800020, "bgelr");
assert_asm!(0x4CA00020, "bgelr+");
assert_asm!(0x4C810020, "blelr"); assert_asm!(0x4C810020, "blelr");
assert_asm!(0x4C820020, "bnelr"); assert_asm!(0x4C820020, "bnelr");
assert_asm!(0x4C9E0020, "bnelr cr7"); assert_asm!(0x4C9E0020, "bnelr cr7");
@ -142,6 +154,8 @@ fn test_ins_bclr() {
assert_asm!(0x4D860020, "beqlr cr1"); assert_asm!(0x4D860020, "beqlr cr1");
assert_asm!(0x4E800020, "blr"); assert_asm!(0x4E800020, "blr");
assert_asm!(0x4E800021, "blrl"); assert_asm!(0x4E800021, "blrl");
assert_asm!(0x4D000020, "bdnztlr lt");
assert_asm!(0x4C1F0021, "bdnzflrl 4*cr7+so");
} }
#[test] #[test]
@ -149,11 +163,10 @@ fn test_ins_cmp() {
assert_asm!(0x7C030000, "cmpw r3, r0"); assert_asm!(0x7C030000, "cmpw r3, r0");
} }
/*
#[test] #[test]
fn test_ins_cmpi() { fn test_ins_cmpi() {
assert_asm!(0x2C050D00, "cmpwi r5, 0xd00"); assert_asm!(0x2C050D00, "cmpwi r5, 0xd00");
assert_asm!(0x2F1F0000, "cmpwi cr6, r31, 0"); assert_asm!(0x2F1F0000, "cmpwi cr6, r31, 0x0");
} }
#[test] #[test]
@ -166,16 +179,52 @@ fn test_ins_cmpli() {
assert_asm!(0x2803FFF3, "cmplwi r3, 0xfff3"); assert_asm!(0x2803FFF3, "cmplwi r3, 0xfff3");
assert_asm!(0x2884F8F0, "cmplwi cr1, r4, 0xf8f0"); assert_asm!(0x2884F8F0, "cmplwi cr1, r4, 0xf8f0");
} }
*/
#[test] #[test]
fn test_ins_cntlzw() { fn test_ins_cntlzw() {
assert_asm!(0x7C030034, "cntlzw r3, r0"); assert_asm!(0x7C030034, "cntlzw r3, r0");
} }
#[test]
fn test_ins_crand() {
assert_asm!(0x4C853202, "crand 4*cr1+lt, 4*cr1+gt, 4*cr1+eq");
}
#[test]
fn test_ins_crandc() {
assert_asm!(0x4C642902, "crandc so, 4*cr1+lt, 4*cr1+gt");
}
#[test]
fn test_ins_creqv() {
assert_asm!(0x4CE00A42, "creqv 4*cr1+so, lt, gt");
}
#[test]
fn test_ins_crnand() {
assert_asm!(0x4C2219C2, "crnand gt, eq, so");
}
#[test] #[test]
fn test_ins_cror() { fn test_ins_cror() {
assert_asm!(0x4C411382, "cror 2, 1, 2"); assert_asm!(0x4C411382, "cror eq, gt, eq");
assert_asm!(0x4CA63B82, "cror 4*cr1+gt, 4*cr1+eq, 4*cr1+so");
}
#[test]
fn test_ins_crorc() {
assert_asm!(0x4C432342, "crorc eq, so, 4*cr1+lt");
}
#[test]
fn test_ins_crnor() {
assert_asm!(0x4C011042, "crnor lt, gt, eq");
assert_asm!(0x4CA63042, "crnot 4*cr1+gt, 4*cr1+eq");
}
#[test]
fn test_ins_crxor() {
assert_asm!(0x4CC70182, "crxor 4*cr1+eq, 4*cr1+so, lt");
} }
#[test] #[test]
@ -498,7 +547,10 @@ fn test_ins_mfmsr() {
#[test] #[test]
fn test_ins_mfspr() { fn test_ins_mfspr() {
assert_asm!(0x7E1A02A6, "mfspr r16, 26"); assert_asm!(0x7E1A02A6, "mfsrr0 r16");
assert_asm!(0x7C70FAA6, "mfspr r3, HID0");
assert_asm!(0x7C7482A6, "mfibatu r3, 2");
assert_asm!(0x7C7782A6, "mfibatl r3, 3");
} }
#[test] #[test]
@ -516,14 +568,14 @@ fn test_ins_mtcrf() {
assert_asm!(0x7C6FF120, "mtcrf 255, r3"); assert_asm!(0x7C6FF120, "mtcrf 255, r3");
} }
/*
#[test] #[test]
fn test_ins_mtfsb0() {} fn test_ins_mtfsb0() {
*/ assert_asm!(0xFFA0008C, "mtfsb0 4*cr7+gt")
}
#[test] #[test]
fn test_ins_mtfsb1() { fn test_ins_mtfsb1() {
assert_asm!(0xFFA0004C, "mtfsb1 29"); assert_asm!(0xFFA0004C, "mtfsb1 4*cr7+gt");
} }
#[test] #[test]
@ -539,7 +591,16 @@ fn test_ins_mtmsr() {
#[test] #[test]
fn test_ins_mtspr() { fn test_ins_mtspr() {
assert_asm!(0x7E75FBA6, "mtspr 1013, r19"); assert_asm!(0x7E75FBA6, "mtspr DABR, r19");
assert_asm!(0x7C70FBA6, "mtspr HID0, r3");
assert_asm!(0x7C7603A6, "mtdec r3");
assert_asm!(0x7C7043A6, "mtsprg 0, r3");
assert_asm!(0x7C7143A6, "mtsprg 1, r3");
assert_asm!(0x7C7343A6, "mtsprg 3, r3");
assert_asm!(0x7C7083A6, "mtibatu 0, r3");
assert_asm!(0x7C7483A6, "mtibatu 2, r3");
assert_asm!(0x7C7783A6, "mtibatl 3, r3");
assert_asm!(0x7C7D83A6, "mtdbatl 2, r3");
} }
#[test] #[test]
@ -624,7 +685,7 @@ fn test_ins_psq_lx() {
rA(GPR(0)), rA(GPR(0)),
rB(GPR(0)), rB(GPR(0)),
ps_WX(OpaqueU(0)), ps_WX(OpaqueU(0)),
ps_IX(GQR(0)) ps_IX(GQR(0)),
] ]
); );
assert_eq!(ins.defs(), vec![frD(FPR(0))]); assert_eq!(ins.defs(), vec![frD(FPR(0))]);
@ -792,12 +853,24 @@ fn test_ins_rlwinm() {
// mnemonics // mnemonics
assert_asm!(0x57E5103A, "slwi r5, r31, 2"); assert_asm!(0x57E5103A, "slwi r5, r31, 2");
assert_asm!(0x54832026, "extlwi r3, r4, 20, 4");
assert_asm!(0x5483AB3E, "extrwi r3, r4, 20, 1");
assert_asm!(0x540027BE, "extrwi r0, r0, 2, 2");
assert_asm!(0x54839B3E, "rlwinm r3, r4, 19, 12, 31");
assert_asm!(0x5483203E, "rotlwi r3, r4, 4");
assert_asm!(0x5483E03E, "rotrwi r3, r4, 4");
assert_asm!(0x5464043E, "clrlwi r4, r3, 16");
assert_asm!(0x54830036, "clrrwi r3, r4, 4");
assert_asm!(0x54640FBC, "clrlslwi r4, r3, 31, 1");
assert_asm!(0x54092DB4, "clrlslwi r9, r0, 27, 5");
assert_asm!(0x54096226, "clrlslwi r9, r0, 20, 12");
} }
#[test] #[test]
fn test_ins_rlwnm() { fn test_ins_rlwnm() {
assert_asm!(0x5D6A67FE, "rlwnm r10, r11, r12, 31, 31"); assert_asm!(0x5D6A67FE, "rlwnm r10, r11, r12, 31, 31");
assert_asm!(0x5FC52EFE, "rlwnm r5, r30, r5, 27, 31"); assert_asm!(0x5FC52EFE, "rlwnm r5, r30, r5, 27, 31");
assert_asm!(0x5FC5283F, "rotlw. r5, r30, r5");
} }
#[test] #[test]

View File

@ -205,12 +205,9 @@ impl From<&DolHeaderData> for DolHeader {
impl DolHeader { impl DolHeader {
pub fn section_at(&self, addr: u32) -> Option<&DolSection> { pub fn section_at(&self, addr: u32) -> Option<&DolSection> {
for section in &self.sections { self.sections.iter()
if (section.target..(section.target + section.size)).contains(&addr) { .find(|&section| (section.target..(section.target + section.size))
return Some(section); .contains(&addr))
}
}
None
} }
} }

View File

@ -6,7 +6,7 @@ use std::process::{Command, Stdio};
use std::str::FromStr; use std::str::FromStr;
use itertools::Itertools; use itertools::Itertools;
use proc_macro2::{Ident, Literal, Span, TokenStream, TokenTree}; use proc_macro2::{Group, Ident, Literal, Span, TokenStream, TokenTree};
use quote::quote; use quote::quote;
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use syn::{LitChar, LitInt, LitStr}; use syn::{LitChar, LitInt, LitStr};
@ -74,8 +74,8 @@ pub(crate) struct BitRange(Range<u8>);
impl<'de> Deserialize<'de> for BitRange { impl<'de> Deserialize<'de> for BitRange {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
let range_str: String = Deserialize::deserialize(deserializer)?; let range_str: String = Deserialize::deserialize(deserializer)?;
if let Some((start_str, stop_str)) = range_str.split_once("..") { if let Some((start_str, stop_str)) = range_str.split_once("..") {
@ -232,7 +232,8 @@ impl Opcode {
pub(crate) struct Mnemonic { pub(crate) struct Mnemonic {
name: String, name: String,
opcode: String, opcode: String,
modifiers: Vec<String>, // Overrides modifier list from opcode
modifiers: Option<Vec<String>>,
args: Vec<String>, args: Vec<String>,
condition: String, condition: String,
} }
@ -243,23 +244,31 @@ pub(crate) struct Modifier {
name: String, name: String,
suffix: char, suffix: char,
bit: u8, bit: u8,
condition: String,
} }
impl Modifier { impl Modifier {
fn express_value_self(&self) -> TokenStream { fn express_value_self(&self, field_by_name: &HashMap<String, &Field>) -> Result<TokenStream> {
let modifier_bit = self.bit as usize; if self.condition.is_empty() {
quote!(self.bit(#modifier_bit)) let modifier_bit = self.bit as usize;
Ok(quote!(self.bit(#modifier_bit)))
} else {
compile_mnemonic_condition(
field_by_name,
&self.condition,
)
}
} }
fn construct_accessor(&self) -> TokenStream { fn construct_accessor(&self, field_by_name: &HashMap<String, &Field>) -> Result<TokenStream> {
let field_variant = to_rust_ident("field_", &self.name); let field_variant = to_rust_ident("field_", &self.name);
let value = self.express_value_self(); let value = self.express_value_self(field_by_name)?;
quote! { Ok(quote! {
#[inline(always)] #[inline(always)]
pub fn #field_variant(&self) -> bool { pub fn #field_variant(&self) -> bool {
#value #value
} }
} })
} }
} }
@ -482,7 +491,7 @@ impl Isa {
}); });
// Generate modifiers. // Generate modifiers.
let suffix = express_suffix(&modifier_by_name, opcode)?; let suffix = express_suffix(&modifier_by_name, &field_by_name, &opcode.modifiers)?;
suffix_match_arms.push(quote! { suffix_match_arms.push(quote! {
Opcode::#ident => #suffix, Opcode::#ident => #suffix,
}); });
@ -556,21 +565,29 @@ impl Isa {
)?); )?);
// Emit branch. // Emit branch.
let mnemonic_lit = LitStr::new(&mnemonic.name, Span::call_site()); let mnemonic_lit = LitStr::new(&mnemonic.name, Span::call_site());
// Emit suffix.
let modifiers = mnemonic.modifiers.as_ref().unwrap_or(&opcode.modifiers);
let suffix = express_suffix(&modifier_by_name, &field_by_name, modifiers)?;
// Extract arguments. // Extract arguments.
let mut args = Vec::new(); let mut args = Vec::new();
for arg in &mnemonic.args { for arg in &mnemonic.args {
let (field_name, expression) = arg.split_once('=').unwrap_or((arg, arg));
let field = field_by_name let field = field_by_name
.get(arg) .get(field_name)
.unwrap_or_else(|| panic!("field not found: {}", arg)); .unwrap_or_else(|| panic!("field not found: {}", arg));
let variant = Ident::new(field.arg.as_ref().unwrap(), Span::call_site()); let variant = Ident::new(field.arg.as_ref().unwrap(), Span::call_site());
let value = field.express_value_self(); let value = compile_mnemonic_condition(
args.push(quote!(Argument::#variant(#variant(#value as _)),)); &field_by_name,
expression,
)?;
args.push(quote!(Argument::#variant(#variant((#value) as _)),));
} }
let args = token_stream!(args); let args = token_stream!(args);
simplified_conditions.push(quote! { simplified_conditions.push(quote! {
{ {
return SimplifiedIns { return SimplifiedIns {
mnemonic: #mnemonic_lit, mnemonic: #mnemonic_lit,
suffix: #suffix,
args: vec![#args], args: vec![#args],
ins: self, ins: self,
}; };
@ -592,11 +609,10 @@ impl Isa {
let simplified_ins_match_arms = token_stream!(simplified_ins_match_arms); let simplified_ins_match_arms = token_stream!(simplified_ins_match_arms);
let field_accessors = let field_accessors =
TokenStream::from_iter(self.fields.iter().map(|field| field.construct_accessor())); TokenStream::from_iter(self.fields.iter().map(|field| field.construct_accessor()));
let modifier_accessors = TokenStream::from_iter( let modifiers: Vec<TokenStream> = self.modifiers
self.modifiers .iter()
.iter() .map(|modifier| modifier.construct_accessor(&field_by_name)).try_collect()?;
.map(|modifier| modifier.construct_accessor()), let modifier_accessors = TokenStream::from_iter(modifiers);
);
// Generate final fields function. // Generate final fields function.
let ins_impl = quote! { let ins_impl = quote! {
#[allow(clippy::all, unused_mut)] #[allow(clippy::all, unused_mut)]
@ -701,31 +717,41 @@ fn compile_mnemonic_condition(
code: &str, code: &str,
) -> Result<TokenStream> { ) -> Result<TokenStream> {
let src_stream = TokenStream::from_str(code)?; let src_stream = TokenStream::from_str(code)?;
let token_iter = src_stream.into_iter().flat_map(|token| { fn map_ident(field_by_name: &HashMap<String, &Field>, token: TokenTree) -> TokenStream {
if let TokenTree::Ident(ref ident) = token { match token {
if let Some(field) = field_by_name.get(&ident.to_string()) { TokenTree::Ident(ref ident) => {
return field.express_value_self(); if let Some(field) = field_by_name.get(&ident.to_string()) {
return field.express_value_self();
}
} }
TokenTree::Group(ref group) => {
let iter = group.stream().into_iter().flat_map(|token| map_ident(field_by_name, token));
let stream = TokenStream::from_iter(iter);
return TokenStream::from(TokenTree::Group(Group::new(group.delimiter(), stream)));
}
_ => {}
} }
token.into() token.into()
}); }
let token_iter = src_stream.into_iter().flat_map(|token| map_ident(field_by_name, token));
Ok(TokenStream::from_iter(token_iter)) Ok(TokenStream::from_iter(token_iter))
} }
fn express_suffix( fn express_suffix(
modifier_by_name: &HashMap<String, &Modifier>, modifier_by_name: &HashMap<String, &Modifier>,
opcode: &Opcode, field_by_name: &HashMap<String, &Field>,
modifiers: &[String],
) -> Result<TokenStream> { ) -> Result<TokenStream> {
Ok(if opcode.modifiers.is_empty() { Ok(if modifiers.is_empty() {
quote!(String::new()) quote!(String::new())
} else { } else {
let mut chars = Vec::new(); let mut chars = Vec::new();
for mod_name in &opcode.modifiers { for mod_name in modifiers {
let modifier: &Modifier = modifier_by_name let modifier: &Modifier = modifier_by_name
.get(mod_name) .get(mod_name)
.ok_or_else(|| Error::from(format!("undefined modifier {}", mod_name)))?; .ok_or_else(|| Error::from(format!("undefined modifier {}", mod_name)))?;
let lit_char = LitChar::new(modifier.suffix, Span::call_site()); let lit_char = LitChar::new(modifier.suffix, Span::call_site());
let modifier_bit = modifier.express_value_self(); let modifier_bit = modifier.express_value_self(field_by_name)?;
chars.push(quote! { chars.push(quote! {
if #modifier_bit { if #modifier_bit {
s.push(#lit_char); s.push(#lit_char);

365
isa.yaml
View File

@ -20,7 +20,7 @@ fields:
arg: OpaqueU arg: OpaqueU
bits: 6..11 bits: 6..11
- name: BI - name: BI
arg: OpaqueU arg: CRBit
bits: 11..16 bits: 11..16
- name: BH - name: BH
arg: OpaqueU arg: OpaqueU
@ -141,6 +141,14 @@ fields:
arg: OpaqueU arg: OpaqueU
desc: Immediate for mtfsfi desc: Immediate for mtfsfi
bits: 16..20 bits: 16..20
- name: spr_SPRG
arg: OpaqueU
desc: SPRG index for m[tf]sprg
bits: 14..16
- name: spr_BAT
arg: OpaqueU
desc: IBAT/DBAT index for m[tf][id]bat[ul]
bits: 13..15
- name: TO - name: TO
arg: OpaqueU arg: OpaqueU
desc: Bitset for tw and twi desc: Bitset for tw and twi
@ -167,6 +175,18 @@ modifiers:
- name: AA - name: AA
suffix: a suffix: a
bit: 30 bit: 30
# Predict branch to be taken
- name: BP
suffix: +
condition: BO & 1 == 1 && BD >= 0
# Predict branch not to be taken (fall through)
- name: BNP
suffix: '-'
condition: BO & 1 == 1 && BD < 0
# Predict branch to be taken (implicit dest for LR/CTR)
- name: BP_ND
suffix: +
condition: BO & 1 == 1
opcodes: opcodes:
- name: add - name: add
@ -294,14 +314,14 @@ opcodes:
desc: Branch Conditional desc: Branch Conditional
bitmask: 0xfc000000 bitmask: 0xfc000000
pattern: 0x40000000 pattern: 0x40000000
modifiers: [ LK, AA ] modifiers: [ LK, AA, BP, BNP ]
args: [ BO, BI, BD ] args: [ BO, BI, BD ]
- name: bcctr - name: bcctr
desc: Branch Conditional to Count Register desc: Branch Conditional to Count Register
bitmask: 0xfc007ffe bitmask: 0xfc007ffe
pattern: 0x4c000420 pattern: 0x4c000420
modifiers: [ LK ] modifiers: [ LK, BP_ND ]
args: [ BO, BI, BH ] args: [ BO, BI, BH ]
uses: [ ctr ] uses: [ ctr ]
@ -309,7 +329,7 @@ opcodes:
desc: Branch Conditional to Link Register desc: Branch Conditional to Link Register
bitmask: 0xfc007ffe bitmask: 0xfc007ffe
pattern: 0x4c000020 pattern: 0x4c000020
modifiers: [ LK ] modifiers: [ LK, BP_ND ]
args: [ BO, BI, BH ] args: [ BO, BI, BH ]
uses: [ lr ] uses: [ lr ]
@ -1966,6 +1986,18 @@ mnemonics:
condition: rA == 0 && rS == 0 && uimm == 0 condition: rA == 0 && rS == 0 && uimm == 0
# Rotates/Shifts # Rotates/Shifts
- name: rotlw
opcode: rlwnm
args: [ rA, rS, rB ]
condition: MB == 0 && ME == 31
# TODO rlwimi: inslwi/insrwi
# Rotates/Shifts Immediate
- name: clrrwi
opcode: rlwinm
args: [ rA, rS, ME=31-ME ]
condition: SH == 0 && MB == 0 && ME < 32
- name: clrlwi - name: clrlwi
opcode: rlwinm opcode: rlwinm
args: [ rA, rS, MB ] args: [ rA, rS, MB ]
@ -1973,7 +2005,11 @@ mnemonics:
- name: rotlwi - name: rotlwi
opcode: rlwinm opcode: rlwinm
args: [ rA, rS, SH ] args: [ rA, rS, SH ]
condition: MB == 0 && ME == 31 condition: MB == 0 && ME == 31 && SH <= 16
- name: rotrwi
opcode: rlwinm
args: [ rA, rS, SH=32-SH ]
condition: MB == 0 && ME == 31 && SH > 16
- name: slwi - name: slwi
opcode: rlwinm opcode: rlwinm
args: [ rA, rS, SH ] args: [ rA, rS, SH ]
@ -1982,6 +2018,18 @@ mnemonics:
opcode: rlwinm opcode: rlwinm
args: [ rA, rS, MB ] args: [ rA, rS, MB ]
condition: ME == 31 && 32 - MB == SH condition: ME == 31 && 32 - MB == SH
- name: clrlslwi
opcode: rlwinm
args: [ rA, rS, MB=MB+SH, SH ]
condition: SH < 32 && ME == 31 - SH
- name: extlwi
opcode: rlwinm
args: [ rA, rS, ME=ME+1, SH ]
condition: MB == 0
- name: extrwi
opcode: rlwinm
args: [ rA, rS, MB=32-MB, SH=SH-(32-MB) ]
condition: ME == 31 && SH >= 32 - MB
# Compares Word # Compares Word
- name: cmpwi - name: cmpwi
@ -2062,11 +2110,11 @@ mnemonics:
condition: crbD == crbA && crbD == crbB condition: crbD == crbA && crbD == crbB
- name: crmove - name: crmove
opcode: cror opcode: cror
args: [ crbD, crbA, crbB ] args: [ crbD, crbA ]
condition: crbA == crbB condition: crbA == crbB
- name: crnot - name: crnot
opcode: crnor opcode: crnor
args: [ crbD, crbA, crbB ] args: [ crbD, crbA ]
condition: crbA == crbB condition: crbA == crbB
# Misc # Misc
@ -2099,10 +2147,58 @@ mnemonics:
opcode: mtspr opcode: mtspr
args: [ rS ] args: [ rS ]
condition: spr == 18 condition: spr == 18
- name: mtdbatu - name: mtdar
opcode: mtspr opcode: mtspr
args: [ rS ] args: [ rS ]
condition: spr == 397 condition: spr == 19
- name: mtdec
opcode: mtspr
args: [ rS ]
condition: spr == 22
- name: mtsdr1
opcode: mtspr
args: [ rS ]
condition: spr == 25
- name: mtsrr0
opcode: mtspr
args: [ rS ]
condition: spr == 26
- name: mtsrr1
opcode: mtspr
args: [ rS ]
condition: spr == 27
- name: mtsprg
opcode: mtspr
args: [ spr_SPRG, rS ]
condition: spr & 0b1111111100 == 272
- name: mtear
opcode: mtspr
args: [ rS ]
condition: spr == 282
- name: mttbl
opcode: mtspr
args: [ rS ]
condition: spr == 284
- name: mttbu
opcode: mtspr
args: [ rS ]
condition: spr == 285
- name: mtibatu
opcode: mtspr
args: [ spr_BAT, rS ]
condition: spr & 0b1111111001 == 528
- name: mtibatl
opcode: mtspr
args: [ spr_BAT, rS ]
condition: spr & 0b1111111001 == 529
- name: mtdbatu
opcode: mtspr
args: [ spr_BAT, rS ]
condition: spr & 0b1111111001 == 536
- name: mtdbatl
opcode: mtspr
args: [ spr_BAT, rS ]
condition: spr & 0b1111111001 == 537
# Move from special-purpose register # Move from special-purpose register
- name: mfxer - name: mfxer
@ -2121,117 +2217,155 @@ mnemonics:
opcode: mfspr opcode: mfspr
args: [ rD ] args: [ rD ]
condition: spr == 18 condition: spr == 18
- name: mfdbatu - name: mfdar
opcode: mfspr opcode: mfspr
args: [ rD ] args: [ rD ]
condition: spr == 397 condition: spr == 19
- name: mfdec
opcode: mfspr
args: [ rD ]
condition: spr == 22
- name: mfsdr1
opcode: mfspr
args: [ rD ]
condition: spr == 25
- name: mfsrr0
opcode: mfspr
args: [ rD ]
condition: spr == 26
- name: mfsrr1
opcode: mfspr
args: [ rD ]
condition: spr == 27
- name: mfsprg
opcode: mfspr
args: [ rD, spr_SPRG ]
condition: spr & 0b1111111100 == 272
- name: mfear
opcode: mfspr
args: [ rD ]
condition: spr == 282
- name: mfibatu
opcode: mfspr
args: [ rD, spr_BAT ]
condition: spr & 0b1111111001 == 528
- name: mfibatl
opcode: mfspr
args: [ rD, spr_BAT ]
condition: spr & 0b1111111001 == 529
- name: mfdbatu
opcode: mfspr
args: [ rD, spr_BAT ]
condition: spr & 0b1111111001 == 536
- name: mfdbatl
opcode: mfspr
args: [ rD, spr_BAT ]
condition: spr & 0b1111111001 == 537
# Branch Conditional # Branch Conditional
# bc branch always
- name: b
opcode: bc
modifiers: [ LK, AA ]
condition: BO == 20 && BI == 0
# bc branch if negative # bc branch if negative
- name: blt - name: blt
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ BD ] args: [ BD ]
condition: BO == 12 && BI & 0b11 == 0b00 && crfS == 0 condition: BO & 0b11110 == 12 && BI == 0
- name: blt - name: blt
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ crfS, BD ] args: [ crfS, BD ]
condition: BO == 12 && BI & 0b11 == 0b00 condition: BO & 0b11110 == 12 && BI & 0b11 == 0
# bc branch if not positive # bc branch if not positive
- name: ble - name: ble
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ BD ] args: [ BD ]
condition: BO == 4 && BI & 0b11 == 0b01 && crfS == 0 condition: BO & 0b11110 == 4 && BI == 1
- name: ble - name: ble
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ crfS, BD ] args: [ crfS, BD ]
condition: BO == 4 && BI & 0b11 == 0b01 condition: BO & 0b11110 == 4 && BI & 0b11 == 1
# bc branch if zero # bc branch if zero
- name: beq - name: beq
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ BD ] args: [ BD ]
condition: BO == 12 && BI & 0b11 == 0b10 && crfS == 0 condition: BO & 0b11110 == 12 && BI == 2
- name: beq - name: beq
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ crfS, BD ] args: [ crfS, BD ]
condition: BO == 12 && BI & 0b11 == 0b10 condition: BO & 0b11110 == 12 && BI & 0b11 == 2
# bc branch if not negative # bc branch if not negative
- name: bge - name: bge
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ BD ] args: [ BD ]
condition: BO == 4 && BI & 0b11 == 0b00 && crfS == 0 condition: BO & 0b11110 == 4 && BI == 0
- name: bge - name: bge
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ crfS, BD ] args: [ crfS, BD ]
condition: BO == 4 && BI & 0b11 == 0b00 condition: BO & 0b11110 == 4 && BI & 0b11 == 0
# bc branch if positive # bc branch if positive
- name: bgt - name: bgt
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ BD ] args: [ BD ]
condition: BO == 12 && BI & 0b11 == 0b01 && crfS == 0 condition: BO & 0b11110 == 12 && BI == 1
- name: bgt - name: bgt
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ crfS, BD ] args: [ crfS, BD ]
condition: BO == 12 && BI & 0b11 == 0b01 condition: BO & 0b11110 == 12 && BI & 0b11 == 1
# bc branch if not zero # bc branch if not zero
- name: bne - name: bne
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ BD ] args: [ BD ]
condition: BO == 4 && BI & 0b11 == 0b10 && crfS == 0 condition: BO & 0b11110 == 4 && BI == 2
- name: bne - name: bne
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ crfS, BD ] args: [ crfS, BD ]
condition: BO == 4 && BI & 0b11 == 0b10 condition: BO & 0b11110 == 4 && BI & 0b11 == 2
# bc branch if summary overflow # bc branch if summary overflow
- name: bso - name: bso
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ BD ] args: [ BD ]
condition: BO == 12 && BI & 0b11 == 0b11 && crfS == 0 condition: BO & 0b11110 == 12 && BI == 3
- name: bso - name: bso
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ crfS, BD ] args: [ crfS, BD ]
condition: BO == 12 && BI & 0b11 == 0b11 condition: BO & 0b11110 == 12 && BI & 0b11 == 3
# bc branch if not summary overflow # bc branch if not summary overflow
- name: bns - name: bns
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ BD ] args: [ BD ]
condition: BO == 4 && BI & 0b11 == 0b11 && crfS == 0 condition: BO & 0b11110 == 4 && BI == 3
- name: bns - name: bns
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ crfS, BD ] args: [ crfS, BD ]
condition: BO == 4 && BI & 0b11 == 0b11 condition: BO & 0b11110 == 4 && BI & 0b11 == 3
# bc decrement CTR, branch if CTR non-zero
- name: bdnz - name: bdnz
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ BD ] args: [ BD ]
condition: BO == 16 && BI == 0 condition: BO & 0b11110 == 16 && BI == 0
# bc decrement CTR, branch if CTR non-zero AND condition true
- name: bdnzt
opcode: bc
args: [ BI, BD ]
condition: BO & 0b11110 == 8
# bc decrement CTR, branch if CTR non-zero AND condition false
- name: bdnzf
opcode: bc
args: [ BI, BD ]
condition: BO & 0b11110 == 0
# bc decrement CTR, branch if CTR zero
- name: bdz - name: bdz
opcode: bc opcode: bc
modifiers: [ LK, AA ]
args: [ BD ] args: [ BD ]
condition: BO == 18 && BI == 0 condition: BO & 0b11110 == 18 && BI == 0
# TODO support conditional bd... # bc decrement CTR, branch if CTR zero AND condition true
- name: bdzt
opcode: bc
args: [ BI, BD ]
condition: BO & 0b11110 == 10
# bc decrement CTR, branch if CTR zero AND condition false
- name: bdzf
opcode: bc
args: [ BI, BD ]
condition: BO & 0b11110 == 2
# Branch Conditional to Count Register # Branch Conditional to Count Register
# bcctr branch always # bcctr branch always
@ -2242,86 +2376,69 @@ mnemonics:
# bcctr branch if negative # bcctr branch if negative
- name: bltctr - name: bltctr
opcode: bcctr opcode: bcctr
modifiers: [ LK ] condition: BO & 0b11110 == 12 && BI == 0
condition: BO == 12 && BI & 0b11 == 0b00 && crfS == 0
- name: bltctr - name: bltctr
opcode: bcctr opcode: bcctr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 12 && BI & 0b11 == 0b00 condition: BO & 0b11110 == 12 && BI & 0b11 == 0
# bcctr branch if not positive # bcctr branch if not positive
- name: blectr - name: blectr
opcode: bcctr opcode: bcctr
modifiers: [ LK ] condition: BO & 0b11110 == 4 && BI == 1
condition: BO == 4 && BI & 0b11 == 0b01 && crfS == 0
- name: blectr - name: blectr
opcode: bcctr opcode: bcctr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 4 && BI & 0b11 == 0b01 condition: BO & 0b11110 == 4 && BI & 0b11 == 1
# bcctr branch if zero # bcctr branch if zero
- name: beqctr - name: beqctr
opcode: bcctr opcode: bcctr
modifiers: [ LK ] condition: BO & 0b11110 == 12 && BI == 2
condition: BO == 12 && BI & 0b11 == 0b10 && crfS == 0
- name: beqctr - name: beqctr
opcode: bcctr opcode: bcctr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 12 && BI & 0b11 == 0b10 condition: BO & 0b11110 == 12 && BI & 0b11 == 2
# bcctr branch if not negative # bcctr branch if not negative
- name: bgectr - name: bgectr
opcode: bcctr opcode: bcctr
modifiers: [ LK ] condition: BO & 0b11110 == 4 && BI == 0
condition: BO == 4 && BI & 0b11 == 0b00 && crfS == 0
- name: bgectr - name: bgectr
opcode: bcctr opcode: bcctr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 4 && BI & 0b11 == 0b00 condition: BO & 0b11110 == 4 && BI & 0b11 == 0
# bcctr branch if positive # bcctr branch if positive
- name: bgtctr - name: bgtctr
opcode: bcctr opcode: bcctr
modifiers: [ LK ] condition: BO & 0b11110 == 12 && BI == 1
condition: BO == 12 && BI & 0b11 == 0b01 && crfS == 0
- name: bgtctr - name: bgtctr
opcode: bcctr opcode: bcctr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 12 && BI & 0b11 == 0b01 condition: BO & 0b11110 == 12 && BI & 0b11 == 1
# bcctr branch if not zero # bcctr branch if not zero
- name: bnectr - name: bnectr
opcode: bcctr opcode: bcctr
modifiers: [ LK ] condition: BO & 0b11110 == 4 && BI == 2
condition: BO == 4 && BI & 0b11 == 0b10 && crfS == 0
- name: bnectr - name: bnectr
opcode: bcctr opcode: bcctr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 4 && BI & 0b11 == 0b10 condition: BO & 0b11110 == 4 && BI & 0b11 == 2
# bcctr branch if summary overflow # bcctr branch if summary overflow
- name: bsoctr - name: bsoctr
opcode: bcctr opcode: bcctr
modifiers: [ LK ] condition: BO & 0b11110 == 12 && BI == 3
condition: BO == 12 && BI & 0b11 == 0b11 && crfS == 0
- name: bsoctr - name: bsoctr
opcode: bcctr opcode: bcctr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 12 && BI & 0b11 == 0b11 condition: BO & 0b11110 == 12 && BI & 0b11 == 3
# bcctr branch if not summary overflow # bcctr branch if not summary overflow
- name: bnsctr - name: bnsctr
opcode: bcctr opcode: bcctr
modifiers: [ LK ] condition: BO & 0b11110 == 4 && BI == 3
condition: BO == 4 && BI & 0b11 == 0b11 && crfS == 0
- name: bnsctr - name: bnsctr
opcode: bcctr opcode: bcctr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 4 && BI & 0b11 == 0b11 condition: BO & 0b11110 == 4 && BI & 0b11 == 3
# Branch Conditional to Link Register # Branch Conditional to Link Register
# bclr branch always # bclr branch always
- name: blr - name: blr
opcode: bclr opcode: bclr
@ -2330,80 +2447,92 @@ mnemonics:
# bclr branch if negative # bclr branch if negative
- name: bltlr - name: bltlr
opcode: bclr opcode: bclr
modifiers: [ LK ] condition: BO & 0b11110 == 12 && BI == 0
condition: BO == 12 && BI & 0b11 == 0b00 && crfS == 0
- name: bltlr - name: bltlr
opcode: bclr opcode: bclr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 12 && BI & 0b11 == 0b00 condition: BO & 0b11110 == 12 && BI & 0b11 == 0
# bclr branch if not positive # bclr branch if not positive
- name: blelr - name: blelr
opcode: bclr opcode: bclr
modifiers: [ LK ] condition: BO & 0b11110 == 4 && BI == 1
condition: BO == 4 && BI & 0b11 == 0b01 && crfS == 0
- name: blelr - name: blelr
opcode: bclr opcode: bclr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 4 && BI & 0b11 == 0b01 condition: BO & 0b11110 == 4 && BI & 0b11 == 1
# bclr branch if zero # bclr branch if zero
- name: beqlr - name: beqlr
opcode: bclr opcode: bclr
modifiers: [ LK ] condition: BO & 0b11110 == 12 && BI == 2
condition: BO == 12 && BI & 0b11 == 0b10 && crfS == 0
- name: beqlr - name: beqlr
opcode: bclr opcode: bclr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 12 && BI & 0b11 == 0b10 condition: BO & 0b11110 == 12 && BI & 0b11 == 2
# bclr branch if not negative # bclr branch if not negative
- name: bgelr - name: bgelr
opcode: bclr opcode: bclr
modifiers: [ LK ] condition: BO & 0b11110 == 4 && BI == 0
condition: BO == 4 && BI & 0b11 == 0b00 && crfS == 0
- name: bgelr - name: bgelr
opcode: bclr opcode: bclr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 4 && BI & 0b11 == 0b00 condition: BO & 0b11110 == 4 && BI & 0b11 == 0
# bclr branch if positive # bclr branch if positive
- name: bgtlr - name: bgtlr
opcode: bclr opcode: bclr
modifiers: [ LK ] condition: BO & 0b11110 == 12 && BI == 1
condition: BO == 12 && BI & 0b11 == 0b01 && crfS == 0
- name: bgtlr - name: bgtlr
opcode: bclr opcode: bclr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 12 && BI & 0b11 == 0b01 condition: BO & 0b11110 == 12 && BI & 0b11 == 1
# bclr branch if not zero # bclr branch if not zero
- name: bnelr - name: bnelr
opcode: bclr opcode: bclr
modifiers: [ LK ] condition: BO & 0b11110 == 4 && BI == 2
condition: BO == 4 && BI & 0b11 == 0b10 && crfS == 0
- name: bnelr - name: bnelr
opcode: bclr opcode: bclr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 4 && BI & 0b11 == 0b10 condition: BO & 0b11110 == 4 && BI & 0b11 == 2
# bclr branch if summary overflow # bclr branch if summary overflow
- name: bsolr - name: bsolr
opcode: bclr opcode: bclr
modifiers: [ LK ] condition: BO & 0b11110 == 12 && BI == 3
condition: BO == 12 && BI & 0b11 == 0b11 && crfS == 0
- name: bsolr - name: bsolr
opcode: bclr opcode: bclr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 12 && BI & 0b11 == 0b11 condition: BO & 0b11110 == 12 && BI & 0b11 == 3
# bclr branch if not summary overflow # bclr branch if not summary overflow
- name: bnslr - name: bnslr
opcode: bclr opcode: bclr
modifiers: [ LK ] condition: BO & 0b11110 == 4 && BI == 3
condition: BO == 4 && BI & 0b11 == 0b11 && crfS == 0
- name: bnslr - name: bnslr
opcode: bclr opcode: bclr
modifiers: [ LK ]
args: [ crfS ] args: [ crfS ]
condition: BO == 4 && BI & 0b11 == 0b11 condition: BO & 0b11110 == 4 && BI & 0b11 == 3
# bclr decrement CTR, branch if CTR non-zero
- name: bdnzlr
opcode: bclr
condition: BO & 0b11110 == 16 && BI == 0
# bclr decrement CTR, branch if CTR non-zero AND condition true
- name: bdnztlr
opcode: bclr
args: [ BI ]
condition: BO & 0b11110 == 8
# bclr decrement CTR, branch if CTR non-zero AND condition false
- name: bdnzflr
opcode: bclr
args: [ BI ]
condition: BO & 0b11110 == 0
# bclr decrement CTR, branch if CTR zero
- name: bdzlr
opcode: bclr
condition: BO & 0b11110 == 18 && BI == 0
# bclr decrement CTR, branch if CTR zero AND condition true
- name: bdztlr
opcode: bclr
args: [ BI ]
condition: BO & 0b11110 == 10
# bclr decrement CTR, branch if CTR zero AND condition false
- name: bdzflr
opcode: bclr
args: [ BI ]
condition: BO & 0b11110 == 0