From 2ed6200090c737e4bd655c0d4cd9cacf1a3dfd49 Mon Sep 17 00:00:00 2001 From: zero318 Date: Wed, 29 Jun 2022 00:27:56 -0400 Subject: [PATCH 01/26] Add initial imm attribute support --- src/llir/abi.rs | 81 ++++++++++++++++++++++++++++------------- src/llir/intrinsic.rs | 6 +-- src/llir/lower.rs | 70 ++++++++++++++++++++++------------- src/llir/raise/early.rs | 34 ++++++++++------- 4 files changed, 123 insertions(+), 68 deletions(-) diff --git a/src/llir/abi.rs b/src/llir/abi.rs index db721c5..f2a1316 100644 --- a/src/llir/abi.rs +++ b/src/llir/abi.rs @@ -34,13 +34,14 @@ pub struct InstrAbi { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ArgEncoding { /// `S` or `s` in mapfile. 4-byte or 2-byte integer immediate or register. Displayed as signed. + /// `C` in mapfile. 4-byte integer immediate or register, printed as hex when immediate. /// /// May be decompiled as an enum or const based on its value. /// /// The first argument may have `arg0` if it is two bytes large. This indicates that the argument is /// stored in the arg0 header field of the instruction in EoSD and PCB ECL. (which is mapped to the /// `@arg0` pseudo-argument in raw instruction syntax) - Integer { size: u8, ty_color: Option, arg0: bool }, + Integer { size: u8, ty_color: Option, arg0: bool, immediate: bool, radix: ast::IntRadix }, /// `o` in mapfile. Max of one per instruction. Is decoded to a label. JumpOffset, /// `t` in mapfile. Max of one per instruction, and requires an accompanying `o` arg. @@ -49,10 +50,8 @@ pub enum ArgEncoding { /// /// Only exists in pre-StB STD where instructions have fixed sizes. Padding, - /// `C` in mapfile. 4-byte integer immediate or register, printed as hex when immediate. - Color, /// `f` in mapfile. Single-precision float. - Float, + Float { immediate: bool }, /// `z(bs=)`, `m(bs=;mask=,,)`, or `m(len=;mask=,,)` in mapfile. /// /// See [`StringArgSize`] about the size args. @@ -85,7 +84,7 @@ pub enum StringArgSize { } impl ArgEncoding { - pub fn dword() -> Self { ArgEncoding::Integer { size: 4, ty_color: None, arg0: false } } + pub fn dword() -> Self { ArgEncoding::Integer { size: 4, ty_color: None, arg0: false, immediate: false, radix: ast::IntRadix::Dec } } pub fn static_descr(&self) -> &'static str { match self { @@ -95,8 +94,7 @@ impl ArgEncoding { Self::JumpOffset => "jump offset", Self::JumpTime => "jump time", Self::Padding => "padding", - Self::Color => "hex integer", - Self::Float => "float", + Self::Float { .. } => "float", Self::String { .. } => "string", } } @@ -107,10 +105,10 @@ impl ArgEncoding { impl fmt::Display for Impl<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self.0 { - Enc::Integer { arg0: true, ty_color, size } => write!( + Enc::Integer { arg0: true, ty_color, size, immediate, radix } => write!( f, "{} (in timeline arg0)", - Enc::Integer { arg0: false, ty_color: ty_color.clone(), size: *size }.descr(), + Enc::Integer { radix: *radix, immediate: *immediate, arg0: false, ty_color: ty_color.clone(), size: *size }.descr(), ), Enc::Integer { ty_color: Some(en), size: 4, .. } => write!(f, "{}", en.descr()), Enc::Integer { ty_color: Some(en), size, .. } => write!(f, "{size}-byte {}", en.descr()), @@ -124,6 +122,21 @@ impl ArgEncoding { Impl(self) } + + pub fn contributes_to_param_mask(&self) -> bool { + !matches!(self, Self::Padding) + } + + pub fn is_immediate(&self) -> bool { + matches!(self, + | Self::String { .. } + | Self::JumpOffset + | Self::JumpTime + | Self::Padding + | Self::Integer { immediate: true, .. } + | Self::Float { immediate: true, .. } + ) + } } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -194,11 +207,10 @@ impl ArgEncoding { | ArgEncoding::JumpOffset | ArgEncoding::JumpTime | ArgEncoding::Padding - | ArgEncoding::Color | ArgEncoding::Integer { .. } => ScalarType::Int, - | ArgEncoding::Float + | ArgEncoding::Float { .. } => ScalarType::Float, | ArgEncoding::String { .. } @@ -212,6 +224,8 @@ impl ArgEncoding { fn arg_encoding_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Result { if let Some(encoding) = int_from_attrs(param, emitter)? { Ok(encoding) + } else if let Some(encoding) = float_from_attrs(param, emitter)? { + Ok(encoding) } else if let Some(encoding) = string_from_attrs(param, emitter)? { Ok(encoding) } else if let Some(encoding) = other_from_attrs(param, emitter)? { @@ -225,21 +239,24 @@ fn arg_encoding_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Res } fn int_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Result, ErrorReported> { - let (size, default_ty_color) = match param.format_char.value { + let (size, default_ty_color, radix) = match param.format_char.value { // FIXME: Uu should be unsigned but I'm not sure yet if I want `i(signed)`, `i(unsigned)`, or `i(sign=1)` - 'S' => (4u8, None), - 's' => (2, None), - 'U' => (4, None), - 'u' => (2, None), - 'n' => (4, Some(TypeColor::Enum(auto_enum_names::anm_sprite()))), - 'N' => (4, Some(TypeColor::Enum(auto_enum_names::anm_script()))), - 'E' => (4, Some(TypeColor::Enum(auto_enum_names::ecl_sub()))), + 'S' => (4u8, None, ast::IntRadix::Dec), + 's' => (2, None, ast::IntRadix::Dec), + 'U' => (4, None, ast::IntRadix::Dec), + 'u' => (2, None, ast::IntRadix::Dec), + 'n' => (4, Some(TypeColor::Enum(auto_enum_names::anm_sprite())), ast::IntRadix::Dec), + 'N' => (4, Some(TypeColor::Enum(auto_enum_names::anm_script())), ast::IntRadix::Dec), + 'E' => (4, Some(TypeColor::Enum(auto_enum_names::ecl_sub())), ast::IntRadix::Dec), + 'C' => (4, None, ast::IntRadix::Hex), _ => return Ok(None), // not an integer }; param.clone().deserialize_attributes(emitter, |de| { let user_ty_color = de.accept_value("enum")?.map(|ident| TypeColor::Enum(ident.value)); let arg0 = de.accept_flag("arg0")?; + let imm = de.accept_flag("imm")?; + let is_hex = de.accept_flag("hex")?; if let Some(arg0_flag) = arg0 { if size != 2 { @@ -254,10 +271,27 @@ fn int_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Result Result, ErrorReported> { + match param.format_char.value { + 'f' => param.clone().deserialize_attributes(emitter, |de| { + //let user_ty_color = de.accept_value("enum")?.map(|ident| TypeColor::Enum(ident.value)); + let imm = de.accept_flag("imm")?; + + Ok(Some(ArgEncoding::Float { + //ty_color: user_ty_color.or(default_ty_color), + immediate: imm.is_some(), + })) + }), + _ => Ok(None) + } +} + fn string_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Result, ErrorReported> { let default_mask = match param.format_char.value { 'z' => Some([0,0,0]), @@ -305,10 +339,8 @@ fn string_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Result Result, ErrorReported> { match param.format_char.value { - 'C' => Ok(Some(ArgEncoding::Color)), 'o' => Ok(Some(ArgEncoding::JumpOffset)), 't' => Ok(Some(ArgEncoding::JumpTime)), - 'f' => Ok(Some(ArgEncoding::Float)), '_' => Ok(Some(ArgEncoding::Padding)), _ => Ok(None), } @@ -362,9 +394,6 @@ fn abi_to_signature(abi: &InstrAbi, abi_span: Span, ctx: &mut CompilerContext<'_ return_ty: sp!(value::ExprType::Void), params: abi.encodings.iter().enumerate().flat_map(|(index, enc)| { let Info { ty, default, reg_ok, ty_color } = match *enc { - | ArgEncoding::Color - => Info { ty: ScalarType::Int, default: None, reg_ok: true, ty_color: None }, - | ArgEncoding::Integer { arg0: false, ref ty_color, .. } => Info { ty: ScalarType::Int, default: None, reg_ok: true, ty_color: ty_color.clone() }, @@ -378,7 +407,7 @@ fn abi_to_signature(abi: &InstrAbi, abi_span: Span, ctx: &mut CompilerContext<'_ | ArgEncoding::Padding => Info { ty: ScalarType::Int, default: Some(sp!(0.into())), reg_ok: true, ty_color: None }, - | ArgEncoding::Float + | ArgEncoding::Float { .. } => Info { ty: ScalarType::Float, default: None, reg_ok: true, ty_color: None }, | ArgEncoding::String { .. } @@ -414,7 +443,7 @@ mod tests { #[test] fn test_parse() { - assert_eq!(parse("SSf").unwrap(), InstrAbi::from_encodings(Span::NULL, vec![Enc::dword(), Enc::dword(), Enc::Float]).unwrap()); + assert_eq!(parse("SSf").unwrap(), InstrAbi::from_encodings(Span::NULL, vec![Enc::dword(), Enc::dword(), Enc::Float { immediate: false }]).unwrap()); } #[test] diff --git a/src/llir/intrinsic.rs b/src/llir/intrinsic.rs index 021eb8c..5be362d 100644 --- a/src/llir/intrinsic.rs +++ b/src/llir/intrinsic.rs @@ -295,7 +295,7 @@ impl IntrinsicAbiHelper<'_> { fn find_and_remove_sub_id(&self, arg_encodings: &mut Vec<(usize, &ArgEncoding)>) -> Result { let data = Self::remove_first_where(arg_encodings, |&(_, enc)| { match enc { - ArgEncoding::Integer { size: _, ty_color: Some(TypeColor::Enum(enum_name)), arg0: false } => { + ArgEncoding::Integer { ty_color: Some(TypeColor::Enum(enum_name)), arg0: false, .. } => { enum_name == &auto_enum_names::ecl_sub() }, _ => false, @@ -314,7 +314,7 @@ impl IntrinsicAbiHelper<'_> { }; match (ty_in_ast, encoding) { | (ScalarType::Int, ArgEncoding::Integer { .. }) - | (ScalarType::Float, ArgEncoding::Float) + | (ScalarType::Float, ArgEncoding::Float { .. }) => Ok((index, abi_parts::OutputArgMode::Natural)), | (ScalarType::Float, ArgEncoding::Integer { .. }) @@ -332,7 +332,7 @@ impl IntrinsicAbiHelper<'_> { }; match (ty_in_ast, encoding) { | (ScalarType::Int, ArgEncoding::Integer { .. }) - | (ScalarType::Float, ArgEncoding::Float) + | (ScalarType::Float, ArgEncoding::Float { .. }) => Ok(index), | (_, _) diff --git a/src/llir/lower.rs b/src/llir/lower.rs index a09488f..361a68e 100644 --- a/src/llir/lower.rs +++ b/src/llir/lower.rs @@ -545,16 +545,51 @@ fn encode_args( // The remaining args go into the argument byte blob. let mut args_blob = std::io::Cursor::new(vec![]); + + let mut param_mask: raw::ParamMask = 0; + let mut current_param_mask_bit: raw::ParamMask = 1; // Important: we put the shortest iterator (args_iter) first in the zip list // to ensure that this loop reads an equal number of items from all iters. assert!(args_iter.len() <= arg_encodings_iter.len()); for (arg, enc) in zip!(args_iter, arg_encodings_iter.by_ref()) { + + let arg_bit = match &arg.value { + LowerArg::Raw(raw) if raw.is_reg => current_param_mask_bit, + LowerArg::Local { .. } => current_param_mask_bit, + LowerArg::DiffSwitch { .. } => panic!("should be handled earlier"), + _ => 0, + }; + // Verify this arg even applies to the param mask... + if enc.contributes_to_param_mask() { + if enc.is_immediate() && arg_bit != 0 { + // Warn if a register is used for an immediate arg + emitter.emit(warning!( + message("non-constant expression in immediate argument"), + primary(arg, "non-const expression"), + // FIXME: Find a way to display the resulting value! + // Could eventually be relevant for oversided values too + // note(format!()), + )).ignore(); + } else { + param_mask |= arg_bit; + } + current_param_mask_bit <<= 1; + } else if arg_bit != 0 { + // Conceptually invalid since adding this to the + // param mask would misalign all other mask bits + emitter.emit(warning!( + message("non-constant expression in non-parameter"), + primary(arg, "non-const expression"), + )).ignore(); + // Should be impossible to trigger once padding is + // converted to not be optional arguments? Panic? + } + match *enc { | ArgEncoding::Integer { arg0: true, .. } => unreachable!(), - | ArgEncoding::Color | ArgEncoding::JumpOffset | ArgEncoding::JumpTime | ArgEncoding::Padding @@ -567,7 +602,7 @@ fn encode_args( | ArgEncoding::Integer { size, .. } => panic!("unexpected integer size: {}", size), - | ArgEncoding::Float + | ArgEncoding::Float { .. } => args_blob.write_f32(arg.expect_raw().expect_float()).expect("Cursor failed?!"), | ArgEncoding::String { size: size_spec, mask, furibug } @@ -627,12 +662,19 @@ fn encode_args( args_blob.write_u32(0).expect("Cursor failed?!"); } + if current_param_mask_bit.trailing_zeros() > raw::ParamMask::BITS as _ { + return Err(emitter.emit(error!( + message("too many arguments in instruction!"), + primary(args[raw::ParamMask::BITS as usize], "too many arguments"), + ))); + } + Ok(RawInstr { time: instr.stmt_data.time, opcode: instr.opcode, param_mask: match instr.user_param_mask { Some(user_provided_mask) => user_provided_mask, - None => compute_param_mask(&args, emitter)?, + None => param_mask, }, args_blob: args_blob.into_inner(), extra_arg, @@ -642,26 +684,4 @@ fn encode_args( }) } -fn compute_param_mask(args: &[Sp], emitter: &impl Emitter) -> Result { - if args.len() > raw::ParamMask::BITS as _ { - return Err(emitter.emit(error!( - message("too many arguments in instruction!"), - primary(args[raw::ParamMask::BITS as usize], "too many arguments"), - ))); - } - let mut mask = 0; - for arg in args.iter().rev(){ - let bit = match &arg.value { - LowerArg::Raw(raw) => raw.is_reg as raw::ParamMask, - LowerArg::TimeOf { .. } => 0, - LowerArg::Label { .. } => 0, - LowerArg::Local { .. } => 1, - LowerArg::DiffSwitch { .. } => panic!("should be handled earlier"), - }; - mask *= 2; - mask += bit; - } - Ok(mask) -} - // ============================================================================= diff --git a/src/llir/raise/early.rs b/src/llir/raise/early.rs index 555017b..7035935 100644 --- a/src/llir/raise/early.rs +++ b/src/llir/raise/early.rs @@ -226,8 +226,15 @@ fn decode_args_with_abi( for (arg_index, enc) in siggy.arg_encodings().enumerate() { let ref emitter = add_argument_context(emitter, arg_index); - let param_mask_bit = param_mask % 2 == 1; - param_mask /= 2; + // TODO: Add a way to fallback to @mask for + // "bad" mask bits to allow roundtripping + let can_be_param = if enc.contributes_to_param_mask() { + let value = !enc.is_immediate() && param_mask & 1 == 1; + param_mask >>= 1; + value + } else { + false + }; let value = match *enc { | ArgEncoding::Integer { arg0: true, .. } @@ -238,17 +245,16 @@ fn decode_args_with_abi( ScalarValue::Int(extra_arg as _) }, - | ArgEncoding::Integer { arg0: false, size: 4, ty_color: _ } - | ArgEncoding::Color + | ArgEncoding::Integer { arg0: false, size: 4, .. } | ArgEncoding::JumpOffset | ArgEncoding::JumpTime | ArgEncoding::Padding => { decrease_len(emitter, &mut remaining_len, 4)?; - ScalarValue::Int(args_blob.read_u32().expect("already checked len") as i32) + ScalarValue::Int(args_blob.read_i32().expect("already checked len") as i32) }, - | ArgEncoding::Integer { arg0: false, size: 2, ty_color: _ } + | ArgEncoding::Integer { arg0: false, size: 2, .. } => { decrease_len(emitter, &mut remaining_len, 2)?; ScalarValue::Int(args_blob.read_i16().expect("already checked len") as i32) @@ -257,7 +263,7 @@ fn decode_args_with_abi( | ArgEncoding::Integer { size, .. } => panic!("unexpected integer size: {size}"), - | ArgEncoding::Float + | ArgEncoding::Float { .. } => { decrease_len(emitter, &mut remaining_len, 4)?; ScalarValue::Float(f32::from_bits(args_blob.read_u32().expect("already checked len"))) @@ -290,9 +296,9 @@ fn decode_args_with_abi( }; let is_reg = match reg_style { - RegisterEncodingStyle::ByParamMask => param_mask_bit, + RegisterEncodingStyle::ByParamMask => can_be_param, RegisterEncodingStyle::EosdEcl { does_value_look_like_a_register } => { - does_value_look_like_a_register(&value) + can_be_param && does_value_look_like_a_register(&value) }, }; @@ -516,7 +522,7 @@ impl AtomRaiser<'_, '_> { let pseudo_arg0 = match instr.pseudo_arg0 { None | Some(0) => None, Some(arg0) => { - let enc = ArgEncoding::Integer { size: 2, ty_color: None, arg0: true }; + let enc = ArgEncoding::Integer { size: 2, ty_color: None, arg0: true, immediate: true, radix: ast::IntRadix::Dec }; let expr = self.raise_arg(emitter, &SimpleArg::from(arg0 as i32), &enc, dest_label)?; Some(expr) } @@ -641,6 +647,9 @@ impl AtomRaiser<'_, '_> { ensure!(emitter, !raw.is_reg, "expected an immediate, got a register"); match enc { + | ArgEncoding::Integer { radix, .. } if *radix != ast::IntRadix::Dec + => Ok(ast::Expr::LitInt { value: raw.expect_int(), radix: *radix }), + | ArgEncoding::Padding | ArgEncoding::Integer { ty_color: None, .. } => Ok(ast::Expr::from(raw.expect_int())), @@ -657,10 +666,7 @@ impl AtomRaiser<'_, '_> { )) } - | ArgEncoding::Color - => Ok(ast::Expr::LitInt { value: raw.expect_int(), radix: ast::IntRadix::Hex }), - - | ArgEncoding::Float + | ArgEncoding::Float { .. } => Ok(ast::Expr::from(raw.expect_float())), | ArgEncoding::String { .. } From a8b2ad4f183730d49ecaf82f1008be0cc8db44ba Mon Sep 17 00:00:00 2001 From: zero318 Date: Wed, 29 Jun 2022 23:08:03 -0400 Subject: [PATCH 02/26] Improve unsigned/hex support and update padding --- src/ast/meta.rs | 2 +- src/ast/mod.rs | 14 ++++--- src/context/defs.rs | 22 ++--------- src/core_mapfiles/std.rs | 40 +++++++++---------- src/fmt.rs | 16 ++++---- src/formats/anm/mod.rs | 2 +- src/llir/abi.rs | 59 +++++++++++++++------------- src/llir/intrinsic.rs | 21 ++-------- src/llir/lower.rs | 32 ++++++++++----- src/llir/lower/intrinsic.rs | 3 +- src/llir/raise/early.rs | 63 ++++++++++++++++++------------ src/llir/raise/late.rs | 2 +- src/parse/lalrparser.lalrpop | 2 +- tests/integration/timeline_arg0.rs | 2 +- 14 files changed, 143 insertions(+), 137 deletions(-) diff --git a/src/ast/meta.rs b/src/ast/meta.rs index 47dd20d..0e8ffee 100644 --- a/src/ast/meta.rs +++ b/src/ast/meta.rs @@ -574,7 +574,7 @@ impl ToMeta for f32 { fn to_meta(&self) -> Meta { Meta::Scalar(sp!((*self).into())) } } impl ToMeta for bool { - fn to_meta(&self) -> Meta { Meta::Scalar(sp!(ast::Expr::LitInt { value: *self as i32, radix: ast::IntRadix::Bool })) } + fn to_meta(&self) -> Meta { Meta::Scalar(sp!(ast::Expr::LitInt { value: *self as i32, format: ast::IntFormat { unsigned: true, radix: ast::IntRadix::Bool } })) } } impl ToMeta for String { fn to_meta(&self) -> Meta { Meta::Scalar(sp!(self.to_owned().into())) } diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 9864caa..cd4f0b9 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -462,7 +462,7 @@ pub enum Expr { value: raw::LangInt, /// A hint to the formatter on how it should write the integer. /// (may not necessarily represent the original radix of a parsed token) - radix: IntRadix, + format: IntFormat, }, LitFloat { value: raw::LangFloat }, LitString(LitString), @@ -476,14 +476,18 @@ pub enum Expr { }, } +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct IntFormat { + pub unsigned: bool, + pub radix: IntRadix, +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum IntRadix { /// Display as decimal. Dec, /// Display as hexadecimal, with an `0x` prefix. Hex, - /// Display as potentially negative hexadecimal, with an `0x` prefix. - SignedHex, /// Display as binary, with an `0b` prefix. Bin, /// Use `true` and `false` if the value is `1` or `0`. Otherwise, fall back to decimal. @@ -848,7 +852,7 @@ string_enum! { } impl From for Expr { - fn from(value: raw::LangInt) -> Expr { Expr::LitInt { value, radix: IntRadix::Dec } } + fn from(value: raw::LangInt) -> Expr { Expr::LitInt { value, format: IntFormat { unsigned: false, radix: IntRadix::Dec } } } } impl From for Expr { fn from(value: raw::LangFloat) -> Expr { Expr::LitFloat { value } } @@ -1266,7 +1270,7 @@ macro_rules! generate_visitor_stuff { Expr::XcrementOp { op: _, order: _, var } => { v.visit_var(var); }, - Expr::LitInt { value: _, radix: _ } => {}, + Expr::LitInt { value: _, format: _ } => {}, Expr::LitFloat { value: _ } => {}, Expr::LitString(_s) => {}, Expr::LabelProperty { .. } => {}, diff --git a/src/context/defs.rs b/src/context/defs.rs index e4a1bed..da9af0e 100644 --- a/src/context/defs.rs +++ b/src/context/defs.rs @@ -1114,34 +1114,18 @@ impl Signature { signature_from_func_ast(ty_keyword, params) } - pub(crate) fn validate(&self, ctx: &CompilerContext) -> Result<(), ErrorReported> { - self._check_non_optional_after_optional(ctx) - } - - fn _check_non_optional_after_optional(&self, ctx: &CompilerContext) -> Result<(), ErrorReported> { - let mut first_optional = None; - for param in self.params.iter() { - if param.default.is_some() { - first_optional = Some(param); - } else if let Some(optional) = first_optional { - return Err(ctx.emitter.emit(error!( - message("invalid function signature"), - secondary(optional.useful_span, "optional parameter"), - primary(param.useful_span, "non-optional parameter after optional"), - ))); - } - } + pub(crate) fn validate(&self, _ctx: &CompilerContext) -> Result<(), ErrorReported> { Ok(()) } /// Minimum number of arguments accepted. pub fn min_args(&self) -> usize { - self.params.iter().take_while(|param| param.default.is_none()).count() + self.params.iter().fold(0, |count, param| count + param.default.is_none() as usize) } /// Maximum number of arguments accepted. pub fn max_args(&self) -> usize { - self.params.len() + self.min_args() } /// Matches arguments at a call site to their corresponding parameters. diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index 1036711..3721a02 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -22,9 +22,9 @@ static STD_06: &CoreSignatures = &CoreSignatures { (Th06, 0, Some(("fff", None))), (Th06, 1, Some(("Cff", None))), (Th06, 2, Some(("fff", None))), - (Th06, 3, Some(("S__", None))), - (Th06, 4, Some(("S__", None))), - (Th06, 5, Some(("___", None))), + (Th06, 3, Some(("S________", None))), + (Th06, 4, Some(("S________", None))), + (Th06, 5, Some(("____________", None))), ], var: &[], }; @@ -34,40 +34,40 @@ static STD_07_09: &CoreSignatures = &CoreSignatures { ins: &[ (Th07, 0, Some(("fff", None))), (Th07, 1, Some(("Cff", None))), - (Th07, 2, Some(("S__", None))), - (Th07, 3, Some(("___", None))), - (Th07, 4, Some(("ot_", Some(IKind::Jmp)))), + (Th07, 2, Some(("S________", None))), + (Th07, 3, Some(("____________", None))), + (Th07, 4, Some(("ot____", Some(IKind::Jmp)))), (Th07, 5, Some(("fff", None))), - (Th07, 6, Some(("SS_", None))), + (Th07, 6, Some(("SS____", None))), (Th07, 7, Some(("fff", None))), - (Th07, 8, Some(("SS_", None))), + (Th07, 8, Some(("SS____", None))), (Th07, 9, Some(("fff", None))), - (Th07, 10, Some(("SS_", None))), - (Th07, 11, Some(("f__", None))), - (Th07, 12, Some(("SS_", None))), - (Th07, 13, Some(("C__", None))), + (Th07, 10, Some(("SS____", None))), + (Th07, 11, Some(("f________", None))), + (Th07, 12, Some(("SS____", None))), + (Th07, 13, Some(("C________", None))), (Th07, 14, Some(("fff", None))), (Th07, 15, Some(("fff", None))), (Th07, 16, Some(("fff", None))), (Th07, 17, Some(("fff", None))), - (Th07, 18, Some(("S__", None))), + (Th07, 18, Some(("S________", None))), (Th07, 19, Some(("fff", None))), (Th07, 20, Some(("fff", None))), (Th07, 21, Some(("fff", None))), (Th07, 22, Some(("fff", None))), - (Th07, 23, Some(("S__", None))), + (Th07, 23, Some(("S________", None))), (Th07, 24, Some(("fff", None))), (Th07, 25, Some(("fff", None))), (Th07, 26, Some(("fff", None))), (Th07, 27, Some(("fff", None))), - (Th07, 28, Some(("S__", None))), - (Th07, 29, Some(("S__", None))), // anm script - (Th07, 30, Some(("S__", None))), // anm script - (Th07, 31, Some(("S__", Some(IKind::InterruptLabel)))), + (Th07, 28, Some(("S________", None))), + (Th07, 29, Some(("S________", None))), // anm script + (Th07, 30, Some(("S________", None))), // anm script + (Th07, 31, Some(("S________", Some(IKind::InterruptLabel)))), (Th08, 32, Some(("fff", None))), - (Th08, 33, Some(("S__", None))), - (Th08, 34, Some(("S__", None))), // anm script + (Th08, 33, Some(("S________", None))), + (Th08, 34, Some(("S________", None))), // anm script ], var: &[], }; diff --git a/src/fmt.rs b/src/fmt.rs index 59f38d2..5296457 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -904,13 +904,15 @@ impl Format for ast::Expr { ast::Expr::XcrementOp { order: ast::XcrementOpOrder::Pre, op, var } => out.fmt((op, var)), ast::Expr::XcrementOp { order: ast::XcrementOpOrder::Post, op, var } => out.fmt((var, op)), ast::Expr::EnumConst { enum_name, ident } => out.fmt((enum_name, ".", ident)), - ast::Expr::LitInt { value: 0, radix: ast::IntRadix::Bool } => out.fmt("false"), - ast::Expr::LitInt { value: 1, radix: ast::IntRadix::Bool } => out.fmt("true"), - ast::Expr::LitInt { value, radix: ast::IntRadix::Bool } => out.fmt(value), - ast::Expr::LitInt { value, radix: ast::IntRadix::Dec } => out.fmt(value), - ast::Expr::LitInt { value, radix: ast::IntRadix::Hex } => out.fmt(format_args!("{:#x}", value)), - ast::Expr::LitInt { value, radix: ast::IntRadix::SignedHex } => out.fmt(format_args!("{:#x}", SignedRadix(*value))), - ast::Expr::LitInt { value, radix: ast::IntRadix::Bin } => out.fmt(format_args!("{:#b}", value)), + ast::Expr::LitInt { value: 0, format: ast::IntFormat { unsigned: _, radix: ast::IntRadix::Bool } } => out.fmt("false"), + ast::Expr::LitInt { value: 1, format: ast::IntFormat { unsigned: _, radix: ast::IntRadix::Bool } } => out.fmt("true"), + ast::Expr::LitInt { value, format: ast::IntFormat { unsigned: false, radix: ast::IntRadix::Bool } } => out.fmt(value), + ast::Expr::LitInt { value, format: ast::IntFormat { unsigned: true, radix: ast::IntRadix::Bool } } => out.fmt(format_args!("{}", *value as u32)), + ast::Expr::LitInt { value, format: ast::IntFormat { unsigned: false, radix: ast::IntRadix::Dec } } => out.fmt(value), + ast::Expr::LitInt { value, format: ast::IntFormat { unsigned: true, radix: ast::IntRadix::Dec } } => out.fmt(format_args!("{}", *value as u32)), + ast::Expr::LitInt { value, format: ast::IntFormat { unsigned: true, radix: ast::IntRadix::Hex } } => out.fmt(format_args!("{:#x}", value)), + ast::Expr::LitInt { value, format: ast::IntFormat { unsigned: false, radix: ast::IntRadix::Hex } } => out.fmt(format_args!("{:#x}", SignedRadix(*value))), + ast::Expr::LitInt { value, format: ast::IntFormat { unsigned: _, radix: ast::IntRadix::Bin } } => out.fmt(format_args!("{:#b}", value)), ast::Expr::LitFloat { value } => out.fmt(value), ast::Expr::LitString(x) => out.fmt(x), ast::Expr::LabelProperty { label, keyword } => out.fmt((keyword, "(", label, ")")), diff --git a/src/formats/anm/mod.rs b/src/formats/anm/mod.rs index 609d532..0a3d3a4 100644 --- a/src/formats/anm/mod.rs +++ b/src/formats/anm/mod.rs @@ -701,7 +701,7 @@ fn format_to_meta(format_num: u32) -> Meta { } fn colorkey_to_meta(colorkey: u32) -> impl ToMeta { - ast::Expr::LitInt { value: colorkey as i32, radix: ast::IntRadix::Hex } + ast::Expr::LitInt { value: colorkey as i32, format: ast::IntFormat { unsigned: true, radix: ast::IntRadix::Hex } } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] diff --git a/src/llir/abi.rs b/src/llir/abi.rs index f2a1316..61470d2 100644 --- a/src/llir/abi.rs +++ b/src/llir/abi.rs @@ -33,7 +33,8 @@ pub struct InstrAbi { /// [`ScalarType`] tends to be more relevant for variables. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum ArgEncoding { - /// `S` or `s` in mapfile. 4-byte or 2-byte integer immediate or register. Displayed as signed. + /// `S`, `s`, or `c` in mapfile. Integer immediate or register. Displayed as signed. + /// `U`, `u`, or `b` in mapfile. Integer immediate or register. Displayed as unsigned. /// `C` in mapfile. 4-byte integer immediate or register, printed as hex when immediate. /// /// May be decompiled as an enum or const based on its value. @@ -41,14 +42,12 @@ pub enum ArgEncoding { /// The first argument may have `arg0` if it is two bytes large. This indicates that the argument is /// stored in the arg0 header field of the instruction in EoSD and PCB ECL. (which is mapped to the /// `@arg0` pseudo-argument in raw instruction syntax) - Integer { size: u8, ty_color: Option, arg0: bool, immediate: bool, radix: ast::IntRadix }, + Integer { size: u8, ty_color: Option, arg0: bool, immediate: bool, format: ast::IntFormat }, /// `o` in mapfile. Max of one per instruction. Is decoded to a label. JumpOffset, /// `t` in mapfile. Max of one per instruction, and requires an accompanying `o` arg. JumpTime, - /// `_` in mapfile. Unused 4-byte space after script arguments, optionally displayed as integer in text. - /// - /// Only exists in pre-StB STD where instructions have fixed sizes. + /// `_` in mapfile. Unused 1-byte space. Padding, /// `f` in mapfile. Single-precision float. Float { immediate: bool }, @@ -84,10 +83,11 @@ pub enum StringArgSize { } impl ArgEncoding { - pub fn dword() -> Self { ArgEncoding::Integer { size: 4, ty_color: None, arg0: false, immediate: false, radix: ast::IntRadix::Dec } } + pub fn dword() -> Self { ArgEncoding::Integer { size: 4, ty_color: None, arg0: false, immediate: false, format: ast::IntFormat { unsigned: false, radix: ast::IntRadix::Dec } } } pub fn static_descr(&self) -> &'static str { match self { + Self::Integer { size: 1, .. } => "byte-sized integer", Self::Integer { size: 2, .. } => "word-sized integer", Self::Integer { size: 4, .. } => "dword integer", Self::Integer { size: _, .. } => "integer", @@ -105,13 +105,14 @@ impl ArgEncoding { impl fmt::Display for Impl<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self.0 { - Enc::Integer { arg0: true, ty_color, size, immediate, radix } => write!( + Enc::Integer { arg0: true, ty_color, size, immediate, format } => write!( f, "{} (in timeline arg0)", - Enc::Integer { radix: *radix, immediate: *immediate, arg0: false, ty_color: ty_color.clone(), size: *size }.descr(), + Enc::Integer { format: *format, immediate: *immediate, arg0: false, ty_color: ty_color.clone(), size: *size }.descr(), ), Enc::Integer { ty_color: Some(en), size: 4, .. } => write!(f, "{}", en.descr()), Enc::Integer { ty_color: Some(en), size, .. } => write!(f, "{size}-byte {}", en.descr()), + Enc::Integer { ty_color: None, size: 1, .. } => write!(f, "byte-sized integer"), Enc::Integer { ty_color: None, size: 2, .. } => write!(f, "word-sized integer"), Enc::Integer { ty_color: None, size: 4, .. } => write!(f, "dword integer"), Enc::Integer { ty_color: None, size, .. } => write!(f, "{size}-byte integer"), @@ -239,16 +240,18 @@ fn arg_encoding_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Res } fn int_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Result, ErrorReported> { - let (size, default_ty_color, radix) = match param.format_char.value { + let (size, unsigned, mut hex_radix, default_ty_color) = match param.format_char.value { // FIXME: Uu should be unsigned but I'm not sure yet if I want `i(signed)`, `i(unsigned)`, or `i(sign=1)` - 'S' => (4u8, None, ast::IntRadix::Dec), - 's' => (2, None, ast::IntRadix::Dec), - 'U' => (4, None, ast::IntRadix::Dec), - 'u' => (2, None, ast::IntRadix::Dec), - 'n' => (4, Some(TypeColor::Enum(auto_enum_names::anm_sprite())), ast::IntRadix::Dec), - 'N' => (4, Some(TypeColor::Enum(auto_enum_names::anm_script())), ast::IntRadix::Dec), - 'E' => (4, Some(TypeColor::Enum(auto_enum_names::ecl_sub())), ast::IntRadix::Dec), - 'C' => (4, None, ast::IntRadix::Hex), + 'S' => (4u8, false, false, None), + 's' => (2u8, false, false, None), + 'c' => (1u8, false, false, None), + 'U' => (4u8, true, false, None), + 'u' => (2u8, true, false, None), + 'b' => (1u8, true, false, None), + 'n' => (4u8, false, false, Some(TypeColor::Enum(auto_enum_names::anm_sprite()))), + 'N' => (4u8, false, false, Some(TypeColor::Enum(auto_enum_names::anm_script()))), + 'E' => (4u8, false, false, Some(TypeColor::Enum(auto_enum_names::ecl_sub()))), + 'C' => (4u8, true, true, None), _ => return Ok(None), // not an integer }; @@ -259,20 +262,27 @@ fn int_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Result= 2 { return Err(emitter.as_sized().emit(error!( - message("timeline arg0 must be word-sized ('s' or 'u')"), + message("timeline arg0 must be word-sized or less ('s', 'u', 'c', or 'b')"), primary(arg0_flag, ""), ))); } } + + if is_hex.is_some() { + hex_radix = true; + } Ok(Some(ArgEncoding::Integer { size, ty_color: user_ty_color.or(default_ty_color), arg0: arg0.is_some(), immediate: imm.is_some(), - radix: if is_hex.is_none() { radix } else { ast::IntRadix::Hex }, + format: match hex_radix { + false => ast::IntFormat { unsigned: unsigned, radix: ast::IntRadix::Dec }, + true => ast::IntFormat { unsigned: unsigned, radix: ast::IntRadix::Hex }, + }, })) }) } @@ -364,19 +374,12 @@ fn validate(abi_span: Span, encodings: &[ArgEncoding]) -> Result<(), Diagnostic> } if encodings.iter().skip(1).any(|c| matches!(c, Enc::Integer { arg0: true, .. })) { - return err(format!("'T()' arguments may only appear at the beginning of a signature")); + return err(format!("'(arg0)' arguments may only appear at the beginning of a signature")); } if encodings.iter().rev().skip(1).any(|c| matches!(c, Enc::String { size: StringArgSize::Block { .. }, .. })) { return err(format!("'z' or 'm' arguments with 'bs=' can only appear at the very end")); } - - let trailing_pad_count = encodings.iter().rev().take_while(|c| matches!(c, Enc::Padding)).count(); - let total_pad_count = encodings.iter().filter(|c| matches!(c, Enc::Padding)).count(); - if total_pad_count != trailing_pad_count { - // this restriction is required because Padding produces signatures with optional args. - return err(format!("non-'_' arguments cannot come after '_' arguments")); - } Ok(()) } diff --git a/src/llir/intrinsic.rs b/src/llir/intrinsic.rs index 5be362d..52aac2a 100644 --- a/src/llir/intrinsic.rs +++ b/src/llir/intrinsic.rs @@ -188,8 +188,6 @@ impl IntrinsicInstrKind { #[derive(Debug)] pub struct IntrinsicInstrAbiParts { pub num_instr_args: usize, - /// Number of padding args at the end - pub padding: abi_parts::PaddingInfo, /// Indices of args that should use the same logic as arguments in `ins_` instruction-call syntax. pub plain_args: Vec, /// Indices of args that are known registers. These show up in intrinsics. @@ -254,18 +252,8 @@ impl IntrinsicAbiHelper<'_> { } } - fn find_and_remove_padding(&self, arg_encodings: &mut Vec<(usize, &ArgEncoding)>) -> Result { - let mut count = 0; - let mut first_index = arg_encodings.len(); - while let Some(&(index, ArgEncoding::Padding)) = arg_encodings.last() { - // assumption that this func always runs first (nothing is deleted before us) - assert_eq!(index, arg_encodings.len() - 1); - - arg_encodings.pop(); - count += 1; - first_index = index; - } - Ok(abi_parts::PaddingInfo { count, index: first_index }) + fn find_and_remove_padding(&self, arg_encodings: &mut Vec<(usize, &ArgEncoding)>) { + arg_encodings.retain(|(_, enc)| !matches!(*enc, ArgEncoding::Padding)); } fn find_and_remove_jump(&self, arg_encodings: &mut Vec<(usize, &ArgEncoding)>) -> Result<(usize, abi_parts::JumpArgOrder), Diagnostic> { @@ -347,13 +335,12 @@ impl IntrinsicInstrAbiParts { use IntrinsicInstrKind as I; let mut encodings = abi.arg_encodings().enumerate().collect::>(); - let num_instr_args = encodings.len(); let helper = IntrinsicAbiHelper { intrinsic, abi_loc }; + helper.find_and_remove_padding(&mut encodings); - let padding = helper.find_and_remove_padding(&mut encodings)?; let mut out = IntrinsicInstrAbiParts { - num_instr_args, padding, + num_instr_args: encodings.len(), plain_args: vec![], outputs: vec![], jump: None, sub_id: None, }; diff --git a/src/llir/lower.rs b/src/llir/lower.rs index 361a68e..4401061 100644 --- a/src/llir/lower.rs +++ b/src/llir/lower.rs @@ -545,14 +545,19 @@ fn encode_args( // The remaining args go into the argument byte blob. let mut args_blob = std::io::Cursor::new(vec![]); - + let mut param_mask: raw::ParamMask = 0; let mut current_param_mask_bit: raw::ParamMask = 1; // Important: we put the shortest iterator (args_iter) first in the zip list // to ensure that this loop reads an equal number of items from all iters. assert!(args_iter.len() <= arg_encodings_iter.len()); - for (arg, enc) in zip!(args_iter, arg_encodings_iter.by_ref()) { + for enc in arg_encodings_iter.by_ref() { + if matches!(enc, ArgEncoding::Padding) { + args_blob.write_u8(0).expect("Cursor failed?!"); + continue; + } + let arg = args_iter.next().expect("function arity already checked"); let arg_bit = match &arg.value { LowerArg::Raw(raw) if raw.is_reg => current_param_mask_bit, @@ -588,17 +593,29 @@ fn encode_args( match *enc { | ArgEncoding::Integer { arg0: true, .. } + | ArgEncoding::Padding => unreachable!(), | ArgEncoding::JumpOffset | ArgEncoding::JumpTime - | ArgEncoding::Padding - | ArgEncoding::Integer { size: 4, .. } + | ArgEncoding::Integer { size: 4, format: ast::IntFormat { unsigned: false, radix: _ }, .. } => args_blob.write_i32(arg.expect_raw().expect_int()).expect("Cursor failed?!"), - | ArgEncoding::Integer { size: 2, .. } + | ArgEncoding::Integer { size: 2, format: ast::IntFormat { unsigned: false, radix: _ }, .. } => args_blob.write_i16(arg.expect_raw().expect_int() as _).expect("Cursor failed?!"), + | ArgEncoding::Integer { size: 1, format: ast::IntFormat { unsigned: false, radix: _ }, .. } + => args_blob.write_i8(arg.expect_raw().expect_int() as _).expect("Cursor failed?!"), + + | ArgEncoding::Integer { size: 4, format: ast::IntFormat { unsigned: true, radix: _ }, .. } + => args_blob.write_u32(arg.expect_raw().expect_int() as _).expect("Cursor failed?!"), + + | ArgEncoding::Integer { size: 2, format: ast::IntFormat { unsigned: true, radix: _ }, .. } + => args_blob.write_u16(arg.expect_raw().expect_int() as _).expect("Cursor failed?!"), + + | ArgEncoding::Integer { size: 1, format: ast::IntFormat { unsigned: true, radix: _ }, .. } + => args_blob.write_u8(arg.expect_raw().expect_int() as _).expect("Cursor failed?!"), + | ArgEncoding::Integer { size, .. } => panic!("unexpected integer size: {}", size), @@ -657,11 +674,6 @@ fn encode_args( } } - for enc in arg_encodings_iter { - assert_eq!(enc, &ArgEncoding::Padding); - args_blob.write_u32(0).expect("Cursor failed?!"); - } - if current_param_mask_bit.trailing_zeros() > raw::ParamMask::BITS as _ { return Err(emitter.emit(error!( message("too many arguments in instruction!"), diff --git a/src/llir/lower/intrinsic.rs b/src/llir/lower/intrinsic.rs index 744b47b..0f9406c 100644 --- a/src/llir/lower/intrinsic.rs +++ b/src/llir/lower/intrinsic.rs @@ -74,7 +74,7 @@ impl IntrinsicBuilder<'_> { ) -> Result>, ErrorReported> { // full pattern match to fail when new fields are added let &IntrinsicInstrAbiParts { - num_instr_args, padding: ref padding_info, plain_args: ref plain_args_info, + num_instr_args, plain_args: ref plain_args_info, outputs: ref outputs_info, jump: ref jump_info, sub_id: sub_id_info, } = abi_parts; // check that the caller's 'build' closure put all of the right things for this intrinsic @@ -88,7 +88,6 @@ impl IntrinsicBuilder<'_> { let mut out_args = vec![None; num_instr_args]; // padding gets added later during args -> bytes conversion so we don't need to fill it - out_args.truncate(padding_info.index); // fill in all of the options if let (Some(goto_ast), &Some(jump_info)) = (self.jump, jump_info) { diff --git a/src/llir/raise/early.rs b/src/llir/raise/early.rs index 7035935..cf0b9e9 100644 --- a/src/llir/raise/early.rs +++ b/src/llir/raise/early.rs @@ -245,21 +245,45 @@ fn decode_args_with_abi( ScalarValue::Int(extra_arg as _) }, - | ArgEncoding::Integer { arg0: false, size: 4, .. } | ArgEncoding::JumpOffset | ArgEncoding::JumpTime - | ArgEncoding::Padding + | ArgEncoding::Integer { arg0: false, size: 4, format: ast::IntFormat { unsigned: false, radix: _ }, .. } => { decrease_len(emitter, &mut remaining_len, 4)?; ScalarValue::Int(args_blob.read_i32().expect("already checked len") as i32) }, - | ArgEncoding::Integer { arg0: false, size: 2, .. } + | ArgEncoding::Integer { arg0: false, size: 2, format: ast::IntFormat { unsigned: false, radix: _ }, .. } => { decrease_len(emitter, &mut remaining_len, 2)?; ScalarValue::Int(args_blob.read_i16().expect("already checked len") as i32) }, + | ArgEncoding::Integer { arg0: false, size: 1, format: ast::IntFormat { unsigned: false, radix: _ }, .. } + => { + decrease_len(emitter, &mut remaining_len, 1)?; + ScalarValue::Int(args_blob.read_i8().expect("already checked len") as i32) + }, + + | ArgEncoding::Integer { arg0: false, size: 4, format: ast::IntFormat { unsigned: true, radix: _ }, .. } + => { + decrease_len(emitter, &mut remaining_len, 4)?; + ScalarValue::Int(args_blob.read_u32().expect("already checked len") as i32) + }, + + | ArgEncoding::Integer { arg0: false, size: 2, format: ast::IntFormat { unsigned: true, radix: _ }, .. } + => { + decrease_len(emitter, &mut remaining_len, 2)?; + ScalarValue::Int(args_blob.read_u16().expect("already checked len") as i32) + }, + + | ArgEncoding::Padding + | ArgEncoding::Integer { arg0: false, size: 1, format: ast::IntFormat { unsigned: true, radix: _ }, .. } + => { + decrease_len(emitter, &mut remaining_len, 1)?; + ScalarValue::Int(args_blob.read_u8().expect("already checked len") as i32) + }, + | ArgEncoding::Integer { size, .. } => panic!("unexpected integer size: {size}"), @@ -522,21 +546,17 @@ impl AtomRaiser<'_, '_> { let pseudo_arg0 = match instr.pseudo_arg0 { None | Some(0) => None, Some(arg0) => { - let enc = ArgEncoding::Integer { size: 2, ty_color: None, arg0: true, immediate: true, radix: ast::IntRadix::Dec }; + let enc = ArgEncoding::Integer { size: 2, ty_color: None, arg0: true, immediate: true, format: ast::IntFormat { unsigned: false, radix: ast::IntRadix::Dec } }; let expr = self.raise_arg(emitter, &SimpleArg::from(arg0 as i32), &enc, dest_label)?; Some(expr) } }; - // drop early STD padding args from the end as long as they're zero. + // drop padding args // // IMPORTANT: this is looking at the original arg list because the new lengths may differ due to arg0. - for (enc, arg) in abi.arg_encodings().zip(args).rev() { - match enc { - ArgEncoding::Padding if arg.is_immediate_zero() => raised_args.pop(), - _ => break, - }; - } + let mut arg_iter = abi.arg_encodings(); + raised_args.retain(|_| !matches!(arg_iter.next().unwrap(), ArgEncoding::Padding)); Ok(RaisedIntrinsicParts { opcode: Some(instr.opcode), @@ -559,15 +579,10 @@ impl AtomRaiser<'_, '_> { let encodings = abi.arg_encodings().collect::>(); let IntrinsicInstrAbiParts { - num_instr_args: _, padding: ref padding_info, outputs: ref outputs_info, + num_instr_args: _, outputs: ref outputs_info, jump: ref jump_info, plain_args: ref plain_args_info, sub_id: ref sub_id_info, } = abi_parts; - let padding_range = padding_info.index..padding_info.index + padding_info.count; - if !args[padding_range].iter().all(|arg| arg.is_immediate_zero()) { - return Err(CannotRaiseIntrinsic); // data in padding - } - let mut jump = None; if let &Some((index, order)) = jump_info { let (offset_arg, time_arg) = match order { @@ -647,14 +662,13 @@ impl AtomRaiser<'_, '_> { ensure!(emitter, !raw.is_reg, "expected an immediate, got a register"); match enc { - | ArgEncoding::Integer { radix, .. } if *radix != ast::IntRadix::Dec - => Ok(ast::Expr::LitInt { value: raw.expect_int(), radix: *radix }), + | ArgEncoding::Integer { ty_color: None, format, .. } + => Ok(ast::Expr::LitInt { value: raw.expect_int(), format: *format }), | ArgEncoding::Padding - | ArgEncoding::Integer { ty_color: None, .. } => Ok(ast::Expr::from(raw.expect_int())), - | ArgEncoding::Integer { ty_color: Some(ty_color), .. } + | ArgEncoding::Integer { ty_color: Some(ty_color), format, .. } => { let lookup_table = match ty_color { TypeColor::Enum(ident) => &self.const_names.enums[ident], @@ -663,6 +677,7 @@ impl AtomRaiser<'_, '_> { &lookup_table, raw.expect_int(), ty_color, + format, )) } @@ -687,7 +702,7 @@ impl AtomRaiser<'_, '_> { | Err(IllegalOffset) => { emitter.emit(warning!("invalid offset in a jump instruction")).ignore(); - Ok(ast::Expr::LitInt { value: raw.expect_int(), radix: ast::IntRadix::SignedHex }) + Ok(ast::Expr::LitInt { value: raw.expect_int(), format: ast::IntFormat { unsigned: false, radix: ast::IntRadix::Hex } }) }, }, } @@ -735,7 +750,7 @@ impl AtomRaiser<'_, '_> { } } -fn raise_to_possibly_named_constant(names: &IdMap>, id: i32, ty_color: &TypeColor) -> ast::Expr { +fn raise_to_possibly_named_constant(names: &IdMap>, id: i32, ty_color: &TypeColor, format: &ast::IntFormat) -> ast::Expr { match names.get(&id) { Some(ident) => { match ty_color { @@ -747,7 +762,7 @@ fn raise_to_possibly_named_constant(names: &IdMap>, id: i32, ty_c }, } }, - None => id.into(), + None => ast::Expr::LitInt { value: id, format: *format }, } } diff --git a/src/llir/raise/late.rs b/src/llir/raise/late.rs index ec6fa38..bee5ae5 100644 --- a/src/llir/raise/late.rs +++ b/src/llir/raise/late.rs @@ -101,7 +101,7 @@ impl SingleSubRaiser<'_, '_> { pseudos.push(sp!(ast::PseudoArg { at_sign: sp!(()), eq_sign: sp!(()), kind: sp!(token![mask]), - value: sp!(ast::Expr::LitInt { value: pseudo_mask as i32, radix: ast::IntRadix::Bin }), + value: sp!(ast::Expr::LitInt { value: pseudo_mask as i32, format: ast::IntFormat { unsigned: true, radix: ast::IntRadix::Bin } }), })); } diff --git a/src/parse/lalrparser.lalrpop b/src/parse/lalrparser.lalrpop index cc4e53f..f4a2a95 100644 --- a/src/parse/lalrparser.lalrpop +++ b/src/parse/lalrparser.lalrpop @@ -611,7 +611,7 @@ ExprTerm: ast::Expr = { > > => ast::Expr::XcrementOp { var, op, order: ast::XcrementOpOrder::Post }, - => ast::Expr::LitInt { value, radix: ast::IntRadix::Dec }, + => ast::Expr::LitInt { value, format: ast::IntFormat { unsigned: false, radix: ast::IntRadix::Dec } }, => ast::Expr::LitFloat { value }, diff --git a/tests/integration/timeline_arg0.rs b/tests/integration/timeline_arg0.rs index d98bccf..051b72f 100644 --- a/tests/integration/timeline_arg0.rs +++ b/tests/integration/timeline_arg0.rs @@ -169,7 +169,7 @@ source_test!( ECL_TIMELINE_06, unused_arg0_padding_edge_case, mapfile: r#"!eclmap !timeline_ins_signatures -200 s(arg0;enum="MsgScript")S__ +200 s(arg0;enum="MsgScript")S________ "#, // this is an edge case that arose in decompilation where the presence of a timeline // arg could make the code that trims padding look at the wrong values From e66c92d0025c062afae01728f5cb997def42d5a3 Mon Sep 17 00:00:00 2001 From: zero318 Date: Thu, 30 Jun 2022 01:15:15 -0400 Subject: [PATCH 03/26] Several suggested changes --- src/ast/mod.rs | 4 ++-- src/llir/abi.rs | 25 ++++++++++++++++--------- src/llir/lower.rs | 2 +- src/llir/raise/early.rs | 12 +++++++----- 4 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index cd4f0b9..b159233 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -476,13 +476,13 @@ pub enum Expr { }, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct IntFormat { pub unsigned: bool, pub radix: IntRadix, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum IntRadix { /// Display as decimal. Dec, diff --git a/src/llir/abi.rs b/src/llir/abi.rs index 61470d2..127685d 100644 --- a/src/llir/abi.rs +++ b/src/llir/abi.rs @@ -31,7 +31,7 @@ pub struct InstrAbi { /// /// By this notion, [`ArgEncoding`] tends to be more relevant for immediate/literal arguments, while /// [`ScalarType`] tends to be more relevant for variables. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum ArgEncoding { /// `S`, `s`, or `c` in mapfile. Integer immediate or register. Displayed as signed. /// `U`, `u`, or `b` in mapfile. Integer immediate or register. Displayed as unsigned. @@ -66,7 +66,7 @@ pub enum ArgEncoding { }, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum StringArgSize { /// A string arg that uses `len=`. /// @@ -128,15 +128,20 @@ impl ArgEncoding { !matches!(self, Self::Padding) } - pub fn is_immediate(&self) -> bool { - matches!(self, + pub fn is_always_immediate(&self) -> bool { + match self { | Self::String { .. } | Self::JumpOffset | Self::JumpTime | Self::Padding | Self::Integer { immediate: true, .. } | Self::Float { immediate: true, .. } - ) + => true, + + | Self::Integer { immediate: false, .. } + | Self::Float { immediate: false, .. } + => false, + } } } @@ -274,15 +279,17 @@ fn int_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Result ast::IntRadix::Dec, + true => ast::IntRadix::Hex, + }; + Ok(Some(ArgEncoding::Integer { size, ty_color: user_ty_color.or(default_ty_color), arg0: arg0.is_some(), immediate: imm.is_some(), - format: match hex_radix { - false => ast::IntFormat { unsigned: unsigned, radix: ast::IntRadix::Dec }, - true => ast::IntFormat { unsigned: unsigned, radix: ast::IntRadix::Hex }, - }, + format: ast::IntFormat { unsigned, radix }, })) }) } diff --git a/src/llir/lower.rs b/src/llir/lower.rs index 4401061..ad85f7c 100644 --- a/src/llir/lower.rs +++ b/src/llir/lower.rs @@ -567,7 +567,7 @@ fn encode_args( }; // Verify this arg even applies to the param mask... if enc.contributes_to_param_mask() { - if enc.is_immediate() && arg_bit != 0 { + if enc.is_always_immediate() && arg_bit != 0 { // Warn if a register is used for an immediate arg emitter.emit(warning!( message("non-constant expression in immediate argument"), diff --git a/src/llir/raise/early.rs b/src/llir/raise/early.rs index cf0b9e9..fecf58b 100644 --- a/src/llir/raise/early.rs +++ b/src/llir/raise/early.rs @@ -229,7 +229,7 @@ fn decode_args_with_abi( // TODO: Add a way to fallback to @mask for // "bad" mask bits to allow roundtripping let can_be_param = if enc.contributes_to_param_mask() { - let value = !enc.is_immediate() && param_mask & 1 == 1; + let value = !enc.is_always_immediate() && param_mask & 1 == 1; param_mask >>= 1; value } else { @@ -250,7 +250,7 @@ fn decode_args_with_abi( | ArgEncoding::Integer { arg0: false, size: 4, format: ast::IntFormat { unsigned: false, radix: _ }, .. } => { decrease_len(emitter, &mut remaining_len, 4)?; - ScalarValue::Int(args_blob.read_i32().expect("already checked len") as i32) + ScalarValue::Int(args_blob.read_i32().expect("already checked len")) }, | ArgEncoding::Integer { arg0: false, size: 2, format: ast::IntFormat { unsigned: false, radix: _ }, .. } @@ -277,6 +277,8 @@ fn decode_args_with_abi( ScalarValue::Int(args_blob.read_u16().expect("already checked len") as i32) }, + // Padding produces values for the sake of verifying the bytes are 0. TODO: Implement! + // They're filtered out later on after dealing with @arg0 in the argument-raising pass. | ArgEncoding::Padding | ArgEncoding::Integer { arg0: false, size: 1, format: ast::IntFormat { unsigned: true, radix: _ }, .. } => { @@ -677,7 +679,7 @@ impl AtomRaiser<'_, '_> { &lookup_table, raw.expect_int(), ty_color, - format, + *format, )) } @@ -750,7 +752,7 @@ impl AtomRaiser<'_, '_> { } } -fn raise_to_possibly_named_constant(names: &IdMap>, id: i32, ty_color: &TypeColor, format: &ast::IntFormat) -> ast::Expr { +fn raise_to_possibly_named_constant(names: &IdMap>, id: i32, ty_color: &TypeColor, format: ast::IntFormat) -> ast::Expr { match names.get(&id) { Some(ident) => { match ty_color { @@ -762,7 +764,7 @@ fn raise_to_possibly_named_constant(names: &IdMap>, id: i32, ty_c }, } }, - None => ast::Expr::LitInt { value: id, format: *format }, + None => ast::Expr::LitInt { value: id, format: format }, } } From f3de7377e22349d459d2de355b271c5bb4cdbf86 Mon Sep 17 00:00:00 2001 From: zero318 Date: Thu, 30 Jun 2022 02:07:13 -0400 Subject: [PATCH 04/26] Change _ back to 4 bytes and add - for single bytes --- src/core_mapfiles/std.rs | 40 +++++++++++++++--------------- src/llir/abi.rs | 22 +++++++++------- src/llir/intrinsic.rs | 2 +- src/llir/lower.rs | 10 +++++--- src/llir/raise/early.rs | 22 ++++++++++++---- src/parse/abi.rs | 2 +- tests/integration/timeline_arg0.rs | 2 +- 7 files changed, 60 insertions(+), 40 deletions(-) diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index 3721a02..1036711 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -22,9 +22,9 @@ static STD_06: &CoreSignatures = &CoreSignatures { (Th06, 0, Some(("fff", None))), (Th06, 1, Some(("Cff", None))), (Th06, 2, Some(("fff", None))), - (Th06, 3, Some(("S________", None))), - (Th06, 4, Some(("S________", None))), - (Th06, 5, Some(("____________", None))), + (Th06, 3, Some(("S__", None))), + (Th06, 4, Some(("S__", None))), + (Th06, 5, Some(("___", None))), ], var: &[], }; @@ -34,40 +34,40 @@ static STD_07_09: &CoreSignatures = &CoreSignatures { ins: &[ (Th07, 0, Some(("fff", None))), (Th07, 1, Some(("Cff", None))), - (Th07, 2, Some(("S________", None))), - (Th07, 3, Some(("____________", None))), - (Th07, 4, Some(("ot____", Some(IKind::Jmp)))), + (Th07, 2, Some(("S__", None))), + (Th07, 3, Some(("___", None))), + (Th07, 4, Some(("ot_", Some(IKind::Jmp)))), (Th07, 5, Some(("fff", None))), - (Th07, 6, Some(("SS____", None))), + (Th07, 6, Some(("SS_", None))), (Th07, 7, Some(("fff", None))), - (Th07, 8, Some(("SS____", None))), + (Th07, 8, Some(("SS_", None))), (Th07, 9, Some(("fff", None))), - (Th07, 10, Some(("SS____", None))), - (Th07, 11, Some(("f________", None))), - (Th07, 12, Some(("SS____", None))), - (Th07, 13, Some(("C________", None))), + (Th07, 10, Some(("SS_", None))), + (Th07, 11, Some(("f__", None))), + (Th07, 12, Some(("SS_", None))), + (Th07, 13, Some(("C__", None))), (Th07, 14, Some(("fff", None))), (Th07, 15, Some(("fff", None))), (Th07, 16, Some(("fff", None))), (Th07, 17, Some(("fff", None))), - (Th07, 18, Some(("S________", None))), + (Th07, 18, Some(("S__", None))), (Th07, 19, Some(("fff", None))), (Th07, 20, Some(("fff", None))), (Th07, 21, Some(("fff", None))), (Th07, 22, Some(("fff", None))), - (Th07, 23, Some(("S________", None))), + (Th07, 23, Some(("S__", None))), (Th07, 24, Some(("fff", None))), (Th07, 25, Some(("fff", None))), (Th07, 26, Some(("fff", None))), (Th07, 27, Some(("fff", None))), - (Th07, 28, Some(("S________", None))), - (Th07, 29, Some(("S________", None))), // anm script - (Th07, 30, Some(("S________", None))), // anm script - (Th07, 31, Some(("S________", Some(IKind::InterruptLabel)))), + (Th07, 28, Some(("S__", None))), + (Th07, 29, Some(("S__", None))), // anm script + (Th07, 30, Some(("S__", None))), // anm script + (Th07, 31, Some(("S__", Some(IKind::InterruptLabel)))), (Th08, 32, Some(("fff", None))), - (Th08, 33, Some(("S________", None))), - (Th08, 34, Some(("S________", None))), // anm script + (Th08, 33, Some(("S__", None))), + (Th08, 34, Some(("S__", None))), // anm script ], var: &[], }; diff --git a/src/llir/abi.rs b/src/llir/abi.rs index 127685d..60938f4 100644 --- a/src/llir/abi.rs +++ b/src/llir/abi.rs @@ -47,8 +47,9 @@ pub enum ArgEncoding { JumpOffset, /// `t` in mapfile. Max of one per instruction, and requires an accompanying `o` arg. JumpTime, - /// `_` in mapfile. Unused 1-byte space. - Padding, + /// `_` in mapfile. Unused 4-byte space. + /// `-` in mapfile. Unused 1-byte space. + Padding { size: u8 }, /// `f` in mapfile. Single-precision float. Float { immediate: bool }, /// `z(bs=)`, `m(bs=;mask=,,)`, or `m(len=;mask=,,)` in mapfile. @@ -93,7 +94,9 @@ impl ArgEncoding { Self::Integer { size: _, .. } => "integer", Self::JumpOffset => "jump offset", Self::JumpTime => "jump time", - Self::Padding => "padding", + Self::Padding { size: 4 } => "dword padding", + Self::Padding { size: 1 } => "byte padding", + Self::Padding { size: _ } => "padding", Self::Float { .. } => "float", Self::String { .. } => "string", } @@ -125,7 +128,7 @@ impl ArgEncoding { } pub fn contributes_to_param_mask(&self) -> bool { - !matches!(self, Self::Padding) + !matches!(self, Self::Padding { .. }) } pub fn is_always_immediate(&self) -> bool { @@ -133,7 +136,7 @@ impl ArgEncoding { | Self::String { .. } | Self::JumpOffset | Self::JumpTime - | Self::Padding + | Self::Padding { .. } | Self::Integer { immediate: true, .. } | Self::Float { immediate: true, .. } => true, @@ -212,7 +215,7 @@ impl ArgEncoding { match self { | ArgEncoding::JumpOffset | ArgEncoding::JumpTime - | ArgEncoding::Padding + | ArgEncoding::Padding { .. } | ArgEncoding::Integer { .. } => ScalarType::Int, @@ -358,7 +361,8 @@ fn other_from_attrs(param: &abi_ast::Param, _emitter: &dyn Emitter) -> Result Ok(Some(ArgEncoding::JumpOffset)), 't' => Ok(Some(ArgEncoding::JumpTime)), - '_' => Ok(Some(ArgEncoding::Padding)), + '_' => Ok(Some(ArgEncoding::Padding { size: 4 })), + '-' => Ok(Some(ArgEncoding::Padding { size: 1 })), _ => Ok(None), } } @@ -414,8 +418,8 @@ fn abi_to_signature(abi: &InstrAbi, abi_span: Span, ctx: &mut CompilerContext<'_ | ArgEncoding::JumpTime => Info { ty: ScalarType::Int, default: None, reg_ok: false, ty_color: None }, - | ArgEncoding::Padding - => Info { ty: ScalarType::Int, default: Some(sp!(0.into())), reg_ok: true, ty_color: None }, + | ArgEncoding::Padding { .. } + => Info { ty: ScalarType::Int, default: Some(sp!(0.into())), reg_ok: false, ty_color: None }, | ArgEncoding::Float { .. } => Info { ty: ScalarType::Float, default: None, reg_ok: true, ty_color: None }, diff --git a/src/llir/intrinsic.rs b/src/llir/intrinsic.rs index 52aac2a..5da3132 100644 --- a/src/llir/intrinsic.rs +++ b/src/llir/intrinsic.rs @@ -253,7 +253,7 @@ impl IntrinsicAbiHelper<'_> { } fn find_and_remove_padding(&self, arg_encodings: &mut Vec<(usize, &ArgEncoding)>) { - arg_encodings.retain(|(_, enc)| !matches!(*enc, ArgEncoding::Padding)); + arg_encodings.retain(|(_, enc)| !matches!(*enc, ArgEncoding::Padding { .. })); } fn find_and_remove_jump(&self, arg_encodings: &mut Vec<(usize, &ArgEncoding)>) -> Result<(usize, abi_parts::JumpArgOrder), Diagnostic> { diff --git a/src/llir/lower.rs b/src/llir/lower.rs index ad85f7c..b05dacf 100644 --- a/src/llir/lower.rs +++ b/src/llir/lower.rs @@ -553,8 +553,12 @@ fn encode_args( // to ensure that this loop reads an equal number of items from all iters. assert!(args_iter.len() <= arg_encodings_iter.len()); for enc in arg_encodings_iter.by_ref() { - if matches!(enc, ArgEncoding::Padding) { - args_blob.write_u8(0).expect("Cursor failed?!"); + if let ArgEncoding::Padding { size } = enc { + match size { + 1 => args_blob.write_u8(0).expect("Cursor failed?!"), + 4 => args_blob.write_u32(0).expect("Cursor failed?!"), + _ => unreachable!(), + } continue; } let arg = args_iter.next().expect("function arity already checked"); @@ -593,7 +597,7 @@ fn encode_args( match *enc { | ArgEncoding::Integer { arg0: true, .. } - | ArgEncoding::Padding + | ArgEncoding::Padding { .. } => unreachable!(), | ArgEncoding::JumpOffset diff --git a/src/llir/raise/early.rs b/src/llir/raise/early.rs index fecf58b..2f9c8c9 100644 --- a/src/llir/raise/early.rs +++ b/src/llir/raise/early.rs @@ -224,6 +224,18 @@ fn decode_args_with_abi( let reg_style = hooks.register_style(); for (arg_index, enc) in siggy.arg_encodings().enumerate() { + // Padding produces values for the sake of verifying the bytes are 0. TODO: Implement! + // They're filtered out later on after dealing with @arg0 in the argument-raising pass. + if let ArgEncoding::Padding { size } = enc { + decrease_len(emitter, &mut remaining_len, *size as usize)?; + let raw_value = match size { + 1 => args_blob.read_u8().expect("already checked len") as i32, + 4 => args_blob.read_u32().expect("already checked len") as i32, + _ => unreachable!(), + }; + args.push(SimpleArg { value: ScalarValue::Int(raw_value), is_reg: false } ); + continue; + } let ref emitter = add_argument_context(emitter, arg_index); // TODO: Add a way to fallback to @mask for @@ -237,6 +249,9 @@ fn decode_args_with_abi( }; let value = match *enc { + | ArgEncoding::Padding { .. } + => unreachable!(), + | ArgEncoding::Integer { arg0: true, .. } => { // a check that non-timeline languages don't have timeline args in their signature @@ -277,9 +292,6 @@ fn decode_args_with_abi( ScalarValue::Int(args_blob.read_u16().expect("already checked len") as i32) }, - // Padding produces values for the sake of verifying the bytes are 0. TODO: Implement! - // They're filtered out later on after dealing with @arg0 in the argument-raising pass. - | ArgEncoding::Padding | ArgEncoding::Integer { arg0: false, size: 1, format: ast::IntFormat { unsigned: true, radix: _ }, .. } => { decrease_len(emitter, &mut remaining_len, 1)?; @@ -558,7 +570,7 @@ impl AtomRaiser<'_, '_> { // // IMPORTANT: this is looking at the original arg list because the new lengths may differ due to arg0. let mut arg_iter = abi.arg_encodings(); - raised_args.retain(|_| !matches!(arg_iter.next().unwrap(), ArgEncoding::Padding)); + raised_args.retain(|_| !matches!(arg_iter.next().unwrap(), ArgEncoding::Padding { .. })); Ok(RaisedIntrinsicParts { opcode: Some(instr.opcode), @@ -667,7 +679,7 @@ impl AtomRaiser<'_, '_> { | ArgEncoding::Integer { ty_color: None, format, .. } => Ok(ast::Expr::LitInt { value: raw.expect_int(), format: *format }), - | ArgEncoding::Padding + | ArgEncoding::Padding { .. } => Ok(ast::Expr::from(raw.expect_int())), | ArgEncoding::Integer { ty_color: Some(ty_color), format, .. } diff --git a/src/parse/abi.rs b/src/parse/abi.rs index aeec8ac..32cbaf4 100644 --- a/src/parse/abi.rs +++ b/src/parse/abi.rs @@ -124,7 +124,7 @@ pub fn parse_abi( } match next_char { - format_char @ sp_pat!('a'..='z' | 'A'..='Z' | '_' | '0'..='9') => { + format_char @ sp_pat!('a'..='z' | 'A'..='Z' | '_' | '-' | '0'..='9') => { let next_non_ws = text.chars().filter(|&c| !is_ws(c)).next(); let attributes = match next_non_ws { // Type with attributes. diff --git a/tests/integration/timeline_arg0.rs b/tests/integration/timeline_arg0.rs index 051b72f..d98bccf 100644 --- a/tests/integration/timeline_arg0.rs +++ b/tests/integration/timeline_arg0.rs @@ -169,7 +169,7 @@ source_test!( ECL_TIMELINE_06, unused_arg0_padding_edge_case, mapfile: r#"!eclmap !timeline_ins_signatures -200 s(arg0;enum="MsgScript")S________ +200 s(arg0;enum="MsgScript")S__ "#, // this is an edge case that arose in decompilation where the presence of a timeline // arg could make the code that trims padding look at the wrong values From 96c1d4c56168dd747d7959c8c0a3224d00c684cc Mon Sep 17 00:00:00 2001 From: zero318 Date: Fri, 1 Jul 2022 05:01:35 -0400 Subject: [PATCH 05/26] First batch of updated signatures --- src/core_mapfiles/anm.rs | 58 +++--- src/core_mapfiles/ecl.rs | 354 ++++++++++++++++++----------------- src/core_mapfiles/msg.rs | 10 +- src/core_mapfiles/std.rs | 10 +- src/llir/abi.rs | 8 +- tests/integration/general.rs | 2 +- 6 files changed, 222 insertions(+), 220 deletions(-) diff --git a/src/core_mapfiles/anm.rs b/src/core_mapfiles/anm.rs index ce56c27..2852498 100644 --- a/src/core_mapfiles/anm.rs +++ b/src/core_mapfiles/anm.rs @@ -49,8 +49,8 @@ static ANM_INS_06: &'static CoreSignatures = &CoreSignatures { (Th06, 0, Some(("", None))), (Th06, 1, Some(("n", None))), (Th06, 2, Some(("ff", None))), - (Th06, 3, Some(("S", None))), - (Th06, 4, Some(("C", None))), + (Th06, 3, Some(("b(hex)---", None))), + (Th06, 4, Some(("b(hex)b(hex)b(hex)-", None))), (Th06, 5, Some(("o", Some(IKind::Jmp)))), (Th06, 6, Some(("", None))), (Th06, 7, Some(("", None))), @@ -58,26 +58,26 @@ static ANM_INS_06: &'static CoreSignatures = &CoreSignatures { (Th06, 9, Some(("fff", None))), (Th06, 10, Some(("fff", None))), (Th06, 11, Some(("ff", None))), - (Th06, 12, Some(("SS", None))), + (Th06, 12, Some(("b(hex)---s--", None))), (Th06, 13, Some(("", None))), (Th06, 14, Some(("", None))), (Th06, 15, Some(("", None))), - (Th06, 16, Some(("nS", None))), + (Th06, 16, Some(("nu--", None))), (Th06, 17, Some(("fff", None))), - (Th06, 18, Some(("fffS", None))), - (Th06, 19, Some(("fffS", None))), - (Th06, 20, Some(("fffS", None))), + (Th06, 18, Some(("fffs--", None))), + (Th06, 19, Some(("fffs--", None))), + (Th06, 20, Some(("fffs--", None))), (Th06, 21, Some(("", None))), (Th06, 22, Some(("S", Some(IKind::InterruptLabel)))), (Th06, 23, Some(("", None))), (Th06, 24, Some(("", None))), - (Th06, 25, Some(("S", None))), - (Th06, 26, Some(("S", None))), + (Th06, 25, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") + (Th06, 26, Some(("s--", None))), (Th06, 27, Some(("f", None))), (Th06, 28, Some(("f", None))), - (Th06, 29, Some(("S", None))), - (Th06, 30, Some(("ffS", None))), - (Th06, 31, Some(("S", None))), + (Th06, 29, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") + (Th06, 30, Some(("ffs--", None))), + (Th06, 31, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") ], var: &[], }; @@ -92,38 +92,38 @@ static ANM_INS_07_09: &'static CoreSignatures = &CoreSignatures { (Th07, 2, Some(("", None))), (Th07, 3, Some(("n", None))), (Th07, 4, Some(("ot", Some(IKind::Jmp)))), - (Th07, 5, Some(("Sot", Some(IKind::CountJmp(B::Ne))))), + (Th07, 5, Some(("Sot", Some(IKind::CountJmp(B::Gt))))), (Th07, 6, Some(("fff", None))), (Th07, 7, Some(("ff", None))), - (Th07, 8, Some(("S", None))), - (Th07, 9, Some(("S", None))), + (Th07, 8, Some(("b(imm;hex)---", None))), + (Th07, 9, Some(("b(imm;hex)b(imm;hex)b(imm;hex)-", None))), (Th07, 10, Some(("", None))), (Th07, 11, Some(("", None))), (Th07, 12, Some(("fff", None))), (Th07, 13, Some(("fff", None))), (Th07, 14, Some(("ff", None))), - (Th07, 15, Some(("SS", None))), - (Th07, 16, Some(("S", None))), + (Th07, 15, Some(("b(imm;hex)---S", None))), + (Th07, 16, Some(("U(imm)", None))), (Th07, 17, Some(("fffS", None))), (Th07, 18, Some(("fffS", None))), (Th07, 19, Some(("fffS", None))), (Th07, 20, Some(("", None))), - (Th07, 21, Some(("S", Some(IKind::InterruptLabel)))), + (Th07, 21, Some(("S(imm)", Some(IKind::InterruptLabel)))), (Th07, 22, Some(("", None))), (Th07, 23, Some(("", None))), - (Th07, 24, Some(("S", None))), - (Th07, 25, Some(("S", None))), + (Th07, 24, Some((r#"U(imm;enum="bool")"#, None))), // zero: U(imm;enum="BitBool") + (Th07, 25, Some(("s(imm)--", None))), (Th07, 26, Some(("f", None))), (Th07, 27, Some(("f", None))), - (Th07, 28, Some(("S", None))), + (Th07, 28, Some((r#"U(imm;enum="bool")"#, None))), // zero: U(imm;enum="BitBool") (Th07, 29, Some(("ffS", None))), - (Th07, 30, Some(("S", None))), - (Th07, 31, Some(("S", None))), - (Th07, 32, Some(("SSfff", None))), - (Th07, 33, Some(("SSS", None))), - (Th07, 34, Some(("SSS", None))), - (Th07, 35, Some(("SSfff", None))), - (Th07, 36, Some(("SSff", None))), + (Th07, 30, Some((r#"U(imm;enum="bool")"#, None))), // zero: U(imm;enum="BitBool") + (Th07, 31, Some((r#"U(imm;enum="bool")"#, None))), // zero: U(imm;enum="BitBool") + (Th07, 32, Some(("Sb(imm)---fff", None))), + (Th07, 33, Some(("Sb(imm)---b(imm;hex)b(imm;hex)b(imm;hex)-", None))), + (Th07, 34, Some(("Sb(imm)---b(imm;hex)---", None))), + (Th07, 35, Some(("Sb(imm)---fff", None))), + (Th07, 36, Some(("Sb(imm)---ff", None))), (Th07, 37, Some(("SS", Some(IKind::AssignOp(A::Assign, Ty::Int))))), (Th07, 38, Some(("ff", Some(IKind::AssignOp(A::Assign, Ty::Float))))), (Th07, 39, Some(("SS", Some(IKind::AssignOp(A::Add, Ty::Int))))), @@ -146,7 +146,7 @@ static ANM_INS_07_09: &'static CoreSignatures = &CoreSignatures { (Th07, 56, Some(("fff", Some(IKind::BinOp(B::Div, Ty::Float))))), (Th07, 57, Some(("SSS", Some(IKind::BinOp(B::Rem, Ty::Int))))), (Th07, 58, Some(("fff", Some(IKind::BinOp(B::Rem, Ty::Float))))), - (Th07, 59, Some(("SS", None))), + (Th07, 59, Some(("SU", None))), (Th07, 60, Some(("ff", None))), (Th07, 61, Some(("ff", Some(IKind::UnOp(U::Sin, Ty::Float))))), (Th07, 62, Some(("ff", Some(IKind::UnOp(U::Cos, Ty::Float))))), diff --git a/src/core_mapfiles/ecl.rs b/src/core_mapfiles/ecl.rs index 0d8d550..8f2c77c 100644 --- a/src/core_mapfiles/ecl.rs +++ b/src/core_mapfiles/ecl.rs @@ -41,13 +41,14 @@ static TIMELINE: &'static CoreSignatures = &CoreSignatures { (Th06, 8, Some((r#"s(arg0;enum="MsgScript")"#, None))), (Th06, 9, Some(("", None))), (Th06, 10, Some(("SS", None))), - (Th06, 11, Some(("s(arg0)", None))), + (Th06, 11, Some(("u(arg0)", None))), (Th06, 12, Some(("s(arg0)", None))), (Th07, 0, Some((r#"s(arg0;enum="EclSub")fffSSS"#, None))), (Th07, 2, Some((r#"s(arg0;enum="EclSub")fffSSS"#, None))), (Th07, 4, Some((r#"s(arg0;enum="EclSub")fffSSS"#, None))), (Th07, 6, Some((r#"s(arg0;enum="EclSub")fffSSS"#, None))), + (Th07, 11, Some(("s(arg0)", None))), (Th08, 0, Some(("EffSSS", None))), (Th08, 1, Some(("EffSSS", None))), @@ -57,7 +58,7 @@ static TIMELINE: &'static CoreSignatures = &CoreSignatures { (Th08, 5, Some(("EfSSS", None))), (Th08, 6, Some((r#"S(enum="MsgScript")"#, None))), (Th08, 7, Some(("", None))), // Not implemented in PoFV, but present in the files anyway - (Th08, 8, Some(("SS", None))), + (Th08, 8, Some(("Ss--", None))), (Th08, 9, Some(("S", None))), (Th08, 10, Some(("S", None))), (Th08, 11, Some(("EffSSSS", None))), @@ -83,13 +84,13 @@ static ECL_06: &'static CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th06, 0, Some(("", None))), - (Th06, 1, Some(("S", None))), + (Th06, 1, Some(("_", None))), // Bytes are never read (Th06, 2, Some(("to", Some(IKind::Jmp)))), (Th06, 3, Some(("toS", Some(IKind::CountJmp(B::Gt))))), (Th06, 4, Some(("SS", Some(IKind::AssignOp(A::Assign, Ty::Int))))), (Th06, 5, Some(("Sf", Some(IKind::AssignOp(A::Assign, Ty::Float))))), - (Th06, 6, Some(("SS", None))), - (Th06, 7, Some(("SSS", None))), + (Th06, 6, Some(("SU", None))), // The division for both of these uses DIV instead of IDIV + (Th06, 7, Some(("SUS", None))), (Th06, 8, Some(("Sf", None))), (Th06, 9, Some(("Sff", None))), (Th06, 10, Some(("S", None))), @@ -97,7 +98,7 @@ static ECL_06: &'static CoreSignatures = &CoreSignatures { (Th06, 12, Some(("S", None))), (Th06, 13, Some(("SSS", Some(IKind::BinOp(B::Add, Ty::Int))))), (Th06, 14, Some(("SSS", Some(IKind::BinOp(B::Sub, Ty::Int))))), - (Th06, 15, Some(("SSS", Some(IKind::BinOp(B::Mul, Ty::Int))))), + (Th06, 15, Some(("SSS", Some(IKind::BinOp(B::Mul, Ty::Int))))), // EoSD reads args 2/3 an extra time for multiplication compared to the other ops, so don't prefer multiplication based fallback sequences (Th06, 16, Some(("SSS", Some(IKind::BinOp(B::Div, Ty::Int))))), (Th06, 17, Some(("SSS", Some(IKind::BinOp(B::Rem, Ty::Int))))), (Th06, 18, Some(("S", None))), // Some(IKind::UnOp(U::Inc, Ty::Int)) @@ -117,108 +118,109 @@ static ECL_06: &'static CoreSignatures = &CoreSignatures { (Th06, 32, Some(("to", Some(IKind::CondJmp2B(B::Gt))))), (Th06, 33, Some(("to", Some(IKind::CondJmp2B(B::Ge))))), (Th06, 34, Some(("to", Some(IKind::CondJmp2B(B::Ne))))), - (Th06, 35, Some(("ESf", Some(IKind::CallEosd)))), + (Th06, 35, Some(("E(imm)S(imm)f(imm)", Some(IKind::CallEosd)))), (Th06, 36, Some(("", None))), // Some(IKind::Return) - (Th06, 37, Some(("ESfSS", None))), // Some(IKind::CallEosdCond(B::Lt)) - (Th06, 38, Some(("ESfSS", None))), // Some(IKind::CallEosdCond(B::Le)) - (Th06, 39, Some(("ESfSS", None))), // Some(IKind::CallEosdCond(B::Eq)) - (Th06, 40, Some(("ESfSS", None))), // Some(IKind::CallEosdCond(B::Gt)) - (Th06, 41, Some(("ESfSS", None))), // Some(IKind::CallEosdCond(B::Ge)) - (Th06, 42, Some(("ESfSS", None))), // Some(IKind::CallEosdCond(B::Ne)) + (Th06, 37, Some(("E(imm)S(imm)f(imm)SS(imm)", None))), // Some(IKind::CallEosdCond(B::Lt)) + (Th06, 38, Some(("E(imm)S(imm)f(imm)SS(imm)", None))), // Some(IKind::CallEosdCond(B::Le)) + (Th06, 39, Some(("E(imm)S(imm)f(imm)SS(imm)", None))), // Some(IKind::CallEosdCond(B::Eq)) + (Th06, 40, Some(("E(imm)S(imm)f(imm)SS(imm)", None))), // Some(IKind::CallEosdCond(B::Gt)) + (Th06, 41, Some(("E(imm)S(imm)f(imm)SS(imm)", None))), // Some(IKind::CallEosdCond(B::Ge)) + (Th06, 42, Some(("E(imm)S(imm)f(imm)SS(imm)", None))), // Some(IKind::CallEosdCond(B::Ne)) (Th06, 43, Some(("fff", None))), (Th06, 44, Some(("fff", None))), (Th06, 45, Some(("ff", None))), (Th06, 46, Some(("f", None))), (Th06, 47, Some(("f", None))), (Th06, 48, Some(("f", None))), - (Th06, 49, Some(("ff", None))), - (Th06, 50, Some(("ff", None))), - (Th06, 51, Some(("ff", None))), - (Th06, 52, Some(("Sff", None))), - (Th06, 53, Some(("Sff", None))), - (Th06, 54, Some(("Sff", None))), - (Th06, 55, Some(("Sff", None))), - (Th06, 56, Some(("Sfff", None))), - (Th06, 57, Some(("Sfff", None))), - (Th06, 58, Some(("Sfff", None))), - (Th06, 59, Some(("Sfff", None))), - (Th06, 60, Some(("Sfff", None))), - (Th06, 61, Some(("S", None))), - (Th06, 62, Some(("S", None))), - (Th06, 63, Some(("S", None))), - (Th06, 64, Some(("S", None))), - (Th06, 65, Some(("ffff", None))), + (Th06, 49, Some(("f(imm)f(imm)", None))), + (Th06, 50, Some(("f(imm)f(imm)", None))), + (Th06, 51, Some(("f(imm)f", None))), + (Th06, 52, Some(("S(imm)ff(imm)", None))), + (Th06, 53, Some(("S(imm)ff(imm)", None))), + (Th06, 54, Some(("S(imm)ff(imm)", None))), + (Th06, 55, Some(("S(imm)ff(imm)", None))), + (Th06, 56, Some(("S(imm)fff", None))), + (Th06, 57, Some(("S(imm)fff", None))), + (Th06, 58, Some(("S(imm)fff", None))), + (Th06, 59, Some(("S(imm)fff", None))), + (Th06, 60, Some(("S(imm)fff", None))), + (Th06, 61, Some(("S(imm)", None))), // + (Th06, 62, Some(("S(imm)", None))), // These read the current value of SELF_ANGLE as a variable + (Th06, 63, Some(("S(imm)", None))), // + (Th06, 64, Some(("S(imm)", None))), // + (Th06, 65, Some(("f(imm)f(imm)f(imm)f(imm)", None))), (Th06, 66, Some(("", None))), - (Th06, 67, Some(("ssSSffffS", None))), - (Th06, 68, Some(("ssSSffffS", None))), - (Th06, 69, Some(("ssSSffffS", None))), - (Th06, 70, Some(("ssSSffffS", None))), - (Th06, 71, Some(("ssSSffffS", None))), - (Th06, 72, Some(("ssSSffffS", None))), - (Th06, 73, Some(("ssSSffffS", None))), - (Th06, 74, Some(("ssSSffffS", None))), - (Th06, 75, Some(("ssSSffffS", None))), - (Th06, 76, Some(("S", None))), - (Th06, 77, Some(("S", None))), + // Flags marked as hex + (Th06, 67, Some(("s(imm)sSSffffU(imm;hex)", None))), + (Th06, 68, Some(("s(imm)sSSffffU(imm;hex)", None))), + (Th06, 69, Some(("s(imm)sSSffffU(imm;hex)", None))), + (Th06, 70, Some(("s(imm)sSSffffU(imm;hex)", None))), + (Th06, 71, Some(("s(imm)sSSffffU(imm;hex)", None))), + (Th06, 72, Some(("s(imm)sSSffffU(imm;hex)", None))), + (Th06, 73, Some(("s(imm)sSSffffU(imm;hex)", None))), + (Th06, 74, Some(("s(imm)sSSffffU(imm;hex)", None))), + (Th06, 75, Some(("s(imm)sSSffffU(imm;hex)", None))), + (Th06, 76, Some(("S(imm)", None))), + (Th06, 77, Some(("S(imm)", None))), // This value is used with both IDIV and DIV...? (Th06, 78, Some(("", None))), (Th06, 79, Some(("", None))), (Th06, 80, Some(("", None))), (Th06, 81, Some(("fff", None))), (Th06, 82, Some(("SSSSffff", None))), (Th06, 83, Some(("", None))), - (Th06, 84, Some(("S", None))), - (Th06, 85, Some(("ssffffffSSSSSS", None))), - (Th06, 86, Some(("ssffffffSSSSSS", None))), + (Th06, 84, Some(("S(imm)", None))), + (Th06, 85, Some(("s(imm)s(imm)ffffff(imm)S(imm)S(imm)S(imm)S(imm)S(imm)U(imm;hex)", None))), + (Th06, 86, Some(("s(imm)s(imm)ffffff(imm)S(imm)S(imm)S(imm)S(imm)S(imm)U(imm;hex)", None))), (Th06, 87, Some(("S", None))), - (Th06, 88, Some(("Sf", None))), - (Th06, 89, Some(("Sf", None))), - (Th06, 90, Some(("Sfff", None))), - (Th06, 91, Some(("S", None))), - (Th06, 92, Some(("S", None))), + (Th06, 88, Some(("S(imm)f", None))), + (Th06, 89, Some(("S(imm)f", None))), + (Th06, 90, Some(("S(imm)f(imm)f(imm)f(imm)", None))), + (Th06, 91, Some(("S(imm)", None))), + (Th06, 92, Some(("S(imm)", None))), // 34. Yes. This makes every spell name instruction not a multiple of 4 bytes. - (Th06, 93, Some(("ssz(len=34)", None))), + (Th06, 93, Some(("s(imm)s(imm)z(len=34)", None))), (Th06, 94, Some(("", None))), - (Th06, 95, Some(("EfffssS", None))), + (Th06, 95, Some(("E(imm)fffs(imm)s(imm)S(imm)", None))), (Th06, 96, Some(("", None))), - (Th06, 97, Some(("N", None))), - (Th06, 98, Some((r#"s(enum="AnmScript")s(enum="AnmScript")s(enum="AnmScript")s(enum="AnmScript")N"#, None))), // zero: s(enum="AnmScript")s(enum="AnmScript")s(enum="AnmScript")s(enum="AnmScript")s(enum="AnmScript")-- - (Th06, 99, Some(("SN", None))), - (Th06, 100, Some(("U", None))), // zero: bbb- - (Th06, 101, Some(("S", None))), - (Th06, 102, Some(("Sffff", None))), - (Th06, 103, Some(("fff", None))), - (Th06, 104, Some(("U", None))), // zero: b--- - (Th06, 105, Some(("U", None))), // zero: b--- - (Th06, 106, Some(("S", None))), - (Th06, 107, Some(("U", None))), // zero: b--- - (Th06, 108, Some(("E", None))), - (Th06, 109, Some(("ES", None))), - (Th06, 110, Some(("S", None))), - (Th06, 111, Some(("S", None))), - (Th06, 112, Some(("S", None))), - (Th06, 113, Some(("S", None))), - (Th06, 114, Some(("E", None))), - (Th06, 115, Some(("S", None))), - (Th06, 116, Some(("E", None))), - (Th06, 117, Some(("U", None))), // zero: b--- - (Th06, 118, Some(("SUC", None))), - (Th06, 119, Some(("S", None))), - (Th06, 120, Some(("U", None))), // zero: b--- - (Th06, 121, Some(("SS", None))), - (Th06, 122, Some(("S", None))), - (Th06, 123, Some(("S", None))), - (Th06, 124, Some(("S", None))), + (Th06, 97, Some(("N(imm)", None))), + (Th06, 98, Some((r#"s(imm;enum="AnmScript")s(imm;enum="AnmScript")s(imm;enum="AnmScript")s(imm;enum="AnmScript")s(imm;enum="AnmScript")--"#, None))), + (Th06, 99, Some(("S(imm)N(imm)", None))), + (Th06, 100, Some(("b(imm)b(imm)b(imm)-", None))), + (Th06, 101, Some(("S(imm)", None))), + (Th06, 102, Some(("S(imm)f(imm)f(imm)f(imm)f(imm)", None))), + (Th06, 103, Some(("f(imm)f(imm)f(imm)", None))), + (Th06, 104, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th06, 105, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th06, 106, Some(("S(imm)", None))), + (Th06, 107, Some(("b(imm)---", None))), + (Th06, 108, Some(("E(imm)", None))), + (Th06, 109, Some(("E(imm)S(imm)", None))), + (Th06, 110, Some(("S(imm)", None))), + (Th06, 111, Some(("S(imm)", None))), + (Th06, 112, Some(("S(imm)", None))), + (Th06, 113, Some(("S(imm)", None))), + (Th06, 114, Some(("E(imm)", None))), + (Th06, 115, Some(("S(imm)", None))), + (Th06, 116, Some(("E(imm)", None))), + (Th06, 117, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th06, 118, Some(("S(imm)U(imm)C(imm)", None))), + (Th06, 119, Some(("S(imm)", None))), + (Th06, 120, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th06, 121, Some(("S(imm)S(imm)", None))), // zero: S(imm)v + (Th06, 122, Some(("S(imm)", None))), + (Th06, 123, Some(("S", None))), // Lack of (imm) here is not a typo + (Th06, 124, Some(("S(imm)", None))), (Th06, 125, Some(("", None))), - (Th06, 126, Some(("S", None))), + (Th06, 126, Some(("S(imm)", None))), (Th06, 127, Some(("S", None))), - (Th06, 128, Some(("S", None))), // zero: s-- - (Th06, 129, Some(("SS", None))), // zero: Ss-- - (Th06, 130, Some(("U", None))), // zero: b--- - (Th06, 131, Some(("ffSSSS", None))), - (Th06, 132, Some(("U", None))), // zero: b--- + (Th06, 128, Some(("s(imm)--", None))), + (Th06, 129, Some(("S(imm)s(imm)--", None))), + (Th06, 130, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th06, 131, Some(("f(imm)f(imm)S(imm)S(imm)S(imm)S(imm)", None))), + (Th06, 132, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- (Th06, 133, Some(("", None))), (Th06, 134, Some(("", None))), - (Th06, 135, Some(("U", None))), // zero: b--- + (Th06, 135, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- ], var: &[ (Th06, -10001, Some("$")), @@ -258,8 +260,8 @@ static ECL_07: &'static CoreSignatures = &CoreSignatures { (Th07, 3, Some(("toS", Some(IKind::CountJmp(B::Gt))))), (Th07, 4, Some(("SS", Some(IKind::AssignOp(A::Assign, Ty::Int))))), (Th07, 5, Some(("ff", Some(IKind::AssignOp(A::Assign, Ty::Float))))), - (Th07, 6, Some(("SS", None))), - (Th07, 7, Some(("SSS", None))), + (Th07, 6, Some(("SU", None))), + (Th07, 7, Some(("SUS", None))), (Th07, 8, Some(("ff", None))), (Th07, 9, Some(("fff", None))), (Th07, 10, Some(("SS", None))), @@ -293,7 +295,7 @@ static ECL_07: &'static CoreSignatures = &CoreSignatures { (Th07, 38, Some(("SSto", Some(IKind::CondJmp(B::Ge, Ty::Int))))), (Th07, 39, Some(("ffto", Some(IKind::CondJmp(B::Ge, Ty::Float))))), (Th07, 40, Some(("f", None))), - (Th07, 41, Some(("E", Some(IKind::CallReg)))), + (Th07, 41, Some(("E(imm)", Some(IKind::CallReg)))), (Th07, 42, Some(("", None))), // Some(IKind::Return) (Th07, 43, Some(("SSS", None))), (Th07, 44, Some(("ffS", None))), @@ -304,7 +306,7 @@ static ECL_07: &'static CoreSignatures = &CoreSignatures { (Th07, 49, Some(("f", None))), (Th07, 50, Some(("f", None))), (Th07, 51, Some(("fff", None))), - (Th07, 52, Some(("fff", None))), + (Th07, 52, Some(("fff", None))), // Arguments 2 and 3 are never read (Th07, 53, Some(("ff", None))), (Th07, 54, Some(("SSff", None))), (Th07, 55, Some(("SSfff", None))), @@ -316,51 +318,51 @@ static ECL_07: &'static CoreSignatures = &CoreSignatures { (Th07, 61, Some(("S", None))), (Th07, 62, Some(("ffff", None))), (Th07, 63, Some(("", None))), - (Th07, 64, Some(("ssSSffffS", None))), - (Th07, 65, Some(("ssSSffffS", None))), - (Th07, 66, Some(("ssSSffffS", None))), - (Th07, 67, Some(("ssSSffffS", None))), - (Th07, 68, Some(("ssSSffffS", None))), - (Th07, 69, Some(("ssSSffffS", None))), - (Th07, 70, Some(("ssSSffffS", None))), - (Th07, 71, Some(("ssSSffffS", None))), - (Th07, 72, Some(("ssSSffffS", None))), + (Th07, 64, Some(("ssSSffffU(imm;hex)", None))), + (Th07, 65, Some(("ssSSffffU(imm;hex)", None))), + (Th07, 66, Some(("ssSSffffU(imm;hex)", None))), + (Th07, 67, Some(("ssSSffffU(imm;hex)", None))), + (Th07, 68, Some(("ssSSffffU(imm;hex)", None))), + (Th07, 69, Some(("ssSSffffU(imm;hex)", None))), + (Th07, 70, Some(("ssSSffffU(imm;hex)", None))), + (Th07, 71, Some(("ssSSffffU(imm;hex)", None))), + (Th07, 72, Some(("ssSSffffU(imm;hex)", None))), (Th07, 73, Some(("S", None))), (Th07, 74, Some(("S", None))), (Th07, 75, Some(("", None))), (Th07, 76, Some(("", None))), (Th07, 77, Some(("", None))), (Th07, 78, Some(("fff", None))), - (Th07, 79, Some(("SSUSSff", None))), + (Th07, 79, Some((r#"SU(hex)U(enum="bool")SSff"#, None))), (Th07, 80, Some(("", None))), (Th07, 81, Some(("SS", None))), - (Th07, 82, Some(("ssffffffSSSSSS", None))), - (Th07, 83, Some(("ssffffffSSSSSS", None))), + (Th07, 82, Some(("s(imm)sffffff(imm)S(imm)S(imm)S(imm)S(imm)S(imm)U(imm;hex)", None))), + (Th07, 83, Some(("s(imm)sffffff(imm)S(imm)S(imm)S(imm)S(imm)S(imm)U(imm;hex)", None))), (Th07, 84, Some(("S", None))), (Th07, 85, Some(("Sf", None))), (Th07, 86, Some(("Sf", None))), (Th07, 87, Some(("Sfff", None))), (Th07, 88, Some(("S", None))), (Th07, 89, Some(("S", None))), - (Th07, 90, Some(("sum(len=48;mask=0xaa,0,0)", None))), + (Th07, 90, Some(("s(imm)u(imm)m(len=48;mask=0xaa,0,0)", None))), (Th07, 91, Some(("", None))), - (Th07, 92, Some(("EfffSSS", None))), - (Th07, 93, Some(("EfffSSS", None))), + (Th07, 92, Some(("E(imm)fffSSS", None))), + (Th07, 93, Some(("E(imm)fffSSS", None))), (Th07, 94, Some(("", None))), (Th07, 95, Some(("N", None))), - (Th07, 96, Some((r#"s(enum="AnmScript")s(enum="AnmScript")s(enum="AnmScript")s(enum="AnmScript")N"#, None))), // zero: s(enum="AnmScript")s(enum="AnmScript")s(enum="AnmScript")s(enum="AnmScript")s(enum="AnmScript")-- + (Th07, 96, Some((r#"s(imm;enum="AnmScript")s(imm;enum="AnmScript")s(imm;enum="AnmScript")s(imm;enum="AnmScript")s(imm;enum="AnmScript")--"#, None))), (Th07, 97, Some(("SN", None))), - (Th07, 98, Some(("S", None))), // zero: bbb- + (Th07, 98, Some(("c(imm)b(imm)b(imm)-", None))), (Th07, 99, Some(("S", None))), - (Th07, 100, Some(("Sffff", None))), + (Th07, 100, Some(("S(imm)f(imm)f(imm)f(imm)f(imm)", None))), (Th07, 101, Some(("fff", None))), - (Th07, 102, Some(("U", None))), // zero: b--- - (Th07, 103, Some(("U", None))), // zero: b--- - (Th07, 104, Some(("U", None))), // zero: b--- + (Th07, 102, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th07, 103, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th07, 104, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- (Th07, 105, Some(("S", None))), - (Th07, 106, Some(("S", None))), - (Th07, 107, Some(("E", None))), // zero: b(enum="EclSub")--- - (Th07, 108, Some(("ES", None))), + (Th07, 106, Some(("b(imm)---", None))), + (Th07, 107, Some((r#"b(imm;enum="EclSub")---"#, None))), + (Th07, 108, Some(("ES", None))), // Yes, this really is a non-immediate sub id. Any fields marked as such are intentional! (Th07, 109, Some(("S", None))), (Th07, 110, Some(("S", None))), (Th07, 111, Some(("S", None))), @@ -368,29 +370,29 @@ static ECL_07: &'static CoreSignatures = &CoreSignatures { (Th07, 113, Some(("E", None))), (Th07, 114, Some(("S", None))), (Th07, 115, Some(("E", None))), - (Th07, 116, Some(("U", None))), // zero: b--- - (Th07, 117, Some(("SUC", None))), - (Th07, 118, Some(("SUCfff", None))), + (Th07, 116, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th07, 117, Some(("SUC", None))), // Third argument is read from a pointer for some reason... + (Th07, 118, Some(("SUCfff", None))), // Also read as a pointer (Th07, 119, Some(("S", None))), - (Th07, 120, Some(("U", None))), // zero: b--- - (Th07, 121, Some(("SS", None))), - (Th07, 122, Some(("SS", None))), + (Th07, 120, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th07, 121, Some(("SS(imm)", None))), // zero: Sv + (Th07, 122, Some(("SS(imm)", None))), // zero: Sv (Th07, 123, Some(("S", None))), (Th07, 124, Some(("S", None))), (Th07, 125, Some(("S", None))), (Th07, 126, Some(("S", None))), - (Th07, 127, Some(("", None))), + (Th07, 127, Some(("S", None))), (Th07, 128, Some(("S", None))), - (Th07, 129, Some(("SS", None))), - (Th07, 130, Some(("U", None))), // zero: b--- + (Th07, 129, Some(("S(imm)s(imm)--", None))), + (Th07, 130, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- (Th07, 131, Some(("ffSSSS", None))), - (Th07, 132, Some(("U", None))), // zero: b--- + (Th07, 132, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- (Th07, 133, Some(("", None))), (Th07, 134, Some(("", None))), - (Th07, 135, Some(("U", None))), // zero: b--- - (Th07, 136, Some(("U", None))), // zero: b--- - (Th07, 137, Some(("U", None))), // zero: b--- - (Th07, 138, Some(("USSS", None))), // zero: b---SSS + (Th07, 135, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th07, 136, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th07, 137, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th07, 138, Some(("b(imm;hex)---SSS", None))), (Th07, 139, Some(("SSSC", None))), (Th07, 140, Some(("ffff", None))), (Th07, 141, Some(("S", None))), // Not implemented @@ -401,19 +403,19 @@ static ECL_07: &'static CoreSignatures = &CoreSignatures { (Th07, 146, Some(("", None))), (Th07, 147, Some(("S", None))), (Th07, 148, Some(("SSE", None))), - (Th07, 149, Some(("Ufff", None))), + (Th07, 149, Some((r#"U(enum="bool")fff"#, None))), // zero: U(enum="BitBool")fff (Th07, 150, Some(("f", None))), (Th07, 151, Some(("ffff", None))), (Th07, 152, Some(("Sf", None))), (Th07, 153, Some(("fff", None))), (Th07, 154, Some(("S", None))), (Th07, 155, Some(("f", None))), - (Th07, 156, Some(("SU", None))), + (Th07, 156, Some((r#"SU(enum="bool")"#, None))), (Th07, 157, Some(("Sf", None))), (Th07, 158, Some(("Sff", None))), (Th07, 159, Some(("ffff", None))), (Th07, 160, Some(("S", None))), - (Th07, 161, Some(("U", None))), + (Th07, 161, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") ], var: &[ (Th07, 10000, Some("$")), @@ -548,7 +550,7 @@ static ECL_08_09: &'static CoreSignatures = &CoreSignatures { (Th08, 49, Some(("ffto", Some(IKind::CondJmp(B::Gt, Ty::Float))))), (Th08, 50, Some(("SSto", Some(IKind::CondJmp(B::Ge, Ty::Int))))), (Th08, 51, Some(("ffto", Some(IKind::CondJmp(B::Ge, Ty::Float))))), - (Th08, 52, Some(("E", Some(IKind::CallReg)))), + (Th08, 52, Some(("E(imm)", Some(IKind::CallReg)))), (Th08, 53, Some(("", None))), // Some(IKind::Return) (Th08, 54, Some(("N", None))), (Th08, 55, Some(("N", None))), @@ -575,110 +577,110 @@ static ECL_08_09: &'static CoreSignatures = &CoreSignatures { (Th08, 76, Some(("", None))), (Th08, 77, Some(("ff", None))), (Th08, 78, Some(("ff", None))), - (Th08, 79, Some(("U", None))), - (Th08, 80, Some(("U", None))), - (Th08, 81, Some(("U", None))), + (Th08, 79, Some(("U(hex)", None))), + (Th08, 80, Some(("U(hex)", None))), + (Th08, 81, Some(("U(hex)", None))), (Th08, 82, Some(("f", None))), - (Th08, 83, Some(("U", None))), + (Th08, 83, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") (Th08, 86, Some(("SSS", None))), (Th08, 87, Some(("ffS", None))), - (Th08, 88, Some(("SE", None))), + (Th08, 88, Some(("SE(imm)", None))), (Th08, 89, Some(("SS", None))), - (Th08, 90, Some(("EffSSS", None))), - (Th08, 91, Some(("EffSSS", None))), - (Th08, 92, Some(("EffSSS", None))), - (Th08, 93, Some(("EfffSSS", None))), - (Th08, 94, Some(("EfffSSS", None))), + (Th08, 90, Some(("E(imm)ffSSS", None))), + (Th08, 91, Some(("E(imm)ffSSS", None))), + (Th08, 92, Some(("E(imm)ffSSS", None))), + (Th08, 93, Some(("E(imm)fffSSS", None))), + (Th08, 94, Some(("E(imm)fffSSS", None))), (Th08, 95, Some(("", None))), - (Th08, 96, Some(("ssSSffffS", None))), - (Th08, 97, Some(("ssSSffffS", None))), - (Th08, 98, Some(("ssSSffffS", None))), - (Th08, 99, Some(("ssSSffffS", None))), - (Th08, 100, Some(("ssSSffffS", None))), - (Th08, 101, Some(("ssSSffffS", None))), - (Th08, 102, Some(("ssSSffffS", None))), - (Th08, 103, Some(("ssSSffffS", None))), - (Th08, 104, Some(("ssSSffffS", None))), + (Th08, 96, Some(("ssSSffffU(imm;hex)", None))), + (Th08, 97, Some(("ssSSffffU(imm;hex)", None))), + (Th08, 98, Some(("ssSSffffU(imm;hex)", None))), + (Th08, 99, Some(("ssSSffffU(imm;hex)", None))), + (Th08, 100, Some(("ssSSffffU(imm;hex)", None))), + (Th08, 101, Some(("ssSSffffU(imm;hex)", None))), + (Th08, 102, Some(("ssSSffffU(imm;hex)", None))), + (Th08, 103, Some(("ssSSffffU(imm;hex)", None))), + (Th08, 104, Some(("ssSSffffU(imm;hex)", None))), (Th08, 105, Some(("S", None))), (Th08, 106, Some(("S", None))), (Th08, 107, Some(("", None))), (Th08, 108, Some(("", None))), (Th08, 109, Some(("", None))), (Th08, 110, Some(("ff", None))), - (Th08, 111, Some(("SSUSSff", None))), + (Th08, 111, Some((r#"SU(hex)U(enum="bool")SSff"#, None))), (Th08, 112, Some(("", None))), (Th08, 113, Some(("SS", None))), - (Th08, 114, Some(("ssffffffSSSSSS", None))), - (Th08, 115, Some(("ssffffffSSSSSS", None))), + (Th08, 114, Some(("s(imm)sffffffSSSS(imm)S(imm)U(imm;hex)", None))), + (Th08, 115, Some(("s(imm)sffffffSSSS(imm)S(imm)U(imm;hex)", None))), (Th08, 116, Some(("S", None))), (Th08, 117, Some(("Sf", None))), (Th08, 118, Some(("Sf", None))), (Th08, 119, Some(("Sfff", None))), (Th08, 120, Some(("S", None))), (Th08, 121, Some(("S", None))), - (Th08, 122, Some(("suSm(len=48;mask=0xaa,0,0)m(len=48;mask=0xbb,0,0)m(len=64;nulless;mask=0xdd,0,0)m(len=64;nulless;mask=0xee,0,0)", None))), + (Th08, 122, Some(("s(imm)u(imm)S(imm)m(len=48;mask=0xaa,0,0)m(len=48;mask=0xbb,0,0)m(len=64;nulless;mask=0xdd,0,0)m(len=64;nulless;mask=0xee,0,0)", None))), (Th08, 123, Some(("", None))), (Th08, 124, Some(("S", None))), (Th08, 125, Some(("S", None))), (Th08, 126, Some(("ES", None))), (Th08, 127, Some(("S", None))), - (Th08, 128, Some(("Sffff", None))), - (Th08, 129, Some(("U", None))), // zero: b--- - (Th08, 130, Some(("E", None))), // zero: s(enum="EclSub")-- + (Th08, 128, Some(("S(imm)f(imm)f(imm)f(imm)f(imm)", None))), // Argument 1 is unread + (Th08, 129, Some(("b(imm)---", None))), + (Th08, 130, Some((r#"s(imm;enum="EclSub")--"#, None))), (Th08, 131, Some(("S", None))), (Th08, 132, Some(("S", None))), (Th08, 133, Some(("SSE", None))), (Th08, 134, Some(("SE", None))), (Th08, 135, Some(("SE", None))), // Some(IKind::CallRegAsync) - (Th08, 136, Some(("SS", None))), - (Th08, 137, Some(("SS", None))), - (Th08, 138, Some(("U", None))), // zero: bbb- - (Th08, 139, Some(("SUC", None))), - (Th08, 140, Some(("SUCfff", None))), + (Th08, 136, Some(("SS(imm)", None))), // zero: Sv + (Th08, 137, Some(("SS(imm)", None))), // zero: Sv + (Th08, 138, Some(("c(imm)b(imm)b(imm)-", None))), + (Th08, 139, Some(("SUC", None))), // Third argument is read from a pointer for some reason... + (Th08, 140, Some(("SUCfff", None))), // Also read as a pointer (Th08, 141, Some(("S", None))), (Th08, 142, Some(("S", None))), (Th08, 143, Some(("S", None))), (Th08, 144, Some(("SS", None))), - (Th08, 145, Some(("U", None))), // zero: b--- + (Th08, 145, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- (Th08, 146, Some(("S", None))), (Th08, 147, Some(("S", None))), (Th08, 148, Some(("S", None))), (Th08, 149, Some(("S", None))), - (Th08, 150, Some(("SS", None))), - (Th08, 151, Some(("U", None))), // zero: b--- + (Th08, 150, Some(("S(imm)s(imm)--", None))), + (Th08, 151, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- (Th08, 152, Some(("ffSSSS", None))), (Th08, 153, Some(("", None))), (Th08, 154, Some(("", None))), - (Th08, 155, Some(("U", None))), // zero: b--- - (Th08, 156, Some(("U", None))), // zero: b--- - (Th08, 157, Some(("USSS", None))), // zero: b---SSS + (Th08, 155, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th08, 156, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th08, 157, Some(("b(imm;hex)---SSS", None))), (Th08, 158, Some(("SSSC", None))), (Th08, 159, Some(("U", None))), (Th08, 160, Some(("S", None))), (Th08, 161, Some(("f", None))), (Th08, 162, Some(("", None))), (Th08, 163, Some(("S", None))), - (Th08, 164, Some(("Ufff", None))), + (Th08, 164, Some((r#"U(enum="bool")fff"#, None))), // zero: U(enum="BitBool")fff (Th08, 165, Some(("f", None))), (Th08, 166, Some(("ffff", None))), (Th08, 167, Some(("Sf", None))), (Th08, 168, Some(("S", None))), (Th08, 169, Some(("f", None))), - (Th08, 170, Some(("SU", None))), + (Th08, 170, Some((r#"SU(enum="bool")"#, None))), (Th08, 171, Some(("Sf", None))), (Th08, 172, Some(("Sff", None))), - (Th08, 173, Some(("U", None))), + (Th08, 173, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") (Th08, 174, Some(("S", None))), (Th08, 175, Some(("U", None))), - (Th08, 176, Some(("S", None))), + (Th08, 176, Some((r#"b(imm;enum="bool")---"#, None))), // Argument is never read, so this is just to try and make it look better in the output (Th08, 177, Some(("S", None))), (Th08, 178, Some(("SSf", None))), (Th08, 179, Some(("", None))), (Th08, 180, Some(("", None))), (Th08, 181, Some(("", None))), - (Th08, 182, Some(("U", None))), - (Th08, 183, Some(("U", None))), - (Th08, 184, Some(("U", None))), + (Th08, 182, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") + (Th08, 183, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") + (Th08, 184, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") (Th09, 83, None), (Th09, 90, None), diff --git a/src/core_mapfiles/msg.rs b/src/core_mapfiles/msg.rs index fb529dd..f74c0af 100644 --- a/src/core_mapfiles/msg.rs +++ b/src/core_mapfiles/msg.rs @@ -26,19 +26,19 @@ static MSG_06_09: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th06, 0, Some(("", None))), - (Th06, 1, Some(("ss", None))), - (Th06, 2, Some(("ss", None))), // note: 2nd word is technically an anm sprite + (Th06, 1, Some((r#"ss(enum="AnmScript")"#, None))), + (Th06, 2, Some((r#"ss(enum="AnmSprite")"#, None))), (Th06, 3, Some(("ssz(bs=4)", None))), (Th06, 4, Some(("S", None))), - (Th06, 5, Some(("ss", None))), + (Th06, 5, Some(("sb-", None))), (Th06, 6, Some(("", None))), (Th06, 7, Some(("S", None))), (Th06, 8, Some(("ssz(bs=4)", None))), - (Th06, 9, Some(("S", None))), // arg looks unused + (Th06, 9, Some(("_", None))), (Th06, 10, Some(("", None))), (Th06, 11, Some(("", None))), (Th06, 12, Some(("", None))), - (Th06, 13, Some(("S", None))), + (Th06, 13, Some((r#"b(enum="bool")---"#, None))), (Th07, 14, Some(("", None))), diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index 1036711..120dbf9 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -61,13 +61,13 @@ static STD_07_09: &CoreSignatures = &CoreSignatures { (Th07, 26, Some(("fff", None))), (Th07, 27, Some(("fff", None))), (Th07, 28, Some(("S__", None))), - (Th07, 29, Some(("S__", None))), // anm script - (Th07, 30, Some(("S__", None))), // anm script + (Th07, 29, Some(("N__", None))), + (Th07, 30, Some(("N__", None))), (Th07, 31, Some(("S__", Some(IKind::InterruptLabel)))), (Th08, 32, Some(("fff", None))), (Th08, 33, Some(("S__", None))), - (Th08, 34, Some(("S__", None))), // anm script + (Th08, 34, Some(("N__", None))), ], var: &[], }; @@ -89,7 +89,7 @@ static STD_095_18: &CoreSignatures = &CoreSignatures { (Th095, 11, Some(("SSfffffffff", None))), (Th095, 12, Some(("S", None))), (Th095, 13, Some(("C", None))), - (Th095, 14, Some(("SS", None))), // SN + (Th095, 14, Some(("SN", None))), // 15 appears to be a nop (i.e. it's not in the jumptable). // However, no game ever uses it @@ -98,7 +98,7 @@ static STD_095_18: &CoreSignatures = &CoreSignatures { (Th12, 18, Some(("SSfff", None))), - (Th14, 14, Some(("SSS", None))), // SNS. 'layer' argument added + (Th14, 14, Some(("SNS", None))), // 'layer' argument added (Th14, 19, Some(("S", None))), (Th14, 20, Some(("f", None))), diff --git a/src/llir/abi.rs b/src/llir/abi.rs index 60938f4..e6b9d4a 100644 --- a/src/llir/abi.rs +++ b/src/llir/abi.rs @@ -18,7 +18,7 @@ use ArgEncoding as Enc; /// and how to present them in a decompiled file (e.g. hexadecimal for colors). /// /// Like in thtk, signatures are derived from strings. Parse a signature using [`std::str::FromStr`]. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] pub struct InstrAbi { encodings: Vec, } @@ -31,7 +31,7 @@ pub struct InstrAbi { /// /// By this notion, [`ArgEncoding`] tends to be more relevant for immediate/literal arguments, while /// [`ScalarType`] tends to be more relevant for variables. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq)] pub enum ArgEncoding { /// `S`, `s`, or `c` in mapfile. Integer immediate or register. Displayed as signed. /// `U`, `u`, or `b` in mapfile. Integer immediate or register. Displayed as unsigned. @@ -67,7 +67,7 @@ pub enum ArgEncoding { }, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] pub enum StringArgSize { /// A string arg that uses `len=`. /// @@ -270,7 +270,7 @@ fn int_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Result= 2 { + if size.wrapping_sub(1) >= 2 { return Err(emitter.as_sized().emit(error!( message("timeline arg0 must be word-sized or less ('s', 'u', 'c', or 'b')"), primary(arg0_flag, ""), diff --git a/tests/integration/general.rs b/tests/integration/general.rs index 34ec21e..55964ac 100644 --- a/tests/integration/general.rs +++ b/tests/integration/general.rs @@ -190,7 +190,7 @@ source_test!( ECL_06, const_cast_even_in_eosd, main_body: r#" const int x = int(2.0 + 3.0); - ins_1(x); + ins_61(x); "#, check_compiled: |output, format| { let ecl = output.read_ecl(format); From 7fe31f456de29f3b2c914caec28cd196795b384e Mon Sep 17 00:00:00 2001 From: zero318 Date: Fri, 1 Jul 2022 23:30:20 -0400 Subject: [PATCH 06/26] Second batch of updated signatures --- src/core_mapfiles/anm.rs | 24 ++++++++++++++---------- src/core_mapfiles/msg.rs | 6 +++--- src/core_mapfiles/std.rs | 2 +- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/core_mapfiles/anm.rs b/src/core_mapfiles/anm.rs index 2852498..30864f4 100644 --- a/src/core_mapfiles/anm.rs +++ b/src/core_mapfiles/anm.rs @@ -171,17 +171,21 @@ static ANM_INS_07_09: &'static CoreSignatures = &CoreSignatures { (Th07, 81, Some(("f", None))), // v3 - // color instructions changed to take 3 dwords - (Th08, 9, Some(("SSS", None))), - (Th08, 33, Some(("SSSSS", None))), + // alpha/color/alphaTime/colorTime instructions changed to take dword variables + // alphaTimeLinear not updated + (Th08, 8, Some(("C", None))), + (Th08, 9, Some(("CCC", None))), + (Th08, 16, Some((r#"U(imm;enum="bool")"#, None))), + (Th08, 33, Some(("Sb(imm)---CCC", None))), + (Th08, 34, Some(("Sb(imm)---C", None))), // new instructions - (Th08, 82, Some(("S", None))), - (Th08, 83, Some(("S", None))), - (Th08, 84, Some(("SSS", None))), - (Th08, 85, Some(("S", None))), - (Th08, 86, Some(("SSSSS", None))), - (Th08, 87, Some(("SSS", None))), - (Th08, 88, Some(("S", None))), + (Th08, 82, Some(("U(imm)", None))), + (Th08, 83, Some(("S(imm)", None))), + (Th08, 84, Some(("CCC", None))), + (Th08, 85, Some(("C", None))), + (Th08, 86, Some(("Sb(imm)---CCC", None))), + (Th08, 87, Some(("Sb(imm)---C", None))), + (Th08, 88, Some((r#"-b(imm;enum="bool")--"#, None))), // zero: -b(imm;enum="BitBool")-- (Th08, 89, Some(("", None))), ], var: &[], diff --git a/src/core_mapfiles/msg.rs b/src/core_mapfiles/msg.rs index f74c0af..8dd96db 100644 --- a/src/core_mapfiles/msg.rs +++ b/src/core_mapfiles/msg.rs @@ -44,10 +44,10 @@ static MSG_06_09: &CoreSignatures = &CoreSignatures { (Th08, 3, Some(("ssm(bs=4;mask=0x77,0,0)", None))), (Th08, 8, Some(("ssm(bs=4;mask=0x77,0,0)", None))), - (Th08, 15, Some(("SSSSS", None))), // Snnnn + (Th08, 15, Some(("Unnnn", None))), (Th08, 16, Some(("m(bs=4;mask=0x77,0,0)", None))), - (Th08, 17, Some(("SS", None))), // Sn - (Th08, 18, Some(("S", None))), + (Th08, 17, Some(("Un", None))), + (Th08, 18, Some((r#"b(enum="bool")---"#, None))), (Th08, 19, Some(("m(bs=4;mask=0x77,0,0)", None))), (Th08, 20, Some(("m(bs=4;mask=0x77,0,0)", None))), (Th08, 21, Some(("S", None))), diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index 120dbf9..caa7180 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -66,7 +66,7 @@ static STD_07_09: &CoreSignatures = &CoreSignatures { (Th07, 31, Some(("S__", Some(IKind::InterruptLabel)))), (Th08, 32, Some(("fff", None))), - (Th08, 33, Some(("S__", None))), + (Th08, 33, Some(("b---__", None))), (Th08, 34, Some(("N__", None))), ], var: &[], From 4d089acbd1a49a77db55c3aabc9dcfd0e09c9c4c Mon Sep 17 00:00:00 2001 From: zero318 Date: Sat, 2 Jul 2022 00:31:06 -0400 Subject: [PATCH 07/26] Add scratch registers for IN-StB and fix size arg sign --- src/formats/ecl.rs | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/formats/ecl.rs b/src/formats/ecl.rs index 6f9f0e0..d5b9364 100644 --- a/src/formats/ecl.rs +++ b/src/formats/ecl.rs @@ -1009,7 +1009,7 @@ impl LanguageHooks for OldeEclHooks { Game::Th06 => enum_map::enum_map!{ ScalarType::Int => vec![ R(-10001), R(-10002), R(-10003), R(-10004), // I0-I3 - R(-10009), R(-10010), R(-10011), R(-10012), // I4-I7 + R(-10009), R(-10010), R(-10011), R(-10012), // IC0-IC3 ], ScalarType::Float => vec![ R(-10005), R(-10006), R(-10007), R(-10008), // F0-F3 @@ -1019,23 +1019,44 @@ impl LanguageHooks for OldeEclHooks { Game::Th07 => enum_map::enum_map!{ ScalarType::Int => vec![ R(10000), R(10001), R(10002), R(10003), // I0-I3 - R(10012), R(10013), R(10014), R(10015), // I4-I7 + R(10012), R(10013), R(10014), R(10015), // IC0-IC3 + //R(10029), R(10030), R(10031), R(10032), // PARAM_A-PARAM_D ], ScalarType::Float => vec![ R(10004), R(10005), R(10006), R(10007), // F0-F3 R(10008), R(10009), R(10010), R(10011), // F4-F7 R(10072), R(10074), // F8-F9 + //R(10033), R(10034), R(10035), R(10036), // PARAM_R-PARAM_N ], ScalarType::String => vec![], }, - Game::Th08 => enum_map::enum_map!{ + Game::Th08 | Game::Th09 => enum_map::enum_map!{ ScalarType::Int => vec![ - R(10000), R(10001), R(10002), R(10003), - R(10012), R(10013), R(10014), R(10015), + R(10000), R(10001), R(10002), R(10003), // I0-I3 + R(10004), R(10005), R(10006), R(10007), // I4-I7 + R(10036), R(10037), R(10038), R(10039), // IC0-IC3 + //R(10053), R(10054), R(10055), R(10056), // PARAM_A-PARAM_D ], ScalarType::Float => vec![ - R(10004), R(10005), R(10006), R(10007), - R(10008), R(10009), R(10010), R(10011), + R(10016), R(10017), R(10018), R(10019), // F0-F3 + R(10020), R(10021), R(10022), R(10023), // F4-F7 + R(10094), R(10095), // F8-F9 + //R(10057), R(10058), R(10059), R(10060), // PARAM_R-PARAM_N + ], + ScalarType::String => vec![], + }, + Game::Th095 => enum_map::enum_map!{ + ScalarType::Int => vec![ + R(10000), R(10001), R(10002), R(10003), // I0-I3 + R(10004), R(10005), R(10006), R(10007), // I4-I7 + R(10020), R(10021), R(10022), R(10023), // IC0-IC3 + //R(10036), R(10037), R(10038), R(10039), // PARAM_A-PARAM_D + ], + ScalarType::Float => vec![ + R(10008), R(10009), R(10010), R(10011), // F0-F3 + R(10012), R(10013), R(10014), R(10015), // F4-F7 + R(10077), R(10078), R(10079), R(10080), // F8-F11 + //R(10040), R(10041), R(10042), R(10043), // PARAM_R-PARAM_N ], ScalarType::String => vec![], }, @@ -1082,7 +1103,7 @@ impl InstrFormat for OldeEclHooks { fn read_instr(&self, f: &mut BinReader, emitter: &dyn Emitter) -> ReadResult { let time = f.read_i32()?; let opcode = f.read_u16()?; - let size = f.read_u16()? as usize; + let size = f.read_i16()? as usize; let before_difficulty = f.read_u8()?; // according to zero, not referenced in any game let difficulty = f.read_u8()?; let param_mask = f.read_u16()?; @@ -1116,7 +1137,7 @@ impl InstrFormat for OldeEclHooks { fn write_instr(&self, f: &mut BinWriter, _: &dyn Emitter, instr: &RawInstr) -> WriteResult { f.write_i32(instr.time)?; f.write_u16(instr.opcode)?; - f.write_u16(self.instr_size(instr) as _)?; + f.write_i16(self.instr_size(instr) as _)?; f.write_u8(0)?; f.write_u8(instr.difficulty)?; @@ -1132,7 +1153,7 @@ impl InstrFormat for OldeEclHooks { fn write_terminal_instr(&self, f: &mut BinWriter, _: &dyn Emitter) -> WriteResult { f.write_i32(-1)?; // time f.write_i16(-1)?; // opcode - f.write_u16(self.instr_header_size() as _)?; // size + f.write_i16(self.instr_header_size() as _)?; // size f.write_u16(0xff00)?; // difficulty f.write_u16(0x00ff)?; // param_mask Ok(()) @@ -1168,7 +1189,7 @@ impl InstrFormat for TimelineFormat06 { } let opcode = f.read_u16()?; - let size = f.read_u16()? as usize; + let size = f.read_i16()? as usize; let args_size = size.checked_sub(self.instr_header_size()).ok_or_else(|| { emitter.as_sized().emit(error!("bad instruction size ({} < {})", size, self.instr_header_size())) From 9605ae3d00a497be765298c6ab1043f538753e59 Mon Sep 17 00:00:00 2001 From: zero318 Date: Sun, 3 Jul 2022 19:50:22 -0400 Subject: [PATCH 08/26] Third batch of updated signatures --- src/core_mapfiles/anm.rs | 59 ++++++++++++++++-------------- src/core_mapfiles/ecl.rs | 77 ++++++++++++++++++++-------------------- src/core_mapfiles/msg.rs | 7 ++-- src/core_mapfiles/std.rs | 12 +++---- 4 files changed, 82 insertions(+), 73 deletions(-) diff --git a/src/core_mapfiles/anm.rs b/src/core_mapfiles/anm.rs index 30864f4..3d8fb8f 100644 --- a/src/core_mapfiles/anm.rs +++ b/src/core_mapfiles/anm.rs @@ -86,7 +86,7 @@ static ANM_INS_06: &'static CoreSignatures = &CoreSignatures { static ANM_INS_07_09: &'static CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ - // v2 + // v2 (PCB) (Th07, 0, Some(("", None))), (Th07, 1, Some(("", None))), (Th07, 2, Some(("", None))), @@ -170,7 +170,7 @@ static ANM_INS_07_09: &'static CoreSignatures = &CoreSignatures { (Th07, 80, Some(("f", None))), (Th07, 81, Some(("f", None))), - // v3 + // v3, v3b (IN, PoFV) // alpha/color/alphaTime/colorTime instructions changed to take dword variables // alphaTimeLinear not updated (Th08, 8, Some(("C", None))), @@ -185,7 +185,7 @@ static ANM_INS_07_09: &'static CoreSignatures = &CoreSignatures { (Th08, 85, Some(("C", None))), (Th08, 86, Some(("Sb(imm)---CCC", None))), (Th08, 87, Some(("Sb(imm)---C", None))), - (Th08, 88, Some((r#"-b(imm;enum="bool")--"#, None))), // zero: -b(imm;enum="BitBool")-- + (Th08, 88, Some(("-b(imm)--", None))), (Th08, 89, Some(("", None))), ], var: &[], @@ -195,6 +195,7 @@ static ANM_INS_07_09: &'static CoreSignatures = &CoreSignatures { static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ + // v4 (StB) (Th095, 0, Some(("", None))), (Th095, 1, Some(("", None))), (Th095, 2, Some(("", None))), @@ -246,43 +247,43 @@ static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { (Th095, 48, Some(("fff", None))), (Th095, 49, Some(("fff", None))), (Th095, 50, Some(("ff", None))), - (Th095, 51, Some(("S", None))), - (Th095, 52, Some(("SSS", None))), + (Th095, 51, Some(("C", None))), + (Th095, 52, Some(("CCC", None))), (Th095, 53, Some(("fff", None))), (Th095, 54, Some(("ff", None))), - (Th095, 55, Some(("SS", None))), - (Th095, 56, Some(("SSfff", None))), - (Th095, 57, Some(("SSSSS", None))), - (Th095, 58, Some(("SSS", None))), - (Th095, 59, Some(("SSfff", None))), - (Th095, 60, Some(("SSff", None))), + (Th095, 55, Some(("b(imm;hex)---S", None))), + (Th095, 56, Some(("Sb(imm)---fff", None))), + (Th095, 57, Some(("Sb(imm)---CCC", None))), + (Th095, 58, Some(("Sb(imm)---C", None))), + (Th095, 59, Some(("Sb(imm)---fff", None))), + (Th095, 60, Some(("Sb(imm)---ff", None))), (Th095, 61, Some(("", None))), (Th095, 62, Some(("", None))), (Th095, 63, Some(("", None))), - (Th095, 64, Some(("S", Some(IKind::InterruptLabel)))), - (Th095, 65, Some(("ss", None))), - (Th095, 66, Some(("S", None))), - (Th095, 67, Some(("S", None))), - (Th095, 68, Some(("S", None))), + (Th095, 64, Some(("S(imm)", Some(IKind::InterruptLabel)))), + (Th095, 65, Some(("u(imm)u(imm)", None))), + (Th095, 66, Some(("U(imm)", None))), + (Th095, 67, Some(("U(imm)", None))), + (Th095, 68, Some(("b(imm)---", None))), (Th095, 69, Some(("", None))), (Th095, 70, Some(("f", None))), (Th095, 71, Some(("f", None))), - (Th095, 72, Some(("S", None))), - (Th095, 73, Some(("S", None))), - (Th095, 74, Some(("S", None))), + (Th095, 72, Some((r#"U(imm;enum="bool")"#, None))), // zero: U(imm;enum="BitBool") + (Th095, 73, Some((r#"U(imm;enum="bool")"#, None))), // zero: U(imm;enum="BitBool") + (Th095, 74, Some((r#"U(imm;enum="bool")"#, None))), // zero: U(imm;enum="BitBool") (Th095, 75, Some(("S", None))), (Th095, 76, Some(("SSS", None))), (Th095, 77, Some(("S", None))), (Th095, 78, Some(("SSSSS", None))), (Th095, 79, Some(("SSS", None))), - (Th095, 80, Some(("S", None))), + (Th095, 80, Some(("b(imm)---", None))), (Th095, 81, Some(("", None))), - (Th095, 82, Some(("S", None))), + (Th095, 82, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- (Th095, 83, Some(("", None))), (Th095, 84, Some(("S", None))), - (Th095, 85, Some(("S", None))), - (Th095, 86, Some(("S", None))), - (Th095, 87, Some(("S", None))), + (Th095, 85, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th095, 86, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") + (Th095, 87, Some(("b(imm)---", None))), (Th10, 88, Some(("N", None))), (Th10, 89, Some(("S", None))), @@ -477,6 +478,7 @@ static ANM_VAR: &'static CoreSignatures = &CoreSignatures { inherit: &[], ins: &[], var: &[ + // v2, v3 (PCB, IN) (Th07, 10000, Some("$")), (Th07, 10001, Some("$")), (Th07, 10002, Some("$")), @@ -488,9 +490,12 @@ static ANM_VAR: &'static CoreSignatures = &CoreSignatures { (Th07, 10008, Some("$")), (Th07, 10009, Some("$")), - (Th095, 10010, Some("%")), - (Th095, 10011, Some("%")), - (Th095, 10012, Some("%")), + // v3b (PoFV) + (Th09, 10010, Some("%")), + (Th09, 10011, Some("%")), + (Th09, 10012, Some("%")), + + // v4 (StB) (Th095, 10013, Some("%")), (Th095, 10014, Some("%")), (Th095, 10015, Some("%")), diff --git a/src/core_mapfiles/ecl.rs b/src/core_mapfiles/ecl.rs index 8f2c77c..9c9c227 100644 --- a/src/core_mapfiles/ecl.rs +++ b/src/core_mapfiles/ecl.rs @@ -72,6 +72,7 @@ static TIMELINE: &'static CoreSignatures = &CoreSignatures { (Th09, 9, None), (Th09, 17, Some(("EffSSS", None))), + (Th095, 7, None), (Th095, 13, None), (Th095, 14, None), (Th095, 16, None), @@ -671,7 +672,7 @@ static ECL_08_09: &'static CoreSignatures = &CoreSignatures { (Th08, 172, Some(("Sff", None))), (Th08, 173, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") (Th08, 174, Some(("S", None))), - (Th08, 175, Some(("U", None))), + (Th08, 175, Some((r#"U(enum="bool")"#, None))), (Th08, 176, Some((r#"b(imm;enum="bool")---"#, None))), // Argument is never read, so this is just to try and make it look better in the output (Th08, 177, Some(("S", None))), (Th08, 178, Some(("SSf", None))), @@ -699,9 +700,9 @@ static ECL_08_09: &'static CoreSignatures = &CoreSignatures { (Th09, 180, None), (Th09, 181, None), (Th09, 184, None), - (Th09, 185, Some(("U", None))), + (Th09, 185, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") (Th09, 186, Some(("", None))), - (Th09, 187, Some(("U", None))), + (Th09, 187, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") ], var: &[ (Th08, 10000, Some("$")), @@ -870,7 +871,7 @@ static ECL_095: &'static CoreSignatures = &CoreSignatures { (Th095, 49, Some(("ffto", Some(IKind::CondJmp(B::Gt, Ty::Float))))), (Th095, 50, Some(("SSto", Some(IKind::CondJmp(B::Ge, Ty::Int))))), (Th095, 51, Some(("ffto", Some(IKind::CondJmp(B::Ge, Ty::Float))))), - (Th095, 52, Some(("E", Some(IKind::CallReg)))), + (Th095, 52, Some(("E(imm)", Some(IKind::CallReg)))), (Th095, 53, Some(("", None))), // Some(IKind::Return) (Th095, 54, Some(("N", None))), (Th095, 55, Some(("N", None))), @@ -895,29 +896,29 @@ static ECL_095: &'static CoreSignatures = &CoreSignatures { (Th095, 76, Some(("", None))), (Th095, 77, Some(("ff", None))), (Th095, 78, Some(("ff", None))), - (Th095, 79, Some(("U", None))), - (Th095, 80, Some(("U", None))), - (Th095, 81, Some(("U", None))), + (Th095, 79, Some(("U(hex)", None))), + (Th095, 80, Some(("U(hex)", None))), + (Th095, 81, Some(("U(hex)", None))), (Th095, 82, Some(("f", None))), - (Th095, 83, Some(("E", None))), - (Th095, 84, Some(("Eff", None))), + (Th095, 83, Some(("E(imm)", None))), + (Th095, 84, Some(("E(imm)fff", None))), (Th095, 85, Some(("", None))), - (Th095, 86, Some(("ssSSffffS", None))), - (Th095, 87, Some(("ssSSffffS", None))), - (Th095, 88, Some(("ssSSffffS", None))), - (Th095, 89, Some(("ssSSffffS", None))), - (Th095, 90, Some(("ssSSffffS", None))), - (Th095, 91, Some(("ssSSffffS", None))), - (Th095, 92, Some(("ssSSffffS", None))), - (Th095, 93, Some(("ssSSffffS", None))), - (Th095, 94, Some(("ssSSffffS", None))), + (Th095, 86, Some(("ssSSffffU(imm;hex)", None))), + (Th095, 87, Some(("ssSSffffU(imm;hex)", None))), + (Th095, 88, Some(("ssSSffffU(imm;hex)", None))), + (Th095, 89, Some(("ssSSffffU(imm;hex)", None))), + (Th095, 90, Some(("ssSSffffU(imm;hex)", None))), + (Th095, 91, Some(("ssSSffffU(imm;hex)", None))), + (Th095, 92, Some(("ssSSffffU(imm;hex)", None))), + (Th095, 93, Some(("ssSSffffU(imm;hex)", None))), + (Th095, 94, Some(("ssSSffffU(imm;hex)", None))), (Th095, 95, Some(("S", None))), (Th095, 96, Some(("S", None))), (Th095, 97, Some(("", None))), (Th095, 98, Some(("", None))), (Th095, 99, Some(("", None))), (Th095, 100, Some(("ff", None))), - (Th095, 101, Some(("SSUSSff", None))), + (Th095, 101, Some((r#"SU(hex)U(enum="bool")SSff"#, None))), (Th095, 102, Some(("", None))), (Th095, 103, Some(("SS", None))), (Th095, 104, Some(("m(len=48;mask=0xaa,0,0)", None))), @@ -926,47 +927,47 @@ static ECL_095: &'static CoreSignatures = &CoreSignatures { (Th095, 107, Some(("S", None))), (Th095, 108, Some(("ES", None))), (Th095, 109, Some(("S", None))), - (Th095, 112, Some(("E", None))), // zero: s(enum="EclSub")-- + (Th095, 112, Some((r#"s(imm;enum="EclSub")--"#, None))), (Th095, 113, Some(("S", None))), (Th095, 114, Some(("S", None))), (Th095, 115, Some(("SSE", None))), (Th095, 116, Some(("SE", None))), (Th095, 117, Some(("SE", None))), // Some(IKind::CallRegAsync) - (Th095, 118, Some(("S", None))), - (Th095, 119, Some(("S", None))), - (Th095, 120, Some(("U", None))), // zero: b--- + (Th095, 118, Some(("S", None))), // zero: Sv + (Th095, 119, Some(("S", None))), // zero: Sv + (Th095, 120, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- (Th095, 121, Some(("S", None))), (Th095, 124, Some(("S", None))), - (Th095, 126, Some(("U", None))), // zero: b--- + (Th095, 126, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- (Th095, 128, Some(("", None))), - (Th095, 130, Some(("U", None))), // zero: b--- - (Th095, 131, Some(("USSS", None))), // zero: b---SSS - (Th095, 132, Some(("S", None))), + (Th095, 130, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th095, 131, Some(("b(imm;hex)---SSS", None))), + (Th095, 132, Some(("U", None))), (Th095, 133, Some(("S", None))), (Th095, 135, Some(("f", None))), (Th095, 136, Some(("ffff", None))), (Th095, 137, Some(("f", None))), - (Th095, 138, Some(("U", None))), // zero: b--- + (Th095, 138, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") (Th095, 139, Some(("S", None))), - (Th095, 140, Some(("U", None))), // zero: b--- + (Th095, 140, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") (Th095, 141, Some(("S", None))), (Th095, 142, Some(("", None))), - (Th095, 143, Some(("US", None))), + (Th095, 143, Some((r#"U(enum="bool")S"#, None))), // zero: U(enum="BitBool")S (Th095, 144, Some(("S", None))), (Th095, 145, Some(("SSffff", None))), (Th095, 146, Some(("SSffff", None))), - (Th095, 147, Some(("SSfffSSSSfU", None))), - (Th095, 148, Some(("SSfffSSSSfU", None))), + (Th095, 147, Some(("SSfffSSSSfU(imm;hex)", None))), + (Th095, 148, Some(("SSfffSSSSfU(imm;hex)", None))), (Th095, 149, Some(("f", None))), (Th095, 150, Some(("N", None))), (Th095, 151, Some(("SN", None))), (Th095, 152, Some(("SS", None))), - (Th095, 153, Some(("SSfffSSSSfU", None))), - (Th095, 154, Some(("SSfffSSSSfU", None))), - (Th095, 155, Some(("SSfffSSSSfUff", None))), - (Th095, 156, Some(("SSfffSSSSfUff", None))), - (Th095, 157, Some(("SSfffSSSSfUff", None))), - (Th095, 158, Some(("U", None))), + (Th095, 153, Some(("SSfffSSSSfU(imm;hex)", None))), + (Th095, 154, Some(("SSfffSSSSfU(imm;hex)", None))), + (Th095, 155, Some(("SSfffSSSSfU(imm;hex)ff", None))), + (Th095, 156, Some(("SSfffSSSSfU(imm;hex)ff", None))), + (Th095, 157, Some(("SSfffSSSSfU(imm;hex)ff", None))), + (Th095, 158, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") ], var: &[ (Th095, 10000, Some("$")), diff --git a/src/core_mapfiles/msg.rs b/src/core_mapfiles/msg.rs index 8dd96db..a31814e 100644 --- a/src/core_mapfiles/msg.rs +++ b/src/core_mapfiles/msg.rs @@ -53,10 +53,13 @@ static MSG_06_09: &CoreSignatures = &CoreSignatures { (Th08, 21, Some(("S", None))), (Th08, 22, Some(("", None))), + (Th09, 1, Some(("s--", None))), (Th09, 3, Some(("ssm(bs=4;mask=0x77,7,16)", None))), (Th09, 8, Some(("", None))), - (Th09, 15, Some(("SSS", None))), + (Th09, 9, Some(("S", None))), // Can't be marked as padding since unused value is non-zero + (Th09, 15, Some(("Snn", None))), (Th09, 16, Some(("m(bs=4;mask=0x77,7,16)", None))), + (Th09, 17, Some(("Sn", None))), (Th09, 19, None), // removed from jumptable (Th09, 20, None), (Th09, 21, None), @@ -64,7 +67,7 @@ static MSG_06_09: &CoreSignatures = &CoreSignatures { (Th09, 23, Some(("S", None))), (Th09, 24, Some(("", None))), (Th09, 25, Some(("", None))), - (Th09, 26, Some(("S", None))), + (Th09, 26, Some(("b---", None))), // 27 is not in the jumptable; could be a nop, but it's never used (Th09, 28, Some(("S", None))), ], diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index caa7180..0b77094 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -78,16 +78,16 @@ static STD_095_18: &CoreSignatures = &CoreSignatures { (Th095, 0, Some(("", None))), (Th095, 1, Some(("ot", Some(IKind::Jmp)))), (Th095, 2, Some(("fff", None))), - (Th095, 3, Some(("SSfff", None))), + (Th095, 3, Some(("Sbb--fff", None))), (Th095, 4, Some(("fff", None))), - (Th095, 5, Some(("SSfff", None))), + (Th095, 5, Some(("Sbb--fff", None))), (Th095, 6, Some(("fff", None))), (Th095, 7, Some(("f", None))), (Th095, 8, Some(("Cff", None))), - (Th095, 9, Some(("SSCff", None))), - (Th095, 10, Some(("SSfffffffff", None))), - (Th095, 11, Some(("SSfffffffff", None))), - (Th095, 12, Some(("S", None))), + (Th095, 9, Some(("Sbb--Cff", None))), + (Th095, 10, Some(("SUfffffffff", None))), + (Th095, 11, Some(("SUfffffffff", None))), + (Th095, 12, Some(("b---", None))), (Th095, 13, Some(("C", None))), (Th095, 14, Some(("SN", None))), // 15 appears to be a nop (i.e. it's not in the jumptable). From 5ff6724d4ff5f9b3c140712367b5d9f98f51425d Mon Sep 17 00:00:00 2001 From: zero318 Date: Mon, 4 Jul 2022 22:33:25 -0400 Subject: [PATCH 09/26] Fourth batch of updated signatures --- src/core_mapfiles/anm.rs | 6 +++++- src/core_mapfiles/msg.rs | 10 +++++----- src/core_mapfiles/std.rs | 6 ++++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/core_mapfiles/anm.rs b/src/core_mapfiles/anm.rs index 3d8fb8f..b878976 100644 --- a/src/core_mapfiles/anm.rs +++ b/src/core_mapfiles/anm.rs @@ -285,8 +285,11 @@ static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { (Th095, 86, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") (Th095, 87, Some(("b(imm)---", None))), + // v4b (MoF) + (Th10, 56, Some(("SU(imm)fff", None))), + (Th10, 59, Some(("SU(imm)fff", None))), (Th10, 88, Some(("N", None))), - (Th10, 89, Some(("S", None))), + (Th10, 89, Some((r#"U(imm;enum="bool")"#, None))), // zero: U(imm;enum="BitBool") (Th10, 90, Some(("N", None))), (Th10, 91, Some(("N", None))), (Th10, 92, Some(("N", None))), @@ -500,6 +503,7 @@ static ANM_VAR: &'static CoreSignatures = &CoreSignatures { (Th095, 10014, Some("%")), (Th095, 10015, Some("%")), + // v4b (MoF) (Th10, 10016, Some("%")), (Th10, 10017, Some("%")), (Th10, 10018, Some("%")), diff --git a/src/core_mapfiles/msg.rs b/src/core_mapfiles/msg.rs index a31814e..2df8894 100644 --- a/src/core_mapfiles/msg.rs +++ b/src/core_mapfiles/msg.rs @@ -77,19 +77,19 @@ static MSG_10_18: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th10, 0, Some(("", None))), - (Th10, 1, Some(("S", None))), // arg is unused - (Th10, 2, Some(("S", None))), // arg is unused + (Th10, 1, Some(("_", None))), + (Th10, 2, Some(("_", None))), (Th10, 3, Some(("", None))), (Th10, 4, Some(("", None))), (Th10, 5, Some(("", None))), (Th10, 6, Some(("", None))), (Th10, 7, Some(("", None))), (Th10, 8, Some(("", None))), - (Th10, 9, Some(("S", None))), + (Th10, 9, Some((r#"b(enum="bool")---"#, None))), // zero: b(enum="BitBool")--- (Th10, 10, Some(("S", None))), (Th10, 11, Some(("", None))), - (Th10, 12, Some(("S", None))), - (Th10, 13, Some(("S", None))), + (Th10, 12, Some(("N", None))), + (Th10, 13, Some(("N", None))), (Th10, 14, Some(("m(bs=4;mask=0x77,7,16)", None))), (Th10, 15, Some(("m(bs=4;mask=0x77,7,16)", None))), (Th10, 16, Some(("m(bs=4;mask=0x77,7,16)", None))), diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index 0b77094..cf55820 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -93,6 +93,12 @@ static STD_095_18: &CoreSignatures = &CoreSignatures { // 15 appears to be a nop (i.e. it's not in the jumptable). // However, no game ever uses it + (Th10, 3, Some(("SUfff", None))), + (Th10, 5, Some(("SUfff", None))), + (Th10, 9, Some(("SUCff", None))), // Technically the C arg is split into 4 individual byte reads. But why tho + (Th10, 10, Some(("S_fffffffff", None))), + (Th10, 11, Some(("S_fffffffff", None))), + (Th11, 16, Some(("S", Some(IKind::InterruptLabel)))), (Th11, 17, Some(("S", None))), From b70b2ed88dbce78b7405c477fe72bf0955572f8e Mon Sep 17 00:00:00 2001 From: zero318 Date: Wed, 6 Jul 2022 22:20:00 -0400 Subject: [PATCH 10/26] Fifth batch of updated signatures --- src/core_mapfiles/ecl.rs | 418 ++++++++++++++++++++++----------------- src/llir/raise/early.rs | 18 +- 2 files changed, 243 insertions(+), 193 deletions(-) diff --git a/src/core_mapfiles/ecl.rs b/src/core_mapfiles/ecl.rs index aba1520..2b83012 100644 --- a/src/core_mapfiles/ecl.rs +++ b/src/core_mapfiles/ecl.rs @@ -1062,191 +1062,241 @@ static ECL_095: &'static CoreSignatures = &CoreSignatures { static ECL_10: &'static CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ - (Th10, 0, Some((r#""#, None))), - (Th10, 1, Some((r#""#, None))), - (Th10, 10, Some((r#""#, None))), - // (Th10, 11, Some((r#" P(bs=4)v(rep="G") "#, None))), - (Th10, 12, Some((r#" ot "#, None))), - (Th10, 13, Some((r#" ot "#, None))), - (Th10, 14, Some((r#" ot "#, None))), - // (Th10, 15, Some((r#" P(bs=4)v(rep="G") "#, None))), - // (Th10, 16, Some((r#" P(bs=4)Sv(rep="G") "#, None))), - (Th10, 17, Some((r#" S "#, None))), - (Th10, 18, Some((r#" S "#, None))), - (Th10, 19, Some((r#" S "#, None))), - (Th10, 20, Some((r#" SS "#, None))), - (Th10, 21, Some((r#""#, None))), - // (Th10, 30, Some((r#" Pv(rep="g") "#, None))), - (Th10, 40, Some((r#" S "#, None))), - (Th10, 41, Some((r#""#, None))), - (Th10, 42, Some((r#" S "#, None))), - (Th10, 43, Some((r#" S "#, None))), - (Th10, 44, Some((r#" f "#, None))), - (Th10, 45, Some((r#" f "#, None))), - (Th10, 50, Some((r#""#, None))), - (Th10, 51, Some((r#""#, None))), - (Th10, 52, Some((r#""#, None))), - (Th10, 53, Some((r#""#, None))), - (Th10, 54, Some((r#""#, None))), - (Th10, 55, Some((r#""#, None))), - (Th10, 56, Some((r#""#, None))), - (Th10, 57, Some((r#""#, None))), - (Th10, 58, Some((r#""#, None))), - (Th10, 59, Some((r#""#, None))), - (Th10, 60, Some((r#""#, None))), - (Th10, 61, Some((r#""#, None))), - (Th10, 62, Some((r#""#, None))), - (Th10, 63, Some((r#""#, None))), - (Th10, 64, Some((r#""#, None))), - (Th10, 65, Some((r#""#, None))), - (Th10, 66, Some((r#""#, None))), - (Th10, 67, Some((r#""#, None))), - (Th10, 68, Some((r#""#, None))), - (Th10, 69, Some((r#""#, None))), - (Th10, 70, Some((r#""#, None))), - (Th10, 71, Some((r#""#, None))), - (Th10, 72, Some((r#""#, None))), - (Th10, 73, Some((r#""#, None))), - (Th10, 74, Some((r#""#, None))), - (Th10, 75, Some((r#""#, None))), - (Th10, 76, Some((r#""#, None))), - (Th10, 77, Some((r#""#, None))), - (Th10, 78, Some((r#" S "#, None))), - (Th10, 79, Some((r#""#, None))), - (Th10, 80, Some((r#""#, None))), - (Th10, 81, Some((r#" ffff "#, None))), - (Th10, 82, Some((r#" f "#, None))), - (Th10, 83, Some((r#" S "#, None))), - (Th10, 84, Some((r#""#, None))), - (Th10, 85, Some((r#""#, None))), - (Th10, 86, Some((r#" fff "#, None))), - (Th10, 87, Some((r#" ffff "#, None))), - (Th10, 256, Some((r#" P(bs=4)ffSSS "#, None))), - (Th10, 257, Some((r#" P(bs=4)ffSSS "#, None))), - (Th10, 258, Some((r#" S "#, None))), - (Th10, 259, Some((r#" SN "#, None))), - (Th10, 260, Some((r#" P(bs=4)ffSSS "#, None))), - (Th10, 261, Some((r#" P(bs=4)ffSSS "#, None))), - (Th10, 262, Some((r#" SN "#, None))), - (Th10, 263, Some((r#" SN "#, None))), - (Th10, 264, Some((r#" SN "#, None))), - (Th10, 265, Some((r#" P(bs=4)ffSSS "#, None))), - (Th10, 266, Some((r#" P(bs=4)ffSSS "#, None))), - (Th10, 267, Some((r#" P(bs=4)ffSSS "#, None))), - (Th10, 268, Some((r#" P(bs=4)ffSSS "#, None))), - (Th10, 269, Some((r#" N "#, None))), - (Th10, 270, Some((r#" P(bs=4)fffSSS "#, None))), - (Th10, 271, Some((r#" P(bs=4)fffSSS "#, None))), - (Th10, 272, Some((r#" SN "#, None))), - (Th10, 273, Some((r#" SNf "#, None))), - (Th10, 280, Some((r#" ff "#, None))), - (Th10, 281, Some((r#" SSff "#, None))), - (Th10, 282, Some((r#" ff "#, None))), - (Th10, 283, Some((r#" SSff "#, None))), - (Th10, 284, Some((r#" ff "#, None))), - (Th10, 285, Some((r#" SSff "#, None))), - (Th10, 286, Some((r#" ff "#, None))), - (Th10, 287, Some((r#" SSff "#, None))), - (Th10, 288, Some((r#" ffff "#, None))), - (Th10, 289, Some((r#" SSffff "#, None))), - (Th10, 290, Some((r#" ffff "#, None))), - (Th10, 291, Some((r#" SSffff "#, None))), - (Th10, 292, Some((r#" SSf "#, None))), - (Th10, 293, Some((r#" SSf "#, None))), - (Th10, 294, Some((r#""#, None))), - (Th10, 295, Some((r#""#, None))), - (Th10, 296, Some((r#" fff "#, None))), - (Th10, 297, Some((r#" fff "#, None))), - (Th10, 298, Some((r#" ff "#, None))), - (Th10, 299, Some((r#" ff "#, None))), - (Th10, 320, Some((r#" ff "#, None))), - (Th10, 321, Some((r#" ff "#, None))), - (Th10, 322, Some((r#" S "#, None))), - (Th10, 323, Some((r#" S "#, None))), - (Th10, 324, Some((r#" ffff "#, None))), - (Th10, 325, Some((r#""#, None))), - (Th10, 326, Some((r#""#, None))), - (Th10, 327, Some((r#" SS "#, None))), - (Th10, 328, Some((r#" ff "#, None))), - (Th10, 329, Some((r#""#, None))), - (Th10, 330, Some((r#" S "#, None))), - (Th10, 331, Some((r#" S "#, None))), - (Th10, 332, Some((r#" S "#, None))), - (Th10, 333, Some((r#""#, None))), - (Th10, 334, Some((r#" SSSP(bs=4) "#, None))), - (Th10, 335, Some((r#" S "#, None))), - (Th10, 336, Some((r#" S "#, None))), - (Th10, 337, Some((r#" SSS "#, None))), - // (Th10, 338, Some((r#" M "#, None))), - (Th10, 339, Some((r#""#, None))), - (Th10, 340, Some((r#""#, None))), - (Th10, 341, Some((r#" SP(bs=4) "#, None))), - (Th10, 342, Some((r#" SSSp(bs=4;mask=0x77,7,16) "#, None))), - (Th10, 343, Some((r#""#, None))), - (Th10, 344, Some((r#" S "#, None))), - (Th10, 345, Some((r#""#, None))), - (Th10, 346, Some((r#" f "#, None))), - (Th10, 347, Some((r#" SfC "#, None))), - (Th10, 348, Some((r#" SSSp(bs=4;mask=0x77,7,16) "#, None))), - (Th10, 349, Some((r#" fff "#, None))), - (Th10, 350, Some((r#" fffff "#, None))), - (Th10, 351, Some((r#" fff "#, None))), - (Th10, 352, Some((r#" SSS "#, None))), - (Th10, 353, Some((r#" SSSSS "#, None))), - (Th10, 354, Some((r#" SSS "#, None))), - (Th10, 355, Some((r#" SSSSS "#, None))), - (Th10, 356, Some((r#" fffff "#, None))), - (Th10, 357, Some((r#" SSSp(bs=4;mask=0x77,7,16) "#, None))), - (Th10, 358, Some((r#" SSSp(bs=4;mask=0x77,7,16) "#, None))), - (Th10, 359, Some((r#" SSSp(bs=4;mask=0x77,7,16) "#, None))), - (Th10, 360, Some((r#" S "#, None))), - (Th10, 361, Some((r#" S "#, None))), - (Th10, 362, Some((r#""#, None))), - (Th10, 363, Some((r#""#, None))), - (Th10, 364, Some((r#" S(enum="bool") "#, None))), - (Th10, 365, Some((r#""#, None))), - (Th10, 366, Some((r#" S(enum="bool")S "#, None))), - (Th10, 367, Some((r#" f "#, None))), - (Th10, 368, Some((r#" SSSS "#, None))), - (Th10, 400, Some((r#" S "#, None))), - (Th10, 401, Some((r#" S "#, None))), - (Th10, 402, Some((r#" SSS "#, None))), - (Th10, 403, Some((r#" Sff "#, None))), - (Th10, 404, Some((r#" Sff "#, None))), - (Th10, 405, Some((r#" Sff "#, None))), - (Th10, 406, Some((r#" SSS "#, None))), - (Th10, 407, Some((r#" SS "#, None))), - (Th10, 408, Some((r#" SSS "#, None))), - (Th10, 409, Some((r#" SSSSSSff "#, None))), - (Th10, 410, Some((r#""#, None))), - (Th10, 411, Some((r#" SS "#, None))), - (Th10, 412, Some((r#" SSffffff "#, None))), - (Th10, 413, Some((r#" SSSfffSSSSfS "#, None))), - (Th10, 414, Some((r#" Sff "#, None))), - (Th10, 415, Some((r#" Sff "#, None))), - (Th10, 416, Some((r#" Sf "#, None))), - (Th10, 417, Some((r#" Sf "#, None))), - (Th10, 418, Some((r#" Sf "#, None))), - (Th10, 419, Some((r#" Sf "#, None))), - (Th10, 420, Some((r#" f "#, None))), - (Th10, 421, Some((r#" f "#, None))), - (Th10, 422, Some((r#" Sffffff "#, None))), - (Th10, 423, Some((r#" Sffffffffff "#, None))), - (Th10, 424, Some((r#" Sffff "#, None))), - (Th10, 425, Some((r#" SSSSSSS "#, None))), - (Th10, 426, Some((r#" SSSSSSSSSSS "#, None))), - (Th10, 427, Some((r#" SSSSS "#, None))), - (Th10, 428, Some((r#" SSffffff "#, None))), - (Th10, 429, Some((r#" SSSfffSSSSfS "#, None))), - (Th10, 430, Some((r#" fff "#, None))), - (Th10, 431, Some((r#" SSffffff "#, None))), - (Th10, 432, Some((r#" SSSfffSSSSfS "#, None))), - (Th10, 433, Some((r#" SSffffff "#, None))), - (Th10, 434, Some((r#" SSSfffSSSSfS "#, None))), - (Th10, 435, Some((r#" Sffffffff "#, None))), - (Th10, 436, Some((r#" SSSSSSSSS "#, None))), + (Th10, 0, Some(("", None))), + (Th10, 1, Some(("", None))), + (Th10, 10, Some(("", None))), // + // (Th10, 11, Some((r#"P(bs=4)v(rep="G")"#, None))), // Some(IKind::Return) + (Th10, 12, Some(("ot", Some(IKind::Jmp)))), + (Th10, 13, Some(("ot", None))), // Some(IKind::PopJmp(B::Eq)) + (Th10, 14, Some(("ot", None))), // Some(IKind::PopJmp(B::Ne)) + // (Th10, 15, Some((r#"P(bs=4)v(rep="G")"#, None))), // Some(IKind::CallStackAsync) + // (Th10, 16, Some((r#"P(bs=4)Sv(rep="G")"#, None))), // Some(IKind::CallStackAsyncId) + (Th10, 17, Some(("S", None))), + (Th10, 18, Some(("S", None))), + (Th10, 19, Some(("S", None))), + (Th10, 20, Some(("SS", None))), + (Th10, 21, Some(("", None))), + // (Th10, 30, Some((r#"p(bs=4)v(rep="g")"#, None))), + (Th10, 40, Some(("S", None))), // Some(IKind::FrameEnter) + (Th10, 41, Some(("", None))), // Some(IKind::FrameLeave) + (Th10, 42, Some(("S", None))), // Some(IKind::Push(Ty::Int)) + (Th10, 43, Some(("S", None))), // Some(IKind::Pop(Ty::Int)) + (Th10, 44, Some(("f", None))), // Some(IKind::Push(Ty::Float)) + (Th10, 45, Some(("f", None))), // Some(IKind::Pop(Ty::Float)) + (Th10, 50, Some(("", None))), // Some(IKind::StackBinOp(B::Add, Ty::Int)) + (Th10, 51, Some(("", None))), // Some(IKind::StackBinOp(B::Add, Ty::Float)) + (Th10, 52, Some(("", None))), // Some(IKind::StackBinOp(B::Sub, Ty::Int)) + (Th10, 53, Some(("", None))), // Some(IKind::StackBinOp(B::Sub, Ty::Float)) + (Th10, 54, Some(("", None))), // Some(IKind::StackBinOp(B::Mul, Ty::Int)) + (Th10, 55, Some(("", None))), // Some(IKind::StackBinOp(B::Mul, Ty::Float)) + (Th10, 56, Some(("", None))), // Some(IKind::StackBinOp(B::Div, Ty::Int)) + (Th10, 57, Some(("", None))), // Some(IKind::StackBinOp(B::Div, Ty::Float)) + (Th10, 58, Some(("", None))), // Some(IKind::StackBinOp(B::Mod, Ty::Int)) + (Th10, 59, Some(("", None))), // Some(IKind::StackBinCmp(B::Eq, Ty::Int)) + (Th10, 60, Some(("", None))), // Some(IKind::StackBinCmp(B::Eq, Ty::Float)) + (Th10, 61, Some(("", None))), // Some(IKind::StackBinCmp(B::Ne, Ty::Int)) + (Th10, 62, Some(("", None))), // Some(IKind::StackBinCmp(B::Ne, Ty::Float)) + (Th10, 63, Some(("", None))), // Some(IKind::StackBinCmp(B::Lt, Ty::Int)) + (Th10, 64, Some(("", None))), // Some(IKind::StackBinCmp(B::Lt, Ty::Float)) + (Th10, 65, Some(("", None))), // Some(IKind::StackBinCmp(B::Le, Ty::Int)) + (Th10, 66, Some(("", None))), // Some(IKind::StackBinCmp(B::Le, Ty::Float)) + (Th10, 67, Some(("", None))), // Some(IKind::StackBinCmp(B::Gt, Ty::Int)) + (Th10, 68, Some(("", None))), // Some(IKind::StackBinCmp(B::Gt, Ty::Float)) + (Th10, 69, Some(("", None))), // Some(IKind::StackBinCmp(B::Ge, Ty::Int)) + (Th10, 70, Some(("", None))), // Some(IKind::StackBinCmp(B::Ge, Ty::Float)) + (Th10, 71, Some(("", None))), // Some(IKind::StackUnCmp(U::Not, Ty::Int)) + (Th10, 72, Some(("", None))), // Some(IKind::StackUnCmp(U::Not, Ty::Float)) + (Th10, 73, Some(("", None))), // Some(IKind::StackBinOp(B::IllogicOr, Ty::Int)) + (Th10, 74, Some(("", None))), // Some(IKind::StackBinOp(B::IllogicAnd, Ty::Int)) + (Th10, 75, Some(("", None))), // Some(IKind::StackBinCmp(B::BitXor, Ty::Int)) + (Th10, 76, Some(("", None))), // Some(IKind::StackBinCmp(B::BitOr, Ty::Int)) + (Th10, 77, Some(("", None))), // Some(IKind::StackBinCmp(B::BitAnd, Ty::Int)) + (Th10, 78, Some(("S", None))), // + (Th10, 79, Some(("", None))), // Some(IKind::StackUnOp(U::Sin, Ty::Float)) + (Th10, 80, Some(("", None))), // Some(IKind::StackUnOp(U::Cos, Ty::Float)) + (Th10, 81, Some(("ffff", None))), + (Th10, 82, Some(("f", None))), + (Th10, 83, Some(("S", None))), + (Th10, 84, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Int)) + (Th10, 85, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Float)) + (Th10, 86, Some(("fff", None))), + (Th10, 87, Some(("ffff", None))), + (Th10, 256, Some(("P(bs=4)ffSSS", None))), + (Th10, 257, Some(("P(bs=4)ffSSS", None))), + (Th10, 258, Some(("S", None))), + (Th10, 259, Some(("SN", None))), + (Th10, 260, Some(("P(bs=4)ffSSS", None))), + (Th10, 261, Some(("P(bs=4)ffSSS", None))), + (Th10, 262, Some(("SN", None))), + (Th10, 263, Some(("SN", None))), + (Th10, 264, Some(("SN", None))), + (Th10, 265, Some(("P(bs=4)ffSSS", None))), + (Th10, 266, Some(("P(bs=4)ffSSS", None))), + (Th10, 267, Some(("P(bs=4)ffSSS", None))), + (Th10, 268, Some(("P(bs=4)ffSSS", None))), + (Th10, 269, Some(("S", None))), + (Th10, 270, Some(("P(bs=4)fffSSS", None))), + (Th10, 271, Some(("P(bs=4)fffSSS", None))), + (Th10, 272, Some(("SN", None))), + (Th10, 273, Some(("SNf", None))), + (Th10, 280, Some(("ff", None))), + (Th10, 281, Some(("SSff", None))), + (Th10, 282, Some(("ff", None))), + (Th10, 283, Some(("SSff", None))), + (Th10, 284, Some(("ff", None))), + (Th10, 285, Some(("SSff", None))), + (Th10, 286, Some(("ff", None))), + (Th10, 287, Some(("SSff", None))), + (Th10, 288, Some(("ffff", None))), + (Th10, 289, Some(("SSffff", None))), + (Th10, 290, Some(("ffff", None))), + (Th10, 291, Some(("SSffff", None))), + (Th10, 292, Some(("SSf", None))), + (Th10, 293, Some(("SSf", None))), + (Th10, 294, Some(("", None))), + (Th10, 295, Some(("", None))), + (Th10, 296, Some(("fff", None))), + (Th10, 297, Some(("fff", None))), + (Th10, 298, Some(("ff", None))), + (Th10, 299, Some(("ff", None))), + (Th10, 320, Some(("ff", None))), + (Th10, 321, Some(("ff", None))), + (Th10, 322, Some(("S(hex)", None))), + (Th10, 323, Some(("S(hex)", None))), + (Th10, 324, Some(("ffff", None))), + (Th10, 325, Some(("", None))), + (Th10, 326, Some(("", None))), + (Th10, 327, Some(("SS", None))), + (Th10, 328, Some(("ff", None))), + (Th10, 329, Some(("", None))), + (Th10, 330, Some(("S", None))), + (Th10, 331, Some(("S", None))), + (Th10, 332, Some(("S", None))), + (Th10, 333, Some(("", None))), + (Th10, 334, Some(("SSSP(bs=4)", None))), + (Th10, 335, Some(("S", None))), + (Th10, 336, Some(("S", None))), + (Th10, 337, Some(("SSS", None))), + (Th10, 338, Some((r#"S(enum="MsgScript")"#, None))), + (Th10, 339, Some(("", None))), + (Th10, 340, Some(("", None))), + (Th10, 341, Some(("SP(bs=4)", None))), + (Th10, 342, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), + (Th10, 343, Some(("", None))), + (Th10, 344, Some(("S", None))), + (Th10, 345, Some(("", None))), + (Th10, 346, Some(("f", None))), + (Th10, 347, Some(("SfC", None))), + (Th10, 348, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), + (Th10, 349, Some(("fff", None))), + (Th10, 350, Some(("fffff", None))), + (Th10, 351, Some(("fff", None))), + (Th10, 352, Some(("SSS", None))), + (Th10, 353, Some(("SSSSS", None))), + (Th10, 354, Some(("SSS", None))), + (Th10, 355, Some(("SSSSS", None))), + (Th10, 356, Some(("fffff", None))), + (Th10, 357, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), + (Th10, 358, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), + (Th10, 359, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), + (Th10, 360, Some(("S", None))), + (Th10, 361, Some(("S", None))), + (Th10, 362, Some(("", None))), + (Th10, 363, Some(("", None))), + (Th10, 364, Some((r#"S(enum="bool")"#, None))), // zero: S(enum="BitBool") + (Th10, 365, Some(("", None))), + (Th10, 366, Some((r#"S(enum="bool")N"#, None))), + (Th10, 367, Some(("f", None))), + (Th10, 368, Some(("SSSS", None))), + (Th10, 400, Some(("S", None))), + (Th10, 401, Some(("S", None))), + (Th10, 402, Some(("SSS", None))), + (Th10, 403, Some(("Sff", None))), + (Th10, 404, Some(("Sff", None))), + (Th10, 405, Some(("Sff", None))), + (Th10, 406, Some(("SSS", None))), + (Th10, 407, Some(("SS", None))), + (Th10, 408, Some(("SSS", None))), + (Th10, 409, Some((r#"SSS(enum="bool")SSSff"#, None))), + (Th10, 410, Some(("", None))), + (Th10, 411, Some(("SS", None))), + (Th10, 412, Some(("SSffffff", None))), + (Th10, 413, Some(("SSSfffSSSSfS(hex)", None))), + (Th10, 414, Some(("Sff", None))), + (Th10, 415, Some(("Sff", None))), + (Th10, 416, Some(("Sf", None))), + (Th10, 417, Some(("Sf", None))), + (Th10, 418, Some(("Sf", None))), + (Th10, 419, Some(("Sf", None))), + (Th10, 420, Some(("f", None))), + (Th10, 421, Some(("f", None))), + (Th10, 422, Some(("Sffffff", None))), + (Th10, 423, Some(("Sffffffffff", None))), + (Th10, 424, Some(("Sffff", None))), + (Th10, 425, Some(("SSSSSSS", None))), + (Th10, 426, Some(("SSSSSSSSSSS", None))), + (Th10, 427, Some(("SSSSS", None))), + (Th10, 428, Some(("SSffffff", None))), + (Th10, 429, Some(("SSSfffSSSSfS(hex)", None))), + (Th10, 430, Some(("fff", None))), + (Th10, 431, Some(("SSffffff", None))), + (Th10, 432, Some(("SSSfffSSSSfS(hex)", None))), + (Th10, 433, Some(("SSffffff", None))), + (Th10, 434, Some(("SSSfffSSSSfS(hex)", None))), + (Th10, 435, Some(("Sffffffff", None))), + (Th10, 436, Some(("SSSSSSSSS", None))), ], var: &[ - // TODO + (Th10, -10000, Some("$")), + (Th10, -9999, Some("%")), + (Th10, -9998, Some("%")), + (Th10, -9997, Some("%")), + (Th10, -9996, Some("%")), + (Th10, -9995, Some("%")), + (Th10, -9994, Some("%")), + (Th10, -9993, Some("%")), + (Th10, -9992, Some("%")), + (Th10, -9991, Some("%")), + (Th10, -9990, Some("%")), + (Th10, -9989, Some("%")), + (Th10, -9988, Some("$")), + (Th10, -9987, Some("%")), + (Th10, -9986, Some("$")), + (Th10, -9985, Some("$")), + (Th10, -9984, Some("$")), + (Th10, -9983, Some("$")), + (Th10, -9982, Some("$")), + (Th10, -9981, Some("%")), + (Th10, -9980, Some("%")), + (Th10, -9979, Some("%")), + (Th10, -9978, Some("%")), + (Th10, -9977, Some("%")), + (Th10, -9976, Some("%")), + (Th10, -9975, Some("%")), + (Th10, -9974, Some("%")), + (Th10, -9973, Some("%")), + (Th10, -9972, Some("%")), + (Th10, -9971, Some("%")), + (Th10, -9970, Some("%")), + (Th10, -9969, Some("%")), + (Th10, -9968, Some("%")), + (Th10, -9967, Some("%")), + (Th10, -9966, Some("%")), + (Th10, -9965, Some("%")), + (Th10, -9964, Some("%")), + (Th10, -9963, Some("%")), + (Th10, -9962, Some("%")), + (Th10, -9961, Some("$")), + (Th10, -9960, Some("$")), + (Th10, -9959, Some("$")), + (Th10, -9958, Some("%")), + (Th10, -9957, Some("$")), + (Th10, -9956, Some("%")), + (Th10, -9955, Some("%")), + (Th10, -9954, Some("$")), + (Th10, -9953, Some("$")), + (Th10, -9952, Some("$")), + (Th10, -9951, Some("$")), + (Th10, -9950, Some("$")), ], }; diff --git a/src/llir/raise/early.rs b/src/llir/raise/early.rs index 5b6ea13..7858d70 100644 --- a/src/llir/raise/early.rs +++ b/src/llir/raise/early.rs @@ -181,7 +181,7 @@ fn early_raise_intrinsics( fn raise_mask(value: raw::ParamMask) -> ast::Expr { ast::Expr::LitInt { value: value.into(), - radix: ast::IntRadix::Bin, + format: ast::IntFormat { unsigned: true, radix: ast::IntRadix::Bin }, } } @@ -192,7 +192,7 @@ fn raise_nargs(value: raw::ArgCount) -> ast::Expr { fn raise_pop(value: raw::StackPop) -> ast::Expr { ast::Expr::LitInt { value: value.into(), - radix: ast::IntRadix::Hex, + format: ast::IntFormat { unsigned: true, radix: ast::IntRadix::Hex }, } } @@ -256,8 +256,8 @@ fn decode_args_with_abi( if let ArgEncoding::Padding { size } = enc { decrease_len(emitter, &mut remaining_len, *size as usize)?; let raw_value = match size { - 1 => args_blob.read_u8().expect("already checked len") as i32, - 4 => args_blob.read_u32().expect("already checked len") as i32, + 1 => blob_reader.read_u8().expect("already checked len") as i32, + 4 => blob_reader.read_u32().expect("already checked len") as i32, _ => unreachable!(), }; args.push(SimpleArg { value: ScalarValue::Int(raw_value), is_reg: false } ); @@ -292,7 +292,7 @@ fn decode_args_with_abi( | ArgEncoding::Integer { arg0: false, size: 4, format: ast::IntFormat { unsigned: false, radix: _ }, .. } => { decrease_len(emitter, &mut remaining_len, 4)?; - ScalarValue::Int(args_blob.read_i32().expect("already checked len")) + ScalarValue::Int(blob_reader.read_i32().expect("already checked len")) }, | ArgEncoding::Integer { arg0: false, size: 2, format: ast::IntFormat { unsigned: false, radix: _ }, .. } @@ -304,25 +304,25 @@ fn decode_args_with_abi( | ArgEncoding::Integer { arg0: false, size: 1, format: ast::IntFormat { unsigned: false, radix: _ }, .. } => { decrease_len(emitter, &mut remaining_len, 1)?; - ScalarValue::Int(args_blob.read_i8().expect("already checked len") as i32) + ScalarValue::Int(blob_reader.read_i8().expect("already checked len") as i32) }, | ArgEncoding::Integer { arg0: false, size: 4, format: ast::IntFormat { unsigned: true, radix: _ }, .. } => { decrease_len(emitter, &mut remaining_len, 4)?; - ScalarValue::Int(args_blob.read_u32().expect("already checked len") as i32) + ScalarValue::Int(blob_reader.read_u32().expect("already checked len") as i32) }, | ArgEncoding::Integer { arg0: false, size: 2, format: ast::IntFormat { unsigned: true, radix: _ }, .. } => { decrease_len(emitter, &mut remaining_len, 2)?; - ScalarValue::Int(args_blob.read_u16().expect("already checked len") as i32) + ScalarValue::Int(blob_reader.read_u16().expect("already checked len") as i32) }, | ArgEncoding::Integer { arg0: false, size: 1, format: ast::IntFormat { unsigned: true, radix: _ }, .. } => { decrease_len(emitter, &mut remaining_len, 1)?; - ScalarValue::Int(args_blob.read_u8().expect("already checked len") as i32) + ScalarValue::Int(blob_reader.read_u8().expect("already checked len") as i32) }, | ArgEncoding::Integer { size, .. } From 17ce2095bd27c669882d2da61651363d60fd1b89 Mon Sep 17 00:00:00 2001 From: zero318 Date: Fri, 8 Jul 2022 22:38:00 -0400 Subject: [PATCH 11/26] Sixth batch of updated signatures --- src/core_mapfiles/ecl.rs | 45 +++++++++++++++++++++++++++++++++------- src/core_mapfiles/std.rs | 3 ++- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/core_mapfiles/ecl.rs b/src/core_mapfiles/ecl.rs index 2b83012..440ccf3 100644 --- a/src/core_mapfiles/ecl.rs +++ b/src/core_mapfiles/ecl.rs @@ -12,9 +12,9 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { Th07 => ECL_07, Th08 | Th09 => ECL_08_09, Th095 => ECL_095, - Th10 => ECL_10, + Th10 | Alcostg => ECL_10_103, - Alcostg | Th11 | Th12 | Th125 | Th128 | + Th11 | Th12 | Th125 | Th128 | Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 => CoreSignatures::EMPTY, } } @@ -1059,7 +1059,7 @@ static ECL_095: &'static CoreSignatures = &CoreSignatures { }; -static ECL_10: &'static CoreSignatures = &CoreSignatures { +static ECL_10_103: &'static CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th10, 0, Some(("", None))), @@ -1121,6 +1121,9 @@ static ECL_10: &'static CoreSignatures = &CoreSignatures { (Th10, 85, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Float)) (Th10, 86, Some(("fff", None))), (Th10, 87, Some(("ffff", None))), + + (Alcostg, 88, Some(("", None))), // Some(IKind::StackUnOp(U::Sqrt, Ty::Float)) + (Th10, 256, Some(("P(bs=4)ffSSS", None))), (Th10, 257, Some(("P(bs=4)ffSSS", None))), (Th10, 258, Some(("S", None))), @@ -1139,6 +1142,10 @@ static ECL_10: &'static CoreSignatures = &CoreSignatures { (Th10, 271, Some(("P(bs=4)fffSSS", None))), (Th10, 272, Some(("SN", None))), (Th10, 273, Some(("SNf", None))), + + (Alcostg, 274, Some(("SN", None))), + (Alcostg, 275, Some(("SS", None))), + (Th10, 280, Some(("ff", None))), (Th10, 281, Some(("SSff", None))), (Th10, 282, Some(("ff", None))), @@ -1159,6 +1166,12 @@ static ECL_10: &'static CoreSignatures = &CoreSignatures { (Th10, 297, Some(("fff", None))), (Th10, 298, Some(("ff", None))), (Th10, 299, Some(("ff", None))), + + (Alcostg, 300, Some(("ffffff", None))), + (Alcostg, 301, Some(("SSffffff", None))), + (Alcostg, 302, Some(("ffffff", None))), + (Alcostg, 303, Some(("SSffffff", None))), + (Th10, 320, Some(("ff", None))), (Th10, 321, Some(("ff", None))), (Th10, 322, Some(("S(hex)", None))), @@ -1194,8 +1207,8 @@ static ECL_10: &'static CoreSignatures = &CoreSignatures { (Th10, 352, Some(("SSS", None))), (Th10, 353, Some(("SSSSS", None))), (Th10, 354, Some(("SSS", None))), - (Th10, 355, Some(("SSSSS", None))), - (Th10, 356, Some(("fffff", None))), + (Th10, 355, Some(("SSSSS", None))), // alcostg: SS___ + (Th10, 356, Some(("fffff", None))), // alcostg: ff___ (Th10, 357, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), (Th10, 358, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), (Th10, 359, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), @@ -1207,7 +1220,10 @@ static ECL_10: &'static CoreSignatures = &CoreSignatures { (Th10, 365, Some(("", None))), (Th10, 366, Some((r#"S(enum="bool")N"#, None))), (Th10, 367, Some(("f", None))), - (Th10, 368, Some(("SSSS", None))), + (Th10, 368, Some(("SSSS", None))), // alcostg: S___ + + (Alcostg, 369, Some(("SSSS", None))), + (Th10, 400, Some(("S", None))), (Th10, 401, Some(("S", None))), (Th10, 402, Some(("SSS", None))), @@ -1243,8 +1259,17 @@ static ECL_10: &'static CoreSignatures = &CoreSignatures { (Th10, 432, Some(("SSSfffSSSSfS(hex)", None))), (Th10, 433, Some(("SSffffff", None))), (Th10, 434, Some(("SSSfffSSSSfS(hex)", None))), - (Th10, 435, Some(("Sffffffff", None))), - (Th10, 436, Some(("SSSSSSSSS", None))), + (Th10, 435, Some(("Sffffffff", None))), // alcostg: Sf___f___ + (Th10, 436, Some(("SSSSSSSSS", None))), // alcostg: SS___S___ + + (Alcostg, 437, Some(("S", None))), + (Alcostg, 438, Some(("SS", None))), + (Alcostg, 439, Some(("Sf", None))), + (Alcostg, 440, Some(("", None))), + (Alcostg, 441, Some((r#"S(enum="bool")"#, None))), // zero: S(enum="BitBool") + (Alcostg, 442, Some(("S", None))), + (Alcostg, 443, Some(("S", None))), + (Alcostg, 444, Some(("Sf", None))), ], var: &[ (Th10, -10000, Some("$")), @@ -1298,5 +1323,9 @@ static ECL_10: &'static CoreSignatures = &CoreSignatures { (Th10, -9952, Some("$")), (Th10, -9951, Some("$")), (Th10, -9950, Some("$")), + + (Alcostg, -9959, None), // Didn't have difficulty + (Alcostg, -9949, Some("$")), + (Alcostg, -9948, Some("$")), ], }; diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index cf55820..b337ce6 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -99,7 +99,8 @@ static STD_095_18: &CoreSignatures = &CoreSignatures { (Th10, 10, Some(("S_fffffffff", None))), (Th10, 11, Some(("S_fffffffff", None))), - (Th11, 16, Some(("S", Some(IKind::InterruptLabel)))), + (Alcostg, 16, Some(("S(imm)", Some(IKind::InterruptLabel)))), + (Th11, 17, Some(("S", None))), (Th12, 18, Some(("SSfff", None))), From 92292d51677398d602693a5b1490d830a34d7774 Mon Sep 17 00:00:00 2001 From: zero318 Date: Sat, 9 Jul 2022 22:17:08 -0400 Subject: [PATCH 12/26] Seventh batch of updated signatures --- src/core_mapfiles/anm.rs | 21 +++++++------ src/core_mapfiles/ecl.rs | 68 +++++++++++++++++++++++++++++++++------- 2 files changed, 69 insertions(+), 20 deletions(-) diff --git a/src/core_mapfiles/anm.rs b/src/core_mapfiles/anm.rs index b878976..d342dcf 100644 --- a/src/core_mapfiles/anm.rs +++ b/src/core_mapfiles/anm.rs @@ -272,10 +272,10 @@ static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { (Th095, 73, Some((r#"U(imm;enum="bool")"#, None))), // zero: U(imm;enum="BitBool") (Th095, 74, Some((r#"U(imm;enum="bool")"#, None))), // zero: U(imm;enum="BitBool") (Th095, 75, Some(("S", None))), - (Th095, 76, Some(("SSS", None))), - (Th095, 77, Some(("S", None))), - (Th095, 78, Some(("SSSSS", None))), - (Th095, 79, Some(("SSS", None))), + (Th095, 76, Some(("CCC", None))), + (Th095, 77, Some(("C", None))), + (Th095, 78, Some(("Sb(imm)---CCC", None))), + (Th095, 79, Some(("Sb(imm)---C", None))), (Th095, 80, Some(("b(imm)---", None))), (Th095, 81, Some(("", None))), (Th095, 82, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- @@ -285,7 +285,9 @@ static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { (Th095, 86, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") (Th095, 87, Some(("b(imm)---", None))), - // v4b (MoF) + // v4b (MoF, alcostg) + // For some reason only a few of the interp instructions + // were updated to use a 32 bit mode (Th10, 56, Some(("SU(imm)fff", None))), (Th10, 59, Some(("SU(imm)fff", None))), (Th10, 88, Some(("N", None))), @@ -294,18 +296,19 @@ static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { (Th10, 91, Some(("N", None))), (Th10, 92, Some(("N", None))), - (Th11, 93, Some(("SSf", None))), - (Th11, 94, Some(("SSf", None))), + // v4c (SA) + (Th11, 93, Some(("SU(imm)f", None))), + (Th11, 94, Some(("SU(imm)f", None))), (Th11, 95, Some(("N", None))), (Th11, 96, Some(("Nff", None))), (Th11, 97, Some(("Nff", None))), (Th11, 98, Some(("", None))), - (Th11, 99, Some(("S", None))), + (Th11, 99, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") (Th11, 100, Some(("Sfffffffff", None))), (Th11, 101, Some(("S", None))), (Th11, 102, Some(("nS", None))), - (Th11, 103, Some(("ff", None))), + (Th12, 103, Some(("ff", None))), (Th12, 104, Some(("fS", None))), (Th12, 105, Some(("fS", None))), (Th12, 106, Some(("ff", None))), diff --git a/src/core_mapfiles/ecl.rs b/src/core_mapfiles/ecl.rs index 440ccf3..54033bc 100644 --- a/src/core_mapfiles/ecl.rs +++ b/src/core_mapfiles/ecl.rs @@ -1146,6 +1146,9 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Alcostg, 274, Some(("SN", None))), (Alcostg, 275, Some(("SS", None))), + (Th11, 276, Some(("", None))), + (Th11, 277, Some(("Sf", None))), + (Th10, 280, Some(("ff", None))), (Th10, 281, Some(("SSff", None))), (Th10, 282, Some(("ff", None))), @@ -1172,6 +1175,11 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Alcostg, 302, Some(("ffffff", None))), (Alcostg, 303, Some(("SSffffff", None))), + (Th11, 304, Some((r#"S(enum="bool")"#, None))), // zero: S(enum="BitBool") + (Th11, 305, Some(("Sffffff", None))), + (Th11, 306, Some(("Sffffff", None))), + (Th11, 307, Some(("", None))), + (Th10, 320, Some(("ff", None))), (Th10, 321, Some(("ff", None))), (Th10, 322, Some(("S(hex)", None))), @@ -1224,6 +1232,11 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Alcostg, 369, Some(("SSSS", None))), + (Th11, 369, Some((r#"S(enum="bool")"#, None))), // zero: S(enum="BitBool") + (Th11, 370, Some(("S", None))), + (Th11, 371, Some(("S", None))), + (Th11, 372, Some(("S", None))), + (Th10, 400, Some(("S", None))), (Th10, 401, Some(("S", None))), (Th10, 402, Some(("SSS", None))), @@ -1268,8 +1281,23 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Alcostg, 440, Some(("", None))), (Alcostg, 441, Some((r#"S(enum="bool")"#, None))), // zero: S(enum="BitBool") (Alcostg, 442, Some(("S", None))), - (Alcostg, 443, Some(("S", None))), + (Alcostg, 443, Some(("S", None))), // S(enum="StdInterrupt") (Alcostg, 444, Some(("Sf", None))), + + (Th11, 437, Some(("Sff", None))), + (Th11, 438, Some(("Sf", None))), + (Th11, 439, Some(("Sff", None))), + (Th11, 440, Some(("fC", None))), + (Th11, 441, Some(("S", None))), // S(enum="StdInterrupt") + (Th11, 442, Some((r#"S(enum="bool")"#, None))), // zero: S(enum="BitBool") + (Th11, 443, Some(("S", None))), + (Th11, 444, Some(("S", None))), + (Th11, 445, Some(("S", None))), + (Th11, 446, Some(("f", None))), + (Th11, 447, Some(("f", None))), + (Th11, 448, Some(("S", None))), + (Th11, 449, Some(("S", None))), + (Th11, 450, Some(("S", None))), ], var: &[ (Th10, -10000, Some("$")), @@ -1287,14 +1315,14 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Th10, -9988, Some("$")), (Th10, -9987, Some("%")), (Th10, -9986, Some("$")), - (Th10, -9985, Some("$")), - (Th10, -9984, Some("$")), - (Th10, -9983, Some("$")), - (Th10, -9982, Some("$")), - (Th10, -9981, Some("%")), - (Th10, -9980, Some("%")), - (Th10, -9979, Some("%")), - (Th10, -9978, Some("%")), + (Th10, -9985, Some("$")), // Writable since MoF + (Th10, -9984, Some("$")), // Writable since MoF + (Th10, -9983, Some("$")), // Writable since MoF + (Th10, -9982, Some("$")), // Writable since MoF + (Th10, -9981, Some("%")), // Writable since MoF + (Th10, -9980, Some("%")), // Writable since MoF + (Th10, -9979, Some("%")), // Writable since MoF + (Th10, -9978, Some("%")), // Writable since MoF (Th10, -9977, Some("%")), (Th10, -9976, Some("%")), (Th10, -9975, Some("%")), @@ -1325,7 +1353,25 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Th10, -9950, Some("$")), (Alcostg, -9959, None), // Didn't have difficulty - (Alcostg, -9949, Some("$")), - (Alcostg, -9948, Some("$")), + (Alcostg, -9949, Some("$")), // Writable since SA + (Alcostg, -9948, Some("$")), // Writable since SA + + (Th11, -9959, Some("$")), + (Th11, -9947, Some("$")), // Writable since SA + (Th11, -9946, Some("$")), + (Th11, -9945, Some("$")), + (Th11, -9944, Some("%")), + (Th11, -9943, Some("$")), // Writable since SA + (Th11, -9942, Some("$")), // Writable since SA + (Th11, -9941, Some("$")), // Writable since SA + (Th11, -9940, Some("$")), // Writable since SA + (Th11, -9939, Some("%")), // Writable since SA + (Th11, -9938, Some("%")), // Writable since SA + (Th11, -9937, Some("%")), // Writable since SA + (Th11, -9936, Some("%")), // Writable since SA + (Th11, -9935, Some("%")), // Writable since SA + (Th11, -9934, Some("%")), // Writable since SA + (Th11, -9933, Some("%")), // Writable since SA + (Th11, -9932, Some("%")), // Writable since SA ], }; From 3d32e3b271121e62a79f2d5eab8ee26faea732e4 Mon Sep 17 00:00:00 2001 From: zero318 Date: Tue, 12 Jul 2022 04:49:56 -0400 Subject: [PATCH 13/26] Eigth batch of updated signatures --- src/core_mapfiles/anm.rs | 9 +- src/core_mapfiles/ecl.rs | 359 ++++++++++++++++++++++++++++++--------- src/core_mapfiles/msg.rs | 3 +- src/core_mapfiles/std.rs | 2 +- 4 files changed, 292 insertions(+), 81 deletions(-) diff --git a/src/core_mapfiles/anm.rs b/src/core_mapfiles/anm.rs index d342dcf..9ef283f 100644 --- a/src/core_mapfiles/anm.rs +++ b/src/core_mapfiles/anm.rs @@ -306,13 +306,14 @@ static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { (Th11, 99, Some((r#"U(enum="bool")"#, None))), // zero: U(enum="BitBool") (Th11, 100, Some(("Sfffffffff", None))), (Th11, 101, Some(("S", None))), - (Th11, 102, Some(("nS", None))), + (Th11, 102, Some(("nU", None))), + // v4d (UFO) (Th12, 103, Some(("ff", None))), (Th12, 104, Some(("fS", None))), (Th12, 105, Some(("fS", None))), (Th12, 106, Some(("ff", None))), - (Th12, 107, Some(("SSff", None))), + (Th12, 107, Some(("Sb(imm)---ff", None))), (Th12, 108, Some(("ff", None))), (Th12, 109, Some(("ff", None))), (Th12, 110, Some(("ff", None))), @@ -506,7 +507,7 @@ static ANM_VAR: &'static CoreSignatures = &CoreSignatures { (Th095, 10014, Some("%")), (Th095, 10015, Some("%")), - // v4b (MoF) + // v4b (MoF, alcostg) (Th10, 10016, Some("%")), (Th10, 10017, Some("%")), (Th10, 10018, Some("%")), @@ -514,8 +515,10 @@ static ANM_VAR: &'static CoreSignatures = &CoreSignatures { (Th10, 10020, Some("%")), (Th10, 10021, Some("%")), + // v4c (SA) (Th11, 10022, Some("$")), + // v4d (UFO) (Th12, 10023, Some("%")), (Th12, 10024, Some("%")), (Th12, 10025, Some("%")), diff --git a/src/core_mapfiles/ecl.rs b/src/core_mapfiles/ecl.rs index 54033bc..5366452 100644 --- a/src/core_mapfiles/ecl.rs +++ b/src/core_mapfiles/ecl.rs @@ -12,9 +12,10 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { Th07 => ECL_07, Th08 | Th09 => ECL_08_09, Th095 => ECL_095, - Th10 | Alcostg => ECL_10_103, + Th10 | Alcostg | Th11 => ECL_10_11, + Th12 => ECL_12, - Th11 | Th12 | Th125 | Th128 | + Th125 | Th128 | Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 => CoreSignatures::EMPTY, } } @@ -1059,71 +1060,10 @@ static ECL_095: &'static CoreSignatures = &CoreSignatures { }; -static ECL_10_103: &'static CoreSignatures = &CoreSignatures { - inherit: &[], +static ECL_10_11: &'static CoreSignatures = &CoreSignatures { + inherit: &[ECL_10_18_COMMON], ins: &[ - (Th10, 0, Some(("", None))), - (Th10, 1, Some(("", None))), - (Th10, 10, Some(("", None))), // - // (Th10, 11, Some((r#"P(bs=4)v(rep="G")"#, None))), // Some(IKind::Return) - (Th10, 12, Some(("ot", Some(IKind::Jmp)))), - (Th10, 13, Some(("ot", None))), // Some(IKind::PopJmp(B::Eq)) - (Th10, 14, Some(("ot", None))), // Some(IKind::PopJmp(B::Ne)) - // (Th10, 15, Some((r#"P(bs=4)v(rep="G")"#, None))), // Some(IKind::CallStackAsync) - // (Th10, 16, Some((r#"P(bs=4)Sv(rep="G")"#, None))), // Some(IKind::CallStackAsyncId) - (Th10, 17, Some(("S", None))), - (Th10, 18, Some(("S", None))), - (Th10, 19, Some(("S", None))), - (Th10, 20, Some(("SS", None))), - (Th10, 21, Some(("", None))), - // (Th10, 30, Some((r#"p(bs=4)v(rep="g")"#, None))), - (Th10, 40, Some(("S", None))), // Some(IKind::FrameEnter) - (Th10, 41, Some(("", None))), // Some(IKind::FrameLeave) - (Th10, 42, Some(("S", None))), // Some(IKind::Push(Ty::Int)) - (Th10, 43, Some(("S", None))), // Some(IKind::Pop(Ty::Int)) - (Th10, 44, Some(("f", None))), // Some(IKind::Push(Ty::Float)) - (Th10, 45, Some(("f", None))), // Some(IKind::Pop(Ty::Float)) - (Th10, 50, Some(("", None))), // Some(IKind::StackBinOp(B::Add, Ty::Int)) - (Th10, 51, Some(("", None))), // Some(IKind::StackBinOp(B::Add, Ty::Float)) - (Th10, 52, Some(("", None))), // Some(IKind::StackBinOp(B::Sub, Ty::Int)) - (Th10, 53, Some(("", None))), // Some(IKind::StackBinOp(B::Sub, Ty::Float)) - (Th10, 54, Some(("", None))), // Some(IKind::StackBinOp(B::Mul, Ty::Int)) - (Th10, 55, Some(("", None))), // Some(IKind::StackBinOp(B::Mul, Ty::Float)) - (Th10, 56, Some(("", None))), // Some(IKind::StackBinOp(B::Div, Ty::Int)) - (Th10, 57, Some(("", None))), // Some(IKind::StackBinOp(B::Div, Ty::Float)) - (Th10, 58, Some(("", None))), // Some(IKind::StackBinOp(B::Mod, Ty::Int)) - (Th10, 59, Some(("", None))), // Some(IKind::StackBinCmp(B::Eq, Ty::Int)) - (Th10, 60, Some(("", None))), // Some(IKind::StackBinCmp(B::Eq, Ty::Float)) - (Th10, 61, Some(("", None))), // Some(IKind::StackBinCmp(B::Ne, Ty::Int)) - (Th10, 62, Some(("", None))), // Some(IKind::StackBinCmp(B::Ne, Ty::Float)) - (Th10, 63, Some(("", None))), // Some(IKind::StackBinCmp(B::Lt, Ty::Int)) - (Th10, 64, Some(("", None))), // Some(IKind::StackBinCmp(B::Lt, Ty::Float)) - (Th10, 65, Some(("", None))), // Some(IKind::StackBinCmp(B::Le, Ty::Int)) - (Th10, 66, Some(("", None))), // Some(IKind::StackBinCmp(B::Le, Ty::Float)) - (Th10, 67, Some(("", None))), // Some(IKind::StackBinCmp(B::Gt, Ty::Int)) - (Th10, 68, Some(("", None))), // Some(IKind::StackBinCmp(B::Gt, Ty::Float)) - (Th10, 69, Some(("", None))), // Some(IKind::StackBinCmp(B::Ge, Ty::Int)) - (Th10, 70, Some(("", None))), // Some(IKind::StackBinCmp(B::Ge, Ty::Float)) - (Th10, 71, Some(("", None))), // Some(IKind::StackUnCmp(U::Not, Ty::Int)) - (Th10, 72, Some(("", None))), // Some(IKind::StackUnCmp(U::Not, Ty::Float)) - (Th10, 73, Some(("", None))), // Some(IKind::StackBinOp(B::IllogicOr, Ty::Int)) - (Th10, 74, Some(("", None))), // Some(IKind::StackBinOp(B::IllogicAnd, Ty::Int)) - (Th10, 75, Some(("", None))), // Some(IKind::StackBinCmp(B::BitXor, Ty::Int)) - (Th10, 76, Some(("", None))), // Some(IKind::StackBinCmp(B::BitOr, Ty::Int)) - (Th10, 77, Some(("", None))), // Some(IKind::StackBinCmp(B::BitAnd, Ty::Int)) - (Th10, 78, Some(("S", None))), // - (Th10, 79, Some(("", None))), // Some(IKind::StackUnOp(U::Sin, Ty::Float)) - (Th10, 80, Some(("", None))), // Some(IKind::StackUnOp(U::Cos, Ty::Float)) - (Th10, 81, Some(("ffff", None))), - (Th10, 82, Some(("f", None))), - (Th10, 83, Some(("S", None))), - (Th10, 84, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Int)) - (Th10, 85, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Float)) - (Th10, 86, Some(("fff", None))), - (Th10, 87, Some(("ffff", None))), - - (Alcostg, 88, Some(("", None))), // Some(IKind::StackUnOp(U::Sqrt, Ty::Float)) - + // Section A (Th10, 256, Some(("P(bs=4)ffSSS", None))), (Th10, 257, Some(("P(bs=4)ffSSS", None))), (Th10, 258, Some(("S", None))), @@ -1149,6 +1089,7 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Th11, 276, Some(("", None))), (Th11, 277, Some(("Sf", None))), + // Section B (Th10, 280, Some(("ff", None))), (Th10, 281, Some(("SSff", None))), (Th10, 282, Some(("ff", None))), @@ -1175,11 +1116,14 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Alcostg, 302, Some(("ffffff", None))), (Alcostg, 303, Some(("SSffffff", None))), + (Th11, 289, Some(("SSfff", None))), // Why is there 1 fewer arg after this? + (Th11, 291, Some(("SSfff", None))), (Th11, 304, Some((r#"S(enum="bool")"#, None))), // zero: S(enum="BitBool") (Th11, 305, Some(("Sffffff", None))), (Th11, 306, Some(("Sffffff", None))), (Th11, 307, Some(("", None))), + // Section C (Th10, 320, Some(("ff", None))), (Th10, 321, Some(("ff", None))), (Th10, 322, Some(("S(hex)", None))), @@ -1202,13 +1146,13 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Th10, 339, Some(("", None))), (Th10, 340, Some(("", None))), (Th10, 341, Some(("SP(bs=4)", None))), - (Th10, 342, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), + (Th10, 342, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), // Third arg read but not used (Th10, 343, Some(("", None))), (Th10, 344, Some(("S", None))), (Th10, 345, Some(("", None))), (Th10, 346, Some(("f", None))), (Th10, 347, Some(("SfC", None))), - (Th10, 348, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), + (Th10, 348, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), // Third arg read but not used (Th10, 349, Some(("fff", None))), (Th10, 350, Some(("fffff", None))), (Th10, 351, Some(("fff", None))), @@ -1217,16 +1161,16 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Th10, 354, Some(("SSS", None))), (Th10, 355, Some(("SSSSS", None))), // alcostg: SS___ (Th10, 356, Some(("fffff", None))), // alcostg: ff___ - (Th10, 357, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), - (Th10, 358, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), - (Th10, 359, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), + (Th10, 357, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), // Third arg read but not used + (Th10, 358, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), // Third arg read but not used + (Th10, 359, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), // Third arg read but not used (Th10, 360, Some(("S", None))), (Th10, 361, Some(("S", None))), (Th10, 362, Some(("", None))), (Th10, 363, Some(("", None))), (Th10, 364, Some((r#"S(enum="bool")"#, None))), // zero: S(enum="BitBool") (Th10, 365, Some(("", None))), - (Th10, 366, Some((r#"S(enum="bool")N"#, None))), + (Th10, 366, Some((r#"S(enum="bool")N"#, None))), // zero: S(enum="BitBool")N (Th10, 367, Some(("f", None))), (Th10, 368, Some(("SSSS", None))), // alcostg: S___ @@ -1237,6 +1181,7 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Th11, 371, Some(("S", None))), (Th11, 372, Some(("S", None))), + // Section D (Th10, 400, Some(("S", None))), (Th10, 401, Some(("S", None))), (Th10, 402, Some(("SSS", None))), @@ -1299,6 +1244,267 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Th11, 449, Some(("S", None))), (Th11, 450, Some(("S", None))), ], + var: &[ + // This is placed here to avoid putting game-specific + // stuff into the "common" definition block + (Alcostg, -9959, None), // Didn't have difficulty + (Th11, -9959, Some("$")), // Readded difficulty + ], +}; + + +static ECL_12: &'static CoreSignatures = &CoreSignatures { + inherit: &[ECL_10_18_COMMON], + ins: &[ + // Section A + (Th12, 256, Some(("P(bs=4)ffSSS", None))), + (Th12, 257, Some(("P(bs=4)ffSSS", None))), + (Th12, 258, Some(("S", None))), + (Th12, 259, Some(("SN", None))), + (Th12, 260, Some(("P(bs=4)ffSSS", None))), + (Th12, 261, Some(("P(bs=4)ffSSS", None))), + (Th12, 262, Some(("SN", None))), + (Th12, 263, Some(("SN", None))), + (Th12, 264, Some(("SN", None))), + (Th12, 265, Some(("P(bs=4)ffSSS", None))), + (Th12, 266, Some(("P(bs=4)ffSSS", None))), + (Th12, 267, Some(("P(bs=4)ffSSS", None))), + (Th12, 268, Some(("P(bs=4)ffSSS", None))), + (Th12, 269, Some(("S", None))), + (Th12, 270, Some(("P(bs=4)fffSSS", None))), + (Th12, 271, Some(("P(bs=4)fffSSS", None))), + (Th12, 272, Some(("SN", None))), + (Th12, 273, Some(("SNf", None))), + (Th12, 274, Some(("SN", None))), + (Th12, 275, Some(("SS", None))), + (Th12, 276, Some(("", None))), + (Th12, 277, Some(("Sf", None))), + (Th12, 278, Some(("Sff", None))), + (Th12, 279, Some(("Sff", None))), + (Th12, 280, Some(("P(bs=4)ffSSS", None))), + (Th12, 281, Some(("SS", None))), + + // Section B + (Th12, 300, Some(("ff", None))), + (Th12, 301, Some(("SSff", None))), + (Th12, 302, Some(("ff", None))), + (Th12, 303, Some(("SSff", None))), + (Th12, 304, Some(("ff", None))), + (Th12, 305, Some(("SSff", None))), + (Th12, 306, Some(("ff", None))), + (Th12, 307, Some(("SSff", None))), + (Th12, 308, Some(("ffff", None))), + (Th12, 309, Some(("SSfff", None))), + (Th12, 310, Some(("ffff", None))), + (Th12, 311, Some(("SSfff", None))), + (Th12, 312, Some(("SSf", None))), + (Th12, 313, Some(("SSf", None))), + (Th12, 314, Some(("", None))), + (Th12, 315, Some(("", None))), + (Th12, 316, Some(("fff", None))), + (Th12, 317, Some(("fff", None))), + (Th12, 318, Some(("ff", None))), + (Th12, 319, Some(("ff", None))), + (Th12, 320, Some(("ffffff", None))), + (Th12, 321, Some(("SSfffff", None))), // Again, another pair of removed floats...? + (Th12, 322, Some(("ffffff", None))), + (Th12, 323, Some(("SSfffff", None))), + (Th12, 324, Some((r#"S(enum="bool")"#, None))), // zero: S(enum="BitBool") + (Th12, 325, Some(("Sffffff", None))), + (Th12, 326, Some(("Sffffff", None))), + (Th12, 327, Some(("", None))), + + // Section C + (Th12, 400, Some(("ff", None))), + (Th12, 401, Some(("ff", None))), + (Th12, 402, Some(("S(hex)", None))), + (Th12, 403, Some(("S(hex)", None))), + (Th12, 404, Some(("ffff", None))), + (Th12, 405, Some(("", None))), + (Th12, 406, Some(("", None))), + (Th12, 407, Some(("SS", None))), + (Th12, 408, Some(("ff", None))), + (Th12, 409, Some(("", None))), + (Th12, 410, Some(("S", None))), + (Th12, 411, Some(("S", None))), + (Th12, 412, Some(("S", None))), + (Th12, 413, Some(("", None))), + (Th12, 414, Some(("SSSP(bs=4)", None))), + (Th12, 415, Some(("S", None))), + (Th12, 416, Some(("S", None))), + (Th12, 417, Some(("SSS", None))), + (Th12, 418, Some((r#"S(enum="MsgScript")"#, None))), + (Th12, 419, Some(("", None))), + (Th12, 420, Some(("", None))), + (Th12, 421, Some(("SP(bs=4)", None))), + (Th12, 422, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), // Third arg read but not used + (Th12, 423, Some(("", None))), + (Th12, 424, Some(("S", None))), + (Th12, 425, Some(("", None))), + (Th12, 426, Some(("f", None))), + (Th12, 427, Some(("SfC", None))), + (Th12, 428, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), // Third arg read but not used + (Th12, 429, Some(("fff", None))), + (Th12, 430, Some(("fffff", None))), + (Th12, 431, Some(("fff", None))), + (Th12, 432, Some(("SSS", None))), + (Th12, 433, Some(("SSSSS", None))), + (Th12, 434, Some(("SSS", None))), + (Th12, 435, Some(("SSSSS", None))), + (Th12, 436, Some(("fffff", None))), + (Th12, 437, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), // Third arg read but not used + (Th12, 438, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), // Third arg read but not used + (Th12, 439, Some(("SSSp(bs=4;mask=0x77,7,16)", None))), // Third arg read but not used + (Th12, 440, Some(("S", None))), + (Th12, 441, Some(("S", None))), + (Th12, 442, Some(("", None))), + (Th12, 443, Some(("", None))), + (Th12, 444, Some((r#"S(enum="bool")"#, None))), // zero: S(enum="BitBool") + (Th12, 445, Some(("", None))), + (Th12, 446, Some((r#"S(enum="bool")N"#, None))), // zero: S(enum="BitBool")N + (Th12, 447, Some(("f", None))), + (Th12, 448, Some(("SSSS", None))), + (Th12, 449, Some((r#"S(enum="bool")"#, None))), // zero: S(enum="BitBool") + (Th12, 450, Some(("S", None))), + (Th12, 451, Some(("S", None))), + (Th12, 452, Some(("S", None))), + (Th12, 453, Some(("S", None))), + (Th12, 454, Some(("", None))), + (Th12, 455, Some(("SS", None))), + (Th12, 456, Some(("ffS", None))), + + // Section D + (Th12, 500, Some(("S", None))), + (Th12, 501, Some(("S", None))), + (Th12, 502, Some(("SSS", None))), + (Th12, 503, Some(("Sff", None))), + (Th12, 504, Some(("Sff", None))), + (Th12, 505, Some(("Sff", None))), + (Th12, 506, Some(("SSS", None))), + (Th12, 507, Some(("SS", None))), + (Th12, 508, Some(("SSS", None))), + (Th12, 509, Some((r#"SSS(enum="bool")SSSff"#, None))), + (Th12, 510, Some(("", None))), + (Th12, 511, Some(("SS", None))), + // Laser instructions moved, everything else shifted up + (Th12, 512, Some(("f", None))), + (Th12, 513, Some(("f", None))), + (Th12, 514, Some(("Sffffff", None))), + (Th12, 515, Some(("Sffffffffff", None))), + (Th12, 516, Some(("Sffff", None))), + (Th12, 517, Some(("SSSSSSS", None))), + (Th12, 518, Some(("SSSSSSSSSSS", None))), + (Th12, 519, Some(("SSSSS", None))), + // More lasers moved + (Th12, 520, Some(("fff", None))), + // Even more lasers moved + (Th12, 521, Some(("Sffffffff", None))), + (Th12, 522, Some(("SSSSSSSSS", None))), + (Th12, 523, Some(("Sff", None))), + (Th12, 524, Some(("Sf", None))), + (Th12, 525, Some(("Sff", None))), + (Th12, 526, Some(("fC", None))), + (Th12, 527, Some(("S", None))), // S(enum="StdInterrupt") + (Th12, 528, Some((r#"S(enum="bool")"#, None))), // zero: S(enum="BitBool") + (Th12, 529, Some(("S", None))), + (Th12, 530, Some(("S", None))), + (Th12, 531, Some(("S", None))), + (Th12, 532, Some(("f", None))), + (Th12, 533, Some(("f", None))), + // Final laser instruction moved + (Th12, 534, Some(("S", None))), + (Th12, 535, Some(("S", None))), + + // Section E + (Th12, 600, Some(("Sffff", None))), + (Th12, 601, Some(("SSSSSS(hex)", None))), + (Th12, 602, Some(("S", None))), + (Th12, 603, Some(("SS", None))), + (Th12, 604, Some(("Sff", None))), + (Th12, 605, Some(("Sff", None))), + (Th12, 606, Some(("Sf", None))), + (Th12, 607, Some(("Sf", None))), + (Th12, 608, Some(("Sf", None))), + (Th12, 609, Some(("Sf", None))), + (Th12, 610, Some(("S", None))), + (Th12, 611, Some(("S", None))), + + // Section F + (Th12, 700, Some(("S", None))), + ], + var: &[], +}; + + +static ECL_10_18_COMMON: &'static CoreSignatures = &CoreSignatures { + inherit: &[], + ins: &[ + (Th10, 0, Some(("", None))), + (Th10, 1, Some(("", None))), + (Th10, 10, Some(("", None))), // + // (Th10, 11, Some((r#"P(bs=4)v(rep="G")"#, None))), // Some(IKind::Return) + (Th10, 12, Some(("ot", Some(IKind::Jmp)))), + (Th10, 13, Some(("ot", None))), // Some(IKind::PopJmp(B::Eq)) + (Th10, 14, Some(("ot", None))), // Some(IKind::PopJmp(B::Ne)) + // (Th10, 15, Some((r#"P(bs=4)v(rep="G")"#, None))), // Some(IKind::CallStackAsync) + // (Th10, 16, Some((r#"P(bs=4)Sv(rep="G")"#, None))), // Some(IKind::CallStackAsyncId) + (Th10, 17, Some(("S", None))), + (Th10, 18, Some(("S", None))), + (Th10, 19, Some(("S", None))), + (Th10, 20, Some(("SS", None))), + (Th10, 21, Some(("", None))), + // (Th10, 30, Some((r#"p(bs=4)v(rep="g")"#, None))), + (Th10, 40, Some(("S", None))), // Some(IKind::FrameEnter) + (Th10, 41, Some(("", None))), // Some(IKind::FrameLeave) + (Th10, 42, Some(("S", None))), // Some(IKind::Push(Ty::Int)) + (Th10, 43, Some(("S", None))), // Some(IKind::Pop(Ty::Int)) + (Th10, 44, Some(("f", None))), // Some(IKind::Push(Ty::Float)) + (Th10, 45, Some(("f", None))), // Some(IKind::Pop(Ty::Float)) + (Th10, 50, Some(("", None))), // Some(IKind::StackBinOp(B::Add, Ty::Int)) + (Th10, 51, Some(("", None))), // Some(IKind::StackBinOp(B::Add, Ty::Float)) + (Th10, 52, Some(("", None))), // Some(IKind::StackBinOp(B::Sub, Ty::Int)) + (Th10, 53, Some(("", None))), // Some(IKind::StackBinOp(B::Sub, Ty::Float)) + (Th10, 54, Some(("", None))), // Some(IKind::StackBinOp(B::Mul, Ty::Int)) + (Th10, 55, Some(("", None))), // Some(IKind::StackBinOp(B::Mul, Ty::Float)) + (Th10, 56, Some(("", None))), // Some(IKind::StackBinOp(B::Div, Ty::Int)) + (Th10, 57, Some(("", None))), // Some(IKind::StackBinOp(B::Div, Ty::Float)) + (Th10, 58, Some(("", None))), // Some(IKind::StackBinOp(B::Mod, Ty::Int)) + (Th10, 59, Some(("", None))), // Some(IKind::StackBinCmp(B::Eq, Ty::Int)) + (Th10, 60, Some(("", None))), // Some(IKind::StackBinCmp(B::Eq, Ty::Float)) + (Th10, 61, Some(("", None))), // Some(IKind::StackBinCmp(B::Ne, Ty::Int)) + (Th10, 62, Some(("", None))), // Some(IKind::StackBinCmp(B::Ne, Ty::Float)) + (Th10, 63, Some(("", None))), // Some(IKind::StackBinCmp(B::Lt, Ty::Int)) + (Th10, 64, Some(("", None))), // Some(IKind::StackBinCmp(B::Lt, Ty::Float)) + (Th10, 65, Some(("", None))), // Some(IKind::StackBinCmp(B::Le, Ty::Int)) + (Th10, 66, Some(("", None))), // Some(IKind::StackBinCmp(B::Le, Ty::Float)) + (Th10, 67, Some(("", None))), // Some(IKind::StackBinCmp(B::Gt, Ty::Int)) + (Th10, 68, Some(("", None))), // Some(IKind::StackBinCmp(B::Gt, Ty::Float)) + (Th10, 69, Some(("", None))), // Some(IKind::StackBinCmp(B::Ge, Ty::Int)) + (Th10, 70, Some(("", None))), // Some(IKind::StackBinCmp(B::Ge, Ty::Float)) + (Th10, 71, Some(("", None))), // Some(IKind::StackUnCmp(U::Not, Ty::Int)) + (Th10, 72, Some(("", None))), // Some(IKind::StackUnCmp(U::Not, Ty::Float)) + (Th10, 73, Some(("", None))), // Some(IKind::StackBinOp(B::IllogicOr, Ty::Int)) + (Th10, 74, Some(("", None))), // Some(IKind::StackBinOp(B::IllogicAnd, Ty::Int)) + (Th10, 75, Some(("", None))), // Some(IKind::StackBinCmp(B::BitXor, Ty::Int)) + (Th10, 76, Some(("", None))), // Some(IKind::StackBinCmp(B::BitOr, Ty::Int)) + (Th10, 77, Some(("", None))), // Some(IKind::StackBinCmp(B::BitAnd, Ty::Int)) + (Th10, 78, Some(("S", None))), // + (Th10, 79, Some(("", None))), // Some(IKind::StackUnOp(U::Sin, Ty::Float)) + (Th10, 80, Some(("", None))), // Some(IKind::StackUnOp(U::Cos, Ty::Float)) + (Th10, 81, Some(("ffff", None))), + (Th10, 82, Some(("f", None))), + (Th10, 83, Some(("S", None))), + (Th10, 84, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Int)) + (Th10, 85, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Float)) + (Th10, 86, Some(("fff", None))), + (Th10, 87, Some(("ffff", None))), + + (Th12, 87, Some(("fffff", None))), // Changed to not use first arg as input and output + + (Alcostg, 88, Some(("", None))), // Some(IKind::StackUnOp(U::Sqrt, Ty::Float)) + + (Th12, 89, Some(("fff", None))), + ], var: &[ (Th10, -10000, Some("$")), (Th10, -9999, Some("%")), @@ -1352,11 +1558,9 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Th10, -9951, Some("$")), (Th10, -9950, Some("$")), - (Alcostg, -9959, None), // Didn't have difficulty (Alcostg, -9949, Some("$")), // Writable since SA (Alcostg, -9948, Some("$")), // Writable since SA - - (Th11, -9959, Some("$")), + (Th11, -9947, Some("$")), // Writable since SA (Th11, -9946, Some("$")), (Th11, -9945, Some("$")), @@ -1373,5 +1577,8 @@ static ECL_10_103: &'static CoreSignatures = &CoreSignatures { (Th11, -9934, Some("%")), // Writable since SA (Th11, -9933, Some("%")), // Writable since SA (Th11, -9932, Some("%")), // Writable since SA + + (Th12, -9931, Some("$")), + (Th12, -9930, Some("$")), ], -}; +}; \ No newline at end of file diff --git a/src/core_mapfiles/msg.rs b/src/core_mapfiles/msg.rs index 2df8894..e270fdf 100644 --- a/src/core_mapfiles/msg.rs +++ b/src/core_mapfiles/msg.rs @@ -103,7 +103,8 @@ static MSG_10_18: &CoreSignatures = &CoreSignatures { // th11 inserts one in the middle :( (Th11, 9, Some(("", None))), // new - (Th11, 10, Some(("S", None))), // 10...24 are TH10's 9...23 + // 10...24 are TH10's 9...23 + (Th11, 10, Some((r#"b(enum="bool")---"#, None))), // zero: b(enum="BitBool")--- (Th11, 11, Some(("S", None))), (Th11, 12, Some(("", None))), (Th11, 13, Some(("S", None))), diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index b337ce6..a75ffaf 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -103,7 +103,7 @@ static STD_095_18: &CoreSignatures = &CoreSignatures { (Th11, 17, Some(("S", None))), - (Th12, 18, Some(("SSfff", None))), + (Th12, 18, Some(("SUfff", None))), (Th14, 14, Some(("SNS", None))), // 'layer' argument added (Th14, 19, Some(("S", None))), From 88e5a47a2f9bbdd5fdc999bec32999350faf59c0 Mon Sep 17 00:00:00 2001 From: zero318 Date: Fri, 15 Jul 2022 01:24:53 -0400 Subject: [PATCH 14/26] Ninth batch of updated signatures and a few misc fixes --- src/core_mapfiles/ecl.rs | 16 +++++++++++++--- src/core_mapfiles/msg.rs | 2 ++ src/core_mapfiles/std.rs | 6 ++---- src/formats/anm/mod.rs | 4 ++-- src/formats/anm/read_write.rs | 2 +- src/llir/abi.rs | 12 +++++++----- src/llir/lower.rs | 33 +++++++++++++++++++++++++++------ src/llir/raise/early.rs | 2 +- 8 files changed, 55 insertions(+), 22 deletions(-) diff --git a/src/core_mapfiles/ecl.rs b/src/core_mapfiles/ecl.rs index 5366452..52b4cb3 100644 --- a/src/core_mapfiles/ecl.rs +++ b/src/core_mapfiles/ecl.rs @@ -629,7 +629,7 @@ static ECL_08_09: &'static CoreSignatures = &CoreSignatures { (Th08, 127, Some(("S", None))), (Th08, 128, Some(("S(imm)f(imm)f(imm)f(imm)f(imm)", None))), // Argument 1 is unread (Th08, 129, Some(("b(imm)---", None))), - (Th08, 130, Some((r#"s(imm;enum="EclSub")--"#, None))), + (Th08, 130, Some((r#"s(imm;extend;enum="EclSub")--"#, None))), (Th08, 131, Some(("S", None))), (Th08, 132, Some(("S", None))), (Th08, 133, Some(("SSE", None))), @@ -903,7 +903,7 @@ static ECL_095: &'static CoreSignatures = &CoreSignatures { (Th095, 81, Some(("U(hex)", None))), (Th095, 82, Some(("f", None))), (Th095, 83, Some(("E(imm)", None))), - (Th095, 84, Some(("E(imm)fff", None))), + (Th095, 84, Some(("E(imm)ff", None))), // Game engine reads E(imm)fff, but the files are cursed trash (Th095, 85, Some(("", None))), (Th095, 86, Some(("ssSSffffU(imm;hex)", None))), (Th095, 87, Some(("ssSSffffU(imm;hex)", None))), @@ -1088,6 +1088,7 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { (Th11, 276, Some(("", None))), (Th11, 277, Some(("Sf", None))), + (Th11, 278, Some(("S", None))), // Not implemented // Section B (Th10, 280, Some(("ff", None))), @@ -1243,6 +1244,11 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { (Th11, 448, Some(("S", None))), (Th11, 449, Some(("S", None))), (Th11, 450, Some(("S", None))), + + // Section E (Didn't exist yet) + + // Section F + (Th11, 500, Some(("S", None))), // Not implemented ], var: &[ // This is placed here to avoid putting game-specific @@ -1313,6 +1319,10 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { (Th12, 325, Some(("Sffffff", None))), (Th12, 326, Some(("Sffffff", None))), (Th12, 327, Some(("", None))), + (Th12, 328, Some(("ff", None))), + (Th12, 329, Some(("SSff", None))), + (Th12, 330, Some(("ff", None))), + (Th12, 331, Some(("SSff", None))), // Section C (Th12, 400, Some(("ff", None))), @@ -1430,7 +1440,7 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { (Th12, 611, Some(("S", None))), // Section F - (Th12, 700, Some(("S", None))), + (Th12, 700, Some(("S", None))), // Not implemented ], var: &[], }; diff --git a/src/core_mapfiles/msg.rs b/src/core_mapfiles/msg.rs index e270fdf..cf54ee1 100644 --- a/src/core_mapfiles/msg.rs +++ b/src/core_mapfiles/msg.rs @@ -127,6 +127,7 @@ static MSG_10_18: &CoreSignatures = &CoreSignatures { (Th12, 17, Some(("m(bs=4;mask=0x77,7,16;furibug)", None))), (Th12, 27, Some(("f", None))), // new + (Th128, 2, Some(("S", None))), // Argument started being non-zero (Th128, 28, Some(("ff", None))), (Th128, 29, Some(("S", None))), (Th128, 30, Some(("", None))), @@ -143,6 +144,7 @@ static MSG_10_18: &CoreSignatures = &CoreSignatures { (Th15, 33, None), // removed + (Th16, 1, Some(("S", None))), // Argument started being non-zero (Th16, 33, Some(("SS", None))), // replaced with something totally different (but unused) (Th16, 34, Some(("SS", None))), (Th16, 35, Some(("", None))), diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index a75ffaf..73bd4c5 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -85,8 +85,8 @@ static STD_095_18: &CoreSignatures = &CoreSignatures { (Th095, 7, Some(("f", None))), (Th095, 8, Some(("Cff", None))), (Th095, 9, Some(("Sbb--Cff", None))), - (Th095, 10, Some(("SUfffffffff", None))), - (Th095, 11, Some(("SUfffffffff", None))), + (Th095, 10, Some(("SUfffffffff", None))), // Technically S_fffffffff since MoF + (Th095, 11, Some(("SUfffffffff", None))), // Technically S_fffffffff since MoF (Th095, 12, Some(("b---", None))), (Th095, 13, Some(("C", None))), (Th095, 14, Some(("SN", None))), @@ -96,8 +96,6 @@ static STD_095_18: &CoreSignatures = &CoreSignatures { (Th10, 3, Some(("SUfff", None))), (Th10, 5, Some(("SUfff", None))), (Th10, 9, Some(("SUCff", None))), // Technically the C arg is split into 4 individual byte reads. But why tho - (Th10, 10, Some(("S_fffffffff", None))), - (Th10, 11, Some(("S_fffffffff", None))), (Alcostg, 16, Some(("S(imm)", Some(IKind::InterruptLabel)))), diff --git a/src/formats/anm/mod.rs b/src/formats/anm/mod.rs index 346fc20..b82964d 100644 --- a/src/formats/anm/mod.rs +++ b/src/formats/anm/mod.rs @@ -1154,7 +1154,7 @@ fn strip_unnecessary_sprite_ids<'a>(entry_sprites: impl IntoIterator(entry_sprites: impl IntoIterator, arg0: bool, immediate: bool, format: ast::IntFormat }, + Integer { size: u8, ty_color: Option, arg0: bool, immediate: bool, extend: bool, format: ast::IntFormat }, /// `o` in mapfile. Max of one per instruction. Is decoded to a label. JumpOffset, /// `t` in mapfile. Max of one per instruction, and requires an accompanying `o` arg. @@ -91,7 +91,7 @@ pub enum StringArgSize { } impl ArgEncoding { - pub fn dword() -> Self { ArgEncoding::Integer { size: 4, ty_color: None, arg0: false, immediate: false, format: ast::IntFormat { unsigned: false, radix: ast::IntRadix::Dec } } } + pub fn dword() -> Self { ArgEncoding::Integer { size: 4, ty_color: None, arg0: false, immediate: false, extend: false, format: ast::IntFormat { unsigned: false, radix: ast::IntRadix::Dec } } } pub fn static_descr(&self) -> &'static str { match self { @@ -115,10 +115,10 @@ impl ArgEncoding { impl fmt::Display for Impl<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &self.0 { - Enc::Integer { arg0: true, ty_color, size, immediate, format } => write!( + Enc::Integer { arg0: true, ty_color, size, immediate, format, extend } => write!( f, "{} (in timeline arg0)", - Enc::Integer { format: *format, immediate: *immediate, arg0: false, ty_color: ty_color.clone(), size: *size }.descr(), + Enc::Integer { extend: *extend, format: *format, immediate: *immediate, arg0: false, ty_color: ty_color.clone(), size: *size }.descr(), ), Enc::Integer { ty_color: Some(en), size: 4, .. } => write!(f, "{}", en.descr()), Enc::Integer { ty_color: Some(en), size, .. } => write!(f, "{size}-byte {}", en.descr()), @@ -275,6 +275,7 @@ fn int_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Result= 2 { @@ -299,6 +300,7 @@ fn int_from_attrs(param: &abi_ast::Param, emitter: &dyn Emitter) -> Result Info { ty: ScalarType::Int, default: None, reg_ok: true, ty_color: ty_color.clone() }, diff --git a/src/llir/lower.rs b/src/llir/lower.rs index 75377f1..d131e91 100644 --- a/src/llir/lower.rs +++ b/src/llir/lower.rs @@ -554,18 +554,25 @@ fn encode_args( let mut param_mask: raw::ParamMask = 0; let mut current_param_mask_bit: raw::ParamMask = 1; + let mut small_padding_value = 0i8; + // Important: we put the shortest iterator (args_iter) first in the zip list // to ensure that this loop reads an equal number of items from all iters. assert!(args_iter.len() <= arg_encodings_iter.len()); for enc in arg_encodings_iter.by_ref() { if let ArgEncoding::Padding { size } = enc { match size { - 1 => args_blob.write_u8(0).expect("Cursor failed?!"), + 1 => { + if (args_blob.position() & 3) == 0 { small_padding_value = 0i8 } + args_blob.write_i8(small_padding_value).expect("Cursor failed?!") + }, 4 => args_blob.write_u32(0).expect("Cursor failed?!"), _ => unreachable!(), } continue; } + small_padding_value = 0i8; + let arg = args_iter.next().expect("function arity already checked"); let arg_bit = match &arg.value { @@ -607,14 +614,28 @@ fn encode_args( | ArgEncoding::JumpOffset | ArgEncoding::JumpTime - | ArgEncoding::Integer { size: 4, format: ast::IntFormat { unsigned: false, radix: _ }, .. } => args_blob.write_i32(arg.expect_raw().expect_int()).expect("Cursor failed?!"), - | ArgEncoding::Integer { size: 2, format: ast::IntFormat { unsigned: false, radix: _ }, .. } - => args_blob.write_i16(arg.expect_raw().expect_int() as _).expect("Cursor failed?!"), + | ArgEncoding::Integer { size: 4, extend, format: ast::IntFormat { unsigned: false, radix: _ }, .. } + => { + let value = arg.expect_raw().expect_int(); + if extend && value < 0 { small_padding_value = -1 } + args_blob.write_i32(value).expect("Cursor failed?!") + }, - | ArgEncoding::Integer { size: 1, format: ast::IntFormat { unsigned: false, radix: _ }, .. } - => args_blob.write_i8(arg.expect_raw().expect_int() as _).expect("Cursor failed?!"), + | ArgEncoding::Integer { size: 2, extend, format: ast::IntFormat { unsigned: false, radix: _ }, .. } + => { + let value = arg.expect_raw().expect_int(); + if extend && value < 0 { small_padding_value = -1 } + args_blob.write_i16(value as _).expect("Cursor failed?!") + }, + + | ArgEncoding::Integer { size: 1, extend, format: ast::IntFormat { unsigned: false, radix: _ }, .. } + => { + let value = arg.expect_raw().expect_int(); + if extend && value < 0 { small_padding_value = -1 } + args_blob.write_i8(value as _).expect("Cursor failed?!") + }, | ArgEncoding::Integer { size: 4, format: ast::IntFormat { unsigned: true, radix: _ }, .. } => args_blob.write_u32(arg.expect_raw().expect_int() as _).expect("Cursor failed?!"), diff --git a/src/llir/raise/early.rs b/src/llir/raise/early.rs index 7858d70..122e9ee 100644 --- a/src/llir/raise/early.rs +++ b/src/llir/raise/early.rs @@ -593,7 +593,7 @@ impl AtomRaiser<'_, '_> { let pseudo_arg0 = match instr.pseudo_arg0 { None | Some(0) => None, Some(arg0) => { - let enc = ArgEncoding::Integer { size: 2, ty_color: None, arg0: true, immediate: true, format: ast::IntFormat { unsigned: false, radix: ast::IntRadix::Dec } }; + let enc = ArgEncoding::Integer { size: 2, ty_color: None, arg0: true, immediate: true, extend: false, format: ast::IntFormat { unsigned: false, radix: ast::IntRadix::Dec } }; let expr = self.raise_arg(emitter, &SimpleArg::from(arg0 as i32), &enc, dest_label)?; Some(expr) } From 26f14dc4b27ada0fbbaec299b23d8ecc5bb56111 Mon Sep 17 00:00:00 2001 From: zero318 Date: Fri, 26 Apr 2024 19:41:16 -0400 Subject: [PATCH 15/26] e --- src/ast/mod.rs | 6 +++ src/cli_def.rs | 19 +++++-- src/core_mapfiles/anm.rs | 89 +++++++++++++++++++++++--------- src/core_mapfiles/ecl.rs | 98 ++++++++++++++++++++++++++++-------- src/core_mapfiles/end.rs | 55 ++++++++++++++++++++ src/core_mapfiles/mod.rs | 3 +- src/core_mapfiles/msg.rs | 36 +++++++++++-- src/core_mapfiles/std.rs | 6 +-- src/fmt.rs | 2 +- src/formats/anm/mod.rs | 2 +- src/formats/msg.rs | 48 ++++++++++++++---- src/game.rs | 12 ++++- src/llir/abi.rs | 23 ++++++--- src/mapfile.rs | 2 + src/passes/const_simplify.rs | 6 +++ src/passes/type_check.rs | 6 +++ src/quote.rs | 3 ++ 17 files changed, 340 insertions(+), 76 deletions(-) create mode 100644 src/core_mapfiles/end.rs diff --git a/src/ast/mod.rs b/src/ast/mod.rs index ff16f38..0eb0c4a 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -699,6 +699,9 @@ string_enum! { #[strum(serialize = "~")] BitNot, #[strum(serialize = "sin")] Sin, #[strum(serialize = "cos")] Cos, + #[strum(serialize = "tan")] Tan, + #[strum(serialize = "acos")] Acos, + #[strum(serialize = "atan")] Atan, #[strum(serialize = "sqrt")] Sqrt, #[strum(serialize = "$")] EncodeI, #[strum(serialize = "%")] EncodeF, @@ -715,6 +718,9 @@ impl UnOpKind { UnOpKind::BitNot => OpClass::Bitwise, UnOpKind::Sin => OpClass::FloatMath, UnOpKind::Cos => OpClass::FloatMath, + UnOpKind::Tan => OpClass::FloatMath, + UnOpKind::Acos => OpClass::FloatMath, + UnOpKind::Atan => OpClass::FloatMath, UnOpKind::Sqrt => OpClass::FloatMath, UnOpKind::CastI => OpClass::Cast, UnOpKind::CastF => OpClass::Cast, diff --git a/src/cli_def.rs b/src/cli_def.rs index 690bee4..408905b 100644 --- a/src/cli_def.rs +++ b/src/cli_def.rs @@ -576,7 +576,10 @@ pub mod msg_compile { truth.load_mapfiles_from_pragmas(game, &ast)?; }, MsgMode::Mission => {}, - MsgMode::Ending => return Err(truth.emit(error!("--ending is not yet implemented"))), + MsgMode::Ending => { + load_mapfiles(truth, game, &[LanguageKey::End], mapfile_options)?; + truth.load_mapfiles_from_pragmas(game, &ast)?; + }, } let mut truth = truth.validate_defs()?; @@ -590,7 +593,10 @@ pub mod msg_compile { let msg = truth.compile_mission(game, &ast)?; truth.write_mission(game, out_path, &msg)?; }, - MsgMode::Ending => unreachable!(), + MsgMode::Ending => { + let msg = truth.compile_msg(game, LanguageKey::End, &ast)?; + truth.write_msg(game, LanguageKey::End, out_path, &msg)?; + }, } if let Some(debug_info_path) = debug_info_path { truth.prepare_and_write_debug_info(debug_info_path)?; @@ -636,7 +642,14 @@ pub mod msg_decompile { let msg = truth.read_mission(game, in_path)?; truth.decompile_mission(game, &msg) }, - MsgMode::Ending => return Err(truth.emit(error!("--ending is not yet implemented"))), + MsgMode::Ending => { + let mapfile_options = add_env_mapfile_for_decomp(mapfile_options, ".endm"); + load_mapfiles(truth, game, &[LanguageKey::End], &mapfile_options)?; + + let mut truth = truth.validate_defs()?; + let msg = truth.read_msg(game, LanguageKey::End, in_path)?; + truth.decompile_msg(game, LanguageKey::End, &msg, decompile_options) + }, } } } diff --git a/src/core_mapfiles/anm.rs b/src/core_mapfiles/anm.rs index 9ef283f..aa017a1 100644 --- a/src/core_mapfiles/anm.rs +++ b/src/core_mapfiles/anm.rs @@ -32,9 +32,9 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { OUT }, - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 => { + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => { static OUT: &CoreSignatures = &CoreSignatures { - inherit: &[ANM_INS_13_18, ANM_VAR], + inherit: &[ANM_INS_13_19, ANM_VAR], ins: &[], var: &[], }; OUT @@ -150,9 +150,9 @@ static ANM_INS_07_09: &'static CoreSignatures = &CoreSignatures { (Th07, 60, Some(("ff", None))), (Th07, 61, Some(("ff", Some(IKind::UnOp(U::Sin, Ty::Float))))), (Th07, 62, Some(("ff", Some(IKind::UnOp(U::Cos, Ty::Float))))), - (Th07, 63, Some(("ff", None))), - (Th07, 64, Some(("ff", None))), - (Th07, 65, Some(("ff", None))), + (Th07, 63, Some(("ff", Some(IKind::UnOp(U::Tan, Ty::Float))))), + (Th07, 64, Some(("ff", Some(IKind::UnOp(U::Acos, Ty::Float))))), + (Th07, 65, Some(("ff", Some(IKind::UnOp(U::Atan, Ty::Float))))), (Th07, 66, Some(("f", None))), (Th07, 67, Some(("SSot", Some(IKind::CondJmp(B::Eq, Ty::Int))))), (Th07, 68, Some(("ffot", Some(IKind::CondJmp(B::Eq, Ty::Float))))), @@ -240,9 +240,9 @@ static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { (Th095, 41, Some(("ff", None))), (Th095, 42, Some(("ff", Some(IKind::UnOp(U::Sin, Ty::Float))))), (Th095, 43, Some(("ff", Some(IKind::UnOp(U::Cos, Ty::Float))))), - (Th095, 44, Some(("ff", None))), - (Th095, 45, Some(("ff", None))), - (Th095, 46, Some(("ff", None))), + (Th095, 44, Some(("ff", Some(IKind::UnOp(U::Tan, Ty::Float))))), + (Th095, 45, Some(("ff", Some(IKind::UnOp(U::Acos, Ty::Float))))), + (Th095, 46, Some(("ff", Some(IKind::UnOp(U::Atan, Ty::Float))))), (Th095, 47, Some(("f", None))), (Th095, 48, Some(("fff", None))), (Th095, 49, Some(("fff", None))), @@ -328,9 +328,10 @@ static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { }; // v8 -static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { +static ANM_INS_13_19: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ + // Section A (Th13, 0, Some(("", None))), (Th13, 1, Some(("", None))), (Th13, 2, Some(("", None))), @@ -339,6 +340,8 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 5, Some(("S", Some(IKind::InterruptLabel)))), (Th13, 6, Some(("S", None))), (Th13, 7, Some(("", None))), + + // Section B (Th13, 100, Some(("SS", Some(IKind::AssignOp(A::Assign, Ty::Int))))), (Th13, 101, Some(("ff", Some(IKind::AssignOp(A::Assign, Ty::Float))))), (Th13, 102, Some(("SS", Some(IKind::AssignOp(A::Add, Ty::Int))))), @@ -365,12 +368,14 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 123, Some(("ff", None))), (Th13, 124, Some(("ff", Some(IKind::UnOp(U::Sin, Ty::Float))))), (Th13, 125, Some(("ff", Some(IKind::UnOp(U::Cos, Ty::Float))))), - (Th13, 126, Some(("ff", None))), - (Th13, 127, Some(("ff", None))), - (Th13, 128, Some(("ff", None))), + (Th13, 126, Some(("ff", Some(IKind::UnOp(U::Tan, Ty::Float))))), + (Th13, 127, Some(("ff", Some(IKind::UnOp(U::Acos, Ty::Float))))), + (Th13, 128, Some(("ff", Some(IKind::UnOp(U::Atan, Ty::Float))))), (Th13, 129, Some(("f", None))), (Th13, 130, Some(("ffff", None))), (Th13, 131, Some(("ffff", None))), + + // Section C (Th13, 200, Some(("ot", Some(IKind::Jmp)))), (Th13, 201, Some(("Sot", Some(IKind::CountJmp(B::Ne))))), (Th13, 202, Some(("SSot", Some(IKind::CondJmp(B::Eq, Ty::Int))))), @@ -385,6 +390,8 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 211, Some(("ffot", Some(IKind::CondJmp(B::Gt, Ty::Float))))), (Th13, 212, Some(("SSot", Some(IKind::CondJmp(B::Ge, Ty::Int))))), (Th13, 213, Some(("ffot", Some(IKind::CondJmp(B::Ge, Ty::Float))))), + + // Section D (Th13, 300, Some(("n", None))), (Th13, 301, Some(("nS", None))), (Th13, 302, Some(("S", None))), @@ -398,6 +405,18 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 310, Some(("S", None))), (Th13, 311, Some(("S", None))), (Th13, 312, Some(("SS", None))), + + (Th14, 313, Some(("S", None))), + (Th14, 314, Some(("S", None))), + (Th14, 315, Some(("S", None))), + + (Th143, 316, Some(("", None))), + (Th143, 317, Some(("", None))), + + (Th19, 318, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th19, 319, Some(("nnnn", None))), + + // Section E (Th13, 400, Some(("fff", None))), (Th13, 401, Some(("fff", None))), (Th13, 402, Some(("ff", None))), @@ -437,6 +456,16 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 436, Some(("ff", None))), (Th13, 437, Some(("S", None))), (Th13, 438, Some(("S", None))), + + (Th165, 439, Some(("S", None))), // files use this, but it's not in the jumptable! + + (Th17, 439, None), // ... TH17 doesn't use it ... + + (Th18, 439, Some(("Sff", None))), // ...and TH18 demo reused its ID for something else! + + (Th185, 440, Some(("", None))), + + // Section F (Th13, 500, Some(("N", None))), (Th13, 501, Some(("N", None))), (Th13, 502, Some(("N", None))), @@ -446,6 +475,12 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 506, Some(("Nff", None))), (Th13, 507, Some(("S", None))), (Th13, 508, Some(("S", None))), + + (Th14, 509, Some(("", None))), + + (Th19, 510, Some(("Nff", None))), + + // Section G (Th13, 600, Some(("S", None))), (Th13, 601, Some(("S", None))), (Th13, 602, Some(("S", None))), @@ -456,26 +491,34 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 607, Some(("ff", None))), (Th13, 608, Some(("ff", None))), - (Th14, 313, Some(("S", None))), - (Th14, 314, Some(("S", None))), - (Th14, 315, Some(("S", None))), - (Th14, 509, Some(("", None))), (Th14, 609, Some(("S", None))), (Th14, 610, Some(("S", None))), - (Th143, 316, Some(("", None))), - (Th143, 317, Some(("", None))), (Th143, 611, Some(("ffS", None))), (Th16, 612, Some(("ff", None))), (Th16, 613, Some(("ff", None))), - (Th165, 439, Some(("S", None))), // files use this, but it's not in the jumptable! - - (Th17, 439, None), // ... TH17 doesn't use it ... - - (Th18, 439, Some(("Sff", None))), // ...and TH18 demo reused its ID for something else! (Th18, 614, Some(("ff", None))), + + (Th19, 615, Some(("ffS", None))), + (Th19, 616, Some(("ffS", None))), + (Th19, 617, Some(("fS", None))), + (Th19, 618, Some(("", None))), + (Th19, 619, Some(("fS", None))), + (Th19, 620, Some(("ffS", None))), + (Th19, 621, Some(("ffS", None))), + (Th19, 622, Some(("ffS", None))), + (Th19, 623, Some(("fffS", None))), + (Th19, 624, Some(("fffS", None))), + (Th19, 625, Some(("ffffS", None))), + (Th19, 626, Some(("ffffS", None))), + (Th19, 627, Some(("ffffS", None))), + (Th19, 628, Some(("fS", None))), + (Th19, 629, Some(("fS", None))), + (Th19, 630, Some(("ffS", None))), + (Th19, 631, Some(("ffS", None))), + (Th19, 632, Some(("ffS", None))), ], var: &[], }; diff --git a/src/core_mapfiles/ecl.rs b/src/core_mapfiles/ecl.rs index 52b4cb3..793d045 100644 --- a/src/core_mapfiles/ecl.rs +++ b/src/core_mapfiles/ecl.rs @@ -13,10 +13,10 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { Th08 | Th09 => ECL_08_09, Th095 => ECL_095, Th10 | Alcostg | Th11 => ECL_10_11, - Th12 => ECL_12, + Th12 | Th125 => ECL_12, - Th125 | Th128 | - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 => CoreSignatures::EMPTY, + Th128 | + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => CoreSignatures::EMPTY, } } @@ -25,7 +25,7 @@ pub(super) fn timeline_core_signatures(game: Game) -> &'static CoreSignatures { Th06 | Th07 | Th08 | Th09 | Th095 => TIMELINE, Th10 | Alcostg | Th11 | Th12 | Th125 | Th128 | - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 => CoreSignatures::EMPTY, + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => CoreSignatures::EMPTY, } } @@ -1061,9 +1061,9 @@ static ECL_095: &'static CoreSignatures = &CoreSignatures { static ECL_10_11: &'static CoreSignatures = &CoreSignatures { - inherit: &[ECL_10_18_COMMON], + inherit: &[ECL_10_19_COMMON], ins: &[ - // Section A + // Section B (Th10, 256, Some(("P(bs=4)ffSSS", None))), (Th10, 257, Some(("P(bs=4)ffSSS", None))), (Th10, 258, Some(("S", None))), @@ -1090,7 +1090,7 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { (Th11, 277, Some(("Sf", None))), (Th11, 278, Some(("S", None))), // Not implemented - // Section B + // Section C (Th10, 280, Some(("ff", None))), (Th10, 281, Some(("SSff", None))), (Th10, 282, Some(("ff", None))), @@ -1124,7 +1124,7 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { (Th11, 306, Some(("Sffffff", None))), (Th11, 307, Some(("", None))), - // Section C + // Section D (Th10, 320, Some(("ff", None))), (Th10, 321, Some(("ff", None))), (Th10, 322, Some(("S(hex)", None))), @@ -1182,7 +1182,7 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { (Th11, 371, Some(("S", None))), (Th11, 372, Some(("S", None))), - // Section D + // Section E (Th10, 400, Some(("S", None))), (Th10, 401, Some(("S", None))), (Th10, 402, Some(("SSS", None))), @@ -1245,10 +1245,14 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { (Th11, 449, Some(("S", None))), (Th11, 450, Some(("S", None))), - // Section E (Didn't exist yet) + // Section F (Didn't exist yet) - // Section F + // Section G (Didn't exist yet) + + // Section H (Th11, 500, Some(("S", None))), // Not implemented + + // Section I (Didn't exist yet) ], var: &[ // This is placed here to avoid putting game-specific @@ -1260,9 +1264,9 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { static ECL_12: &'static CoreSignatures = &CoreSignatures { - inherit: &[ECL_10_18_COMMON], + inherit: &[ECL_10_19_COMMON], ins: &[ - // Section A + // Section B (Th12, 256, Some(("P(bs=4)ffSSS", None))), (Th12, 257, Some(("P(bs=4)ffSSS", None))), (Th12, 258, Some(("S", None))), @@ -1289,8 +1293,9 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { (Th12, 279, Some(("Sff", None))), (Th12, 280, Some(("P(bs=4)ffSSS", None))), (Th12, 281, Some(("SS", None))), + (Th125, 282, Some(("SS", None))), - // Section B + // Section C (Th12, 300, Some(("ff", None))), (Th12, 301, Some(("SSff", None))), (Th12, 302, Some(("ff", None))), @@ -1323,8 +1328,10 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { (Th12, 329, Some(("SSff", None))), (Th12, 330, Some(("ff", None))), (Th12, 331, Some(("SSff", None))), + (Th125, 332, Some(("S", None))), + (Th125, 333, Some(("S", None))), - // Section C + // Section D (Th12, 400, Some(("ff", None))), (Th12, 401, Some(("ff", None))), (Th12, 402, Some(("S(hex)", None))), @@ -1383,7 +1390,18 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { (Th12, 455, Some(("SS", None))), (Th12, 456, Some(("ffS", None))), - // Section D + (Th125, 427, None), + (Th125, 440, None), + (Th125, 454, None), + (Th125, 457, Some(("", None))), + (Th125, 458, Some(("S", None))), + (Th125, 459, Some(("S", None))), + (Th125, 460, Some(("f", None))), + (Th125, 461, Some(("f", None))), + (Th125, 462, Some(("S", None))), + // (Th125, 463, Some(("P(bs=4)", None))), + + // Section E (Th12, 500, Some(("S", None))), (Th12, 501, Some(("S", None))), (Th12, 502, Some(("SSS", None))), @@ -1424,8 +1442,9 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { // Final laser instruction moved (Th12, 534, Some(("S", None))), (Th12, 535, Some(("S", None))), + (Th125, 536, Some(("S", None))), - // Section E + // Section F (Th12, 600, Some(("Sffff", None))), (Th12, 601, Some(("SSSSSS(hex)", None))), (Th12, 602, Some(("S", None))), @@ -1438,15 +1457,20 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { (Th12, 609, Some(("Sf", None))), (Th12, 610, Some(("S", None))), (Th12, 611, Some(("S", None))), + (Th125, 612, Some(("ff", None))), - // Section F + // Section G (Didn't exist yet) + + // Section H (Th12, 700, Some(("S", None))), // Not implemented + + // Section I (Didn't exist yet) ], var: &[], }; -static ECL_10_18_COMMON: &'static CoreSignatures = &CoreSignatures { +static ECL_10_19_COMMON: &'static CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th10, 0, Some(("", None))), @@ -1463,7 +1487,7 @@ static ECL_10_18_COMMON: &'static CoreSignatures = &CoreSignatures { (Th10, 19, Some(("S", None))), (Th10, 20, Some(("SS", None))), (Th10, 21, Some(("", None))), - // (Th10, 30, Some((r#"p(bs=4)v(rep="g")"#, None))), + // (Th10, 30, Some((r#"p(bs=4)v(rep="g")"#, None))), // Implementation removed as of DS (Th10, 40, Some(("S", None))), // Some(IKind::FrameEnter) (Th10, 41, Some(("", None))), // Some(IKind::FrameLeave) (Th10, 42, Some(("S", None))), // Some(IKind::Push(Ty::Int)) @@ -1505,7 +1529,7 @@ static ECL_10_18_COMMON: &'static CoreSignatures = &CoreSignatures { (Th10, 82, Some(("f", None))), (Th10, 83, Some(("S", None))), (Th10, 84, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Int)) - (Th10, 85, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Float)) + (Th10, 85, Some(("", None))), // NOT an intrinsic, since it's broken (Th10, 86, Some(("fff", None))), (Th10, 87, Some(("ffff", None))), @@ -1514,6 +1538,14 @@ static ECL_10_18_COMMON: &'static CoreSignatures = &CoreSignatures { (Alcostg, 88, Some(("", None))), // Some(IKind::StackUnOp(U::Sqrt, Ty::Float)) (Th12, 89, Some(("fff", None))), + + // Finally not broken + (Th125, 85, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Float)) + (Th125, 90, Some(("fffff", None))), + (Th125, 91, Some(("SfSSff", None))), + (Th125, 92, Some(("SfSSffff", None))), + + (Th128, 22, Some((r#"SP(bs=4)"#, None))), ], var: &[ (Th10, -10000, Some("$")), @@ -1590,5 +1622,27 @@ static ECL_10_18_COMMON: &'static CoreSignatures = &CoreSignatures { (Th12, -9931, Some("$")), (Th12, -9930, Some("$")), + + (Th125, -9930, Some("$")), + (Th125, -9929, Some("$")), + (Th125, -9928, Some("$")), + (Th125, -9927, Some("$")), + (Th125, -9926, Some("$")), + (Th125, -9925, Some("$")), + (Th125, -9924, Some("$")), + (Th125, -9923, Some("$")), + (Th125, -9922, Some("%")), + (Th125, -9921, Some("%")), + (Th125, -9920, Some("%")), + (Th125, -9919, Some("%")), + (Th125, -9918, Some("%")), + (Th125, -9917, Some("%")), + (Th125, -9916, Some("%")), + (Th125, -9915, Some("%")), + (Th125, -9914, Some("$")), + (Th125, -9913, Some("$")), + (Th125, -9912, Some("$")), + (Th125, -9911, Some("%")), + (Th125, -9910, Some("%")), ], -}; \ No newline at end of file +}; diff --git a/src/core_mapfiles/end.rs b/src/core_mapfiles/end.rs new file mode 100644 index 0000000..889675f --- /dev/null +++ b/src/core_mapfiles/end.rs @@ -0,0 +1,55 @@ +use super::CoreSignatures; +use crate::Game::{self, *}; + +pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { + match game { + | Th095 | Alcostg | Th125 | Th143 | Th165 | Th185 + => EMPTY, + + | Th06 | Th07 | Th08 | Th09 + => END_06_09, + + | Th10 | Th11 | Th12 | Th128 | Th13 + | Th14 | Th15 | Th16 | Th17 | Th18 | Th19 + => END_10_19, + } +} + +// Bunkachou titles have no true END scripts. +static EMPTY: &CoreSignatures = &CoreSignatures { + inherit: &[], + ins: &[], + var: &[], +}; + +static END_06_09: &CoreSignatures = &CoreSignatures { + inherit: &[], + // TODO + ins: &[], + var: &[], +}; + +static END_10_19: &CoreSignatures = &CoreSignatures { + inherit: &[], + ins: &[ + (Th10, 0, Some(("", None))), + (Th10, 1, None), + (Th10, 2, None), + (Th10, 3, Some(("m(bs=4;mask=0x77,7,16)", None))), + (Th10, 4, Some(("", None))), + (Th10, 5, Some(("S", None))), + (Th10, 6, Some(("S", None))), + (Th10, 7, Some(("Sz(bs=4)", None))), + (Th10, 8, Some(("SSN", None))), + (Th10, 9, Some(("C", None))), + (Th10, 10, Some(("z(bs=4)", None))), + (Th10, 11, Some(("", None))), + (Th10, 12, Some(("z(bs=4)", None))), + (Th10, 13, Some(("S", None))), + (Th10, 14, Some(("S", None))), + (Th10, 15, Some(("SSN", None))), + (Th10, 16, Some(("SSN", None))), + (Th10, 17, Some(("SSN", None))), + ], + var: &[], +}; diff --git a/src/core_mapfiles/mod.rs b/src/core_mapfiles/mod.rs index 21de548..34ae1d9 100644 --- a/src/core_mapfiles/mod.rs +++ b/src/core_mapfiles/mod.rs @@ -8,6 +8,7 @@ use crate::llir::IntrinsicInstrKind; mod anm; mod ecl; +mod end; mod msg; mod std; @@ -20,7 +21,7 @@ pub fn core_mapfile(emitter: &RootEmitter, game: Game, language: LanguageKey) -> LanguageKey::Msg => self::msg::core_signatures(game), LanguageKey::Ecl => self::ecl::core_signatures(game), LanguageKey::Timeline => self::ecl::timeline_core_signatures(game), - LanguageKey::End => CoreSignatures::EMPTY, // TODO + LanguageKey::End => self::end::core_signatures(game), LanguageKey::Dummy => CoreSignatures::EMPTY, }; diff --git a/src/core_mapfiles/msg.rs b/src/core_mapfiles/msg.rs index cf54ee1..a166cd5 100644 --- a/src/core_mapfiles/msg.rs +++ b/src/core_mapfiles/msg.rs @@ -3,15 +3,15 @@ use crate::Game::{self, *}; pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { match game { - | Th095 | Th125 + | Th095 | Alcostg => EMPTY, | Th06 | Th07 | Th08 | Th09 => MSG_06_09, - | Th10 | Alcostg | Th11 | Th12 | Th128 | Th13 - | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 - => MSG_10_18, + | Th10 | Th11 | Th12 | Th125 | Th128 | Th13 + | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 + => MSG_10_19, } } @@ -73,7 +73,7 @@ static MSG_06_09: &CoreSignatures = &CoreSignatures { ], var: &[], }; -static MSG_10_18: &CoreSignatures = &CoreSignatures { +static MSG_10_19: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th10, 0, Some(("", None))), @@ -161,6 +161,32 @@ static MSG_10_18: &CoreSignatures = &CoreSignatures { (Th18, 7, Some(("S", None))), (Th18, 13, Some(("SS", None))), (Th18, 36, Some(("", None))), + + (Th185, 19, Some(("S", None))), + (Th185, 37, Some(("", None))), + (Th185, 38, Some(("", None))), + (Th185, 39, Some(("", None))), + (Th185, 40, Some(("m(bs=4;mask=0x77,7,16;furibug)", None))), // Just hoping these string types are correct + (Th185, 41, Some(("m(bs=4;mask=0x77,7,16;furibug)", None))), + + // Th19 Notes: + // 20 doesn't read an argument, check size + (Th19, 31, None), + (Th19, 42, Some(("S", None))), + (Th19, 43, Some(("S", None))), + (Th19, 44, Some(("ff", None))), + (Th19, 45, Some(("ff", None))), + (Th19, 46, Some(("SS", None))), + (Th19, 47, Some(("SS", None))), + (Th19, 48, Some(("S", None))), + (Th19, 49, Some(("S", None))), + (Th19, 50, Some(("S", None))), + (Th19, 51, Some(("S", None))), + (Th19, 52, Some(("", None))), + (Th19, 53, Some(("", None))), + (Th19, 54, Some(("", None))), + (Th19, 55, Some(("", None))), + (Th19, 56, Some(("", None))), ], var: &[], }; diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index 73bd4c5..2127811 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -11,8 +11,8 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { => STD_07_09, | Th095 | Th10 | Alcostg | Th11 | Th12 | Th125 | Th128 - | Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 - => STD_095_18 + | Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 + => STD_095_19 } } @@ -72,7 +72,7 @@ static STD_07_09: &CoreSignatures = &CoreSignatures { var: &[], }; -static STD_095_18: &CoreSignatures = &CoreSignatures { +static STD_095_19: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th095, 0, Some(("", None))), diff --git a/src/fmt.rs b/src/fmt.rs index 7c5480d..d87a0fe 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -892,7 +892,7 @@ impl Format for ast::Expr { token![unop $] | token![unop %] | token![unop int] | token![unop float] | - token![sin] | token![cos] | token![sqrt] + token![sin] | token![cos] | token![tan] | token![acos] | token![atan] | token![sqrt] => out.fmt((op, "(", SuppressParens(x), ")")), }, ast::Expr::XcrementOp { order: ast::XcrementOpOrder::Pre, op, var } => out.fmt((op, var)), diff --git a/src/formats/anm/mod.rs b/src/formats/anm/mod.rs index b82964d..4a2d5a5 100644 --- a/src/formats/anm/mod.rs +++ b/src/formats/anm/mod.rs @@ -1185,7 +1185,7 @@ impl Version { Th08 | Th09 => Version::V3, Th095 | Th10 | Alcostg => Version::V4, Th11 | Th12 | Th125 | Th128 => Version::V7, - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 => Version::V8, + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => Version::V8, } } diff --git a/src/formats/msg.rs b/src/formats/msg.rs index b85aa4c..1616602 100644 --- a/src/formats/msg.rs +++ b/src/formats/msg.rs @@ -22,6 +22,7 @@ use indexmap::IndexMap; pub struct MsgFile { pub dense_table: Vec, pub scripts: IndexMap>, + pub extended_header: Option>, /// Filename of a read binary file, for display purposes only. binary_filename: Option, } @@ -395,6 +396,7 @@ fn compile( Ok(MsgFile { dense_table, scripts, + extended_header: None, /// Filename of a read binary file, for display purposes only. binary_filename: None, }) @@ -436,6 +438,13 @@ fn read_msg( let start_pos = reader.pos()?; let script_table_len = reader.read_u32()?; + + let extended_header = if format.extended_header() { + Some(reader.read_u32s(20)?) + } else { + None + }; + let script_table = { (0..script_table_len).map(|_| { Ok(RawScriptTableEntry { @@ -486,7 +495,7 @@ fn read_msg( }).collect(); let binary_filename = Some(reader.display_filename().to_owned()); - Ok(MsgFile { dense_table, scripts, binary_filename }) + Ok(MsgFile { dense_table, scripts, extended_header, binary_filename }) } #[derive(Debug)] @@ -588,8 +597,24 @@ fn write_msg( fn game_format(game: Game, language: LanguageKey, emitter: &RootEmitter) -> Result { match (game, language) { | (Game::Th095, LanguageKey::Msg) - | (Game::Th125, LanguageKey::Msg) - => Err(emitter.emit(error!("{} does not have stage MSG files; maybe try 'trumsg --mission'?", game))), + | (Game::Th095, LanguageKey::End) + => Err(emitter.emit(error!("{} does not have MSG files; maybe try 'trumsg --mission'?", game))), + + | (Game::Alcostg, LanguageKey::Msg) + | (Game::Alcostg, LanguageKey::End) + => Err(emitter.emit(error!("{} does not have MSG files", game))), + + | (Game::Th125, LanguageKey::End) + | (Game::Th143, LanguageKey::End) + | (Game::Th165, LanguageKey::End) + | (Game::Th185, LanguageKey::End) + => Err(emitter.emit(error!("{} does not have ending MSG files", game))), + + | (Game::Th06, LanguageKey::End) + | (Game::Th07, LanguageKey::End) + | (Game::Th08, LanguageKey::End) + | (Game::Th09, LanguageKey::End) + => Err(emitter.emit(error!("--ending is not yet implemented for {}", game))), _ => Ok(FileFormat { game, language }) } @@ -606,18 +631,23 @@ impl FileFormat { fn table_has_flags(&self) -> bool { self.game >= Game::Th09 } + + fn extended_header(&self) -> bool { + self.language == LanguageKey::Msg && self.game == Game::Th19 + } fn language_hooks(&self) -> Box { match self.game { | Game::Th06 | Game::Th07 | Game::Th08 - | Game::Th09 | Game::Th10 | Game::Alcostg | Game::Th11 - | Game::Th12 | Game::Th128 | Game::Th13 - | Game::Th14 | Game::Th143 | Game::Th15 - | Game::Th16 | Game::Th165 | Game::Th17 - | Game::Th18 + | Game::Th09 | Game::Th10 | Game::Th11 + | Game::Th12 | Game::Th125 | Game::Th128 + | Game::Th13 | Game::Th14 | Game::Th143 + | Game::Th15 | Game::Th16 | Game::Th165 + | Game::Th17 | Game::Th18 | Game::Th185 + | Game::Th19 => Box::new(MsgHooks { language: self.language }), - | Game::Th095 | Game::Th125 + | Game::Th095 | Game::Alcostg => unreachable!(), } } diff --git a/src/game.rs b/src/game.rs index 0301beb..b3d91be 100644 --- a/src/game.rs +++ b/src/game.rs @@ -6,8 +6,9 @@ use crate::diagnostic::Diagnostic; pub enum Game { Th06, Th07, Th08, Th09, Th095, Th10, Alcostg, Th11, Th12, Th125, Th128, Th13, Th14, Th143, Th15, Th16, Th165, Th17, Th18, + Th185, Th19 } -macro_rules! max_game_str { () => { "th18" }; } +macro_rules! max_game_str { () => { "th19" }; } impl std::str::FromStr for Game { type Err = Diagnostic; @@ -46,6 +47,8 @@ impl std::str::FromStr for Game { 165 => Ok(Game::Th165), 17 => Ok(Game::Th17), 18 => Ok(Game::Th18), + 185 => Ok(Game::Th185), + 19 => Ok(Game::Th19), _ => Err(unknown_game()), } } @@ -73,6 +76,8 @@ impl Game { Game::Th165 => "VD", Game::Th17 => "WBaWC", Game::Th18 => "UM", + Game::Th185 => "HBM", + Game::Th19 => "UDoALG", } } @@ -97,6 +102,9 @@ impl Game { Game::Th165 => "th165", Game::Th17 => "th17", Game::Th18 => "th18", + Game::Th185 => "th185", + Game::Th19 => "th19", + } } @@ -121,6 +129,8 @@ impl Game { Game::Th165 => 165, Game::Th17 => 17, Game::Th18 => 18, + Game::Th185 => 185, + Game::Th19 => 19, } } } diff --git a/src/llir/abi.rs b/src/llir/abi.rs index 0bd7eea..68957f0 100644 --- a/src/llir/abi.rs +++ b/src/llir/abi.rs @@ -42,7 +42,14 @@ pub enum ArgEncoding { /// The first argument may have `arg0` if it is two bytes large. This indicates that the argument is /// stored in the arg0 header field of the instruction in EoSD and PCB ECL. (which is mapped to the /// `@arg0` pseudo-argument in raw instruction syntax) - Integer { size: u8, ty_color: Option, arg0: bool, immediate: bool, extend: bool, format: ast::IntFormat }, + Integer { + size: u8, + ty_color: Option, + arg0: bool, + immediate: bool, + extend: bool, + format: ast::IntFormat + }, /// `o` in mapfile. Max of one per instruction. Is decoded to a label. JumpOffset, /// `t` in mapfile. Max of one per instruction, and requires an accompanying `o` arg. @@ -114,12 +121,14 @@ impl ArgEncoding { impl fmt::Display for Impl<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match &self.0 { - Enc::Integer { arg0: true, ty_color, size, immediate, format, extend } => write!( - f, - "{} (in timeline arg0)", - Enc::Integer { extend: *extend, format: *format, immediate: *immediate, arg0: false, ty_color: ty_color.clone(), size: *size }.descr(), - ), + match self.0 { + Enc::Integer { arg0: true, .. } => { + let mut temp = self.0.clone(); + write!(f, "{} (in timeline arg0)", match &mut temp { + Enc::Integer { arg0, .. } => { *arg0 = false; temp }, + _ => unreachable!(), + }.descr()) + }, Enc::Integer { ty_color: Some(en), size: 4, .. } => write!(f, "{}", en.descr()), Enc::Integer { ty_color: Some(en), size, .. } => write!(f, "{size}-byte {}", en.descr()), Enc::Integer { ty_color: None, size: 1, .. } => write!(f, "byte-sized integer"), diff --git a/src/mapfile.rs b/src/mapfile.rs index 6165a5b..a686a3b 100644 --- a/src/mapfile.rs +++ b/src/mapfile.rs @@ -174,6 +174,7 @@ fn mapfile_from_seqmap(seqmap: SeqmapRaw<'_>, emitter: &impl Emitter) -> Result< "!anmmap" => LanguageKey::Anm, "!stdmap" => LanguageKey::Std, "!msgmap" => LanguageKey::Msg, + "!endmap" => LanguageKey::End, TIMELINE_MAP_MAGIC => LanguageKey::Timeline, _ => return Err(emitter.emit(error!( message("bad magic: {:?}", magic), @@ -285,6 +286,7 @@ fn borrowed_seqmap_from_mapfile(mapfile: &Mapfile) -> SeqmapRaw<'_> { LanguageKey::Anm => "!anmmap", LanguageKey::Std => "!stdmap", LanguageKey::Msg => "!msgmap", + LanguageKey::End => "!endmap", LanguageKey::Timeline => TIMELINE_MAP_MAGIC, _ => unimplemented!("unexpected language key: {language:?}"), }; diff --git a/src/passes/const_simplify.rs b/src/passes/const_simplify.rs index 26ead1f..56144af 100644 --- a/src/passes/const_simplify.rs +++ b/src/passes/const_simplify.rs @@ -51,6 +51,9 @@ impl ast::UnOpKind { token![unop ~] => Some(ScalarValue::Int(!x)), token![unop sin] | token![unop cos] | + token![unop tan] | + token![unop acos] | + token![unop atan] | token![unop sqrt] => uncaught_type_error(), token![unop int] => Some(ScalarValue::Int(x)), token![unop float] => Some(ScalarValue::Float(x as f32)), @@ -64,6 +67,9 @@ impl ast::UnOpKind { token![unop ~] => uncaught_type_error(), token![unop sin] => Some(ScalarValue::Float(x.sin())), token![unop cos] => Some(ScalarValue::Float(x.cos())), + token![unop tan] => Some(ScalarValue::Float(x.tan())), + token![unop acos] => Some(ScalarValue::Float(x.acos())), + token![unop atan] => Some(ScalarValue::Float(x.atan())), token![unop sqrt] => Some(ScalarValue::Float(x.sqrt())), token![unop int] => Some(ScalarValue::Int(x as i32)), token![unop float] => Some(ScalarValue::Float(x)), diff --git a/src/passes/type_check.rs b/src/passes/type_check.rs index 96cd6d5..6552a93 100644 --- a/src/passes/type_check.rs +++ b/src/passes/type_check.rs @@ -652,6 +652,9 @@ impl ExprTypeChecker<'_, '_> { | token![unop sin] | token![unop cos] + | token![unop tan] + | token![unop acos] + | token![unop atan] | token![unop sqrt] => self.require_float(arg_ty, op.span, arg_span), } @@ -681,6 +684,9 @@ impl ast::Expr { token![unop sin] | token![unop cos] | + token![unop tan] | + token![unop acos] | + token![unop atan] | token![unop sqrt] => ScalarType::Float, token![unop $] => ScalarType::Int, diff --git a/src/quote.rs b/src/quote.rs index baa1546..6a9c540 100644 --- a/src/quote.rs +++ b/src/quote.rs @@ -33,6 +33,9 @@ macro_rules! token { ($(unop)? ~) => { $crate::ast::UnOpKind::BitNot }; ($(unop)? sin) => { $crate::ast::UnOpKind::Sin }; ($(unop)? cos) => { $crate::ast::UnOpKind::Cos }; + ($(unop)? tan) => { $crate::ast::UnOpKind::Tan }; + ($(unop)? acos) => { $crate::ast::UnOpKind::Acos }; + ($(unop)? atan) => { $crate::ast::UnOpKind::Atan }; ($(unop)? sqrt) => { $crate::ast::UnOpKind::Sqrt }; ( unop $) => { $crate::ast::UnOpKind::EncodeI }; ( unop %) => { $crate::ast::UnOpKind::EncodeF }; From 6e5e625a6786413282a09b3b7231681939a9ee11 Mon Sep 17 00:00:00 2001 From: zero318 Date: Sat, 27 Apr 2024 02:32:08 -0400 Subject: [PATCH 16/26] Fixed roundtrip problems --- src/formats/anm/mod.rs | 31 +++++- src/formats/anm/read_write.rs | 73 ++++++++++--- src/formats/msg.rs | 53 ++++++--- src/formats/std.rs | 32 ++++-- src/image/color.rs | 195 +++++++++++++++++++++++++++++++++- src/io.rs | 6 ++ src/llir/abi.rs | 20 ++++ 7 files changed, 366 insertions(+), 44 deletions(-) diff --git a/src/formats/anm/mod.rs b/src/formats/anm/mod.rs index 4a2d5a5..6783265 100644 --- a/src/formats/anm/mod.rs +++ b/src/formats/anm/mod.rs @@ -225,6 +225,9 @@ pub struct EntrySpecs { /// e.g. the border around the game. (not used for things like `ascii.anm` which have dedicated files /// for each resolution) pub low_res_scale: bool, + pub jpeg_quality: u32, + pub full_width: u32, + pub full_height: u32, } #[derive(Debug, Clone, Default)] @@ -244,6 +247,9 @@ struct WorkingEntrySpecs { offset_y: SoftOption, memory_priority: SoftOption, low_res_scale: SoftOption, + jpeg_quality: SoftOption, + full_width: SoftOption, + full_height: SoftOption, } fn default_memory_priority(version: Version) -> u32 { @@ -267,6 +273,9 @@ fn finalize_entry(fs: &Fs, entry: WorkingEntry, game: Game, emitter: &impl Emitt specs.memory_priority.set_soft_if_missing(default_memory_priority(version)); specs.low_res_scale.set_soft_if_missing(DEFAULT_LOW_RES_SCALE); specs.has_data.set_soft_if_missing(DEFAULT_HAS_DATA); + specs.jpeg_quality.set_soft_if_missing(0); + specs.full_width.set_soft_if_missing(0); + specs.full_height.set_soft_if_missing(0); // Do this now. For missing images that are also missing metadata, // this tends to produce the nicest error message. @@ -314,6 +323,9 @@ fn finalize_entry(fs: &Fs, entry: WorkingEntry, game: Game, emitter: &impl Emitt colorkey: specs.colorkey.into_option().expect("was filled by default"), memory_priority: specs.memory_priority.into_option().expect("was filled by default"), low_res_scale: specs.low_res_scale.into_option().expect("was filled by default"), + jpeg_quality: specs.jpeg_quality.into_option().expect("was filled by default"), + full_width: specs.full_width.into_option().expect("was filled by default"), + full_height: specs.full_height.into_option().expect("was filled by default"), }, texture_metadata: texture_data.as_ref().map(|_| TextureMetadata { width: specs.img_width.into_option().expect("was filled by default"), @@ -534,6 +546,7 @@ impl Entry { let EntrySpecs { rt_width, rt_height, rt_format, colorkey, offset_x, offset_y, memory_priority, low_res_scale, + jpeg_quality, full_width, full_height, } = self.specs; // suppress defaults @@ -562,6 +575,9 @@ impl Entry { .field_opt("rt_format", Some(rt_format).filter(|&x| x != img_format).map(format_to_meta)) .field_opt("memory_priority", Some(memory_priority).filter(|&x| x != default_memory_priority(version))) .field_opt("low_res_scale", Some(low_res_scale).filter(|&x| x != DEFAULT_LOW_RES_SCALE)) + .field_opt("jpeg_quality", Some(jpeg_quality).filter(|&x| x != 0)) + .field_opt("full_width", Some(full_width).filter(|&x| x != 0)) + .field_opt("full_height", Some(full_height).filter(|&x| x != 0)) .field("sprites", &self.sprites) .build_fields() } @@ -641,6 +657,9 @@ impl WorkingEntry { let memory_priority = make_explicit(m.get_field("memory_priority")?); let low_res_scale = make_explicit(m.get_field("low_res_scale")?); let has_data = make_explicit(m.get_field("has_data")?); + let jpeg_quality = make_explicit(m.get_field("jpeg_quality")?); + let full_width = make_explicit(m.get_field("full_width")?); + let full_height = make_explicit(m.get_field("full_height")?); let path: Sp = m.expect_field("path")?; let path_2 = m.get_field("path_2")?; let sprites = m.get_field("sprites")?.unwrap_or_default(); @@ -664,6 +683,7 @@ impl WorkingEntry { img_width, img_height, img_format, colorkey, offset_x, offset_y, memory_priority, has_data, low_res_scale, + jpeg_quality, full_width, full_height, }; let loaded_texture = None; let scripts = Default::default(); @@ -768,17 +788,19 @@ pub struct Sprite { pub id: Option, pub offset: [f32; 2], pub size: [f32; 2], + pub unknown: Option<[f32; 5]>, } impl ToMeta for Sprite { fn to_meta(&self) -> Meta { - let &Sprite { id, offset, size } = self; + let &Sprite { id, offset, size, unknown, } = self; Meta::make_object() .field("x", &offset[0]) .field("y", &offset[1]) .field("w", &size[0]) .field("h", &size[1]) .field_opt("id", id.as_ref()) + .field_opt("unknown", unknown.as_ref()) .build() } } @@ -789,6 +811,7 @@ impl FromMeta<'_> for Sprite { id: m.get_field("id")?, offset: [m.expect_field("x")?, m.expect_field("y")?], size: [m.expect_field("w")?, m.expect_field("h")?], + unknown: m.get_field("unknown")? })) } } @@ -887,6 +910,9 @@ fn update_entry_from_anm_image_source(dest_file: &mut WorkingEntry, src_file: En colorkey: src_colorkey, offset_x: src_offset_x, offset_y: src_offset_y, memory_priority: src_memory_priority, low_res_scale: src_low_res_scale, + jpeg_quality: src_jpeg_quality, + full_width: src_full_width, + full_height: src_full_height, } = src_specs; dest_file.specs.has_data.set_soft(HasData::from(src_texture_data.is_some())); @@ -910,6 +936,9 @@ fn update_entry_from_anm_image_source(dest_file: &mut WorkingEntry, src_file: En dest_file.specs.offset_y.set_soft(src_offset_y); dest_file.specs.memory_priority.set_soft(src_memory_priority); dest_file.specs.low_res_scale.set_soft(src_low_res_scale); + dest_file.specs.jpeg_quality.set_soft(src_jpeg_quality); + dest_file.specs.full_width.set_soft(src_full_width); + dest_file.specs.full_height.set_soft(src_full_height); Ok(()) } diff --git a/src/formats/anm/read_write.rs b/src/formats/anm/read_write.rs index 293d7ef..4ee520d 100644 --- a/src/formats/anm/read_write.rs +++ b/src/formats/anm/read_write.rs @@ -29,7 +29,10 @@ struct EntryHeaderData { thtx_offset: Option, has_data: u32, low_res_scale: u32, + jpeg_quality: u32, next_offset: u64, + full_width: u32, + full_height: u32, } pub fn read_anm( @@ -107,7 +110,7 @@ fn read_entry( let mut sprites_seen_in_entry = IndexSet::new(); let sprites = sprite_offsets.iter().map(|&offset| { reader.seek_to(entry_pos + offset as u64)?; - let sprite = read_sprite(reader)?; + let sprite = read_sprite(reader, format.has_extended_sprites())?; let sprite_id = sprite.id.expect("(bug!) sprite read from binary must always have id"); // Note: Duplicate IDs do happen between different entries, so we don't check that. @@ -164,6 +167,9 @@ fn read_entry( offset_x: header_data.offset_x, offset_y: header_data.offset_y, memory_priority: header_data.memory_priority, low_res_scale: header_data.low_res_scale != 0, + jpeg_quality: header_data.jpeg_quality, + full_width: header_data.full_width, + full_height: header_data.full_height, }; let entry = Entry { @@ -226,7 +232,8 @@ fn write_entry( let EntrySpecs { rt_width, rt_height, rt_format, colorkey, offset_x, offset_y, memory_priority, - low_res_scale, + low_res_scale, jpeg_quality, + full_width, full_height } = entry.specs; file_format.write_header(w, &EntryHeaderData { @@ -241,6 +248,9 @@ fn write_entry( // we will overwrite these later name_offset: 0, secondary_name_offset: None, next_offset: 0, thtx_offset: None, + jpeg_quality: jpeg_quality as u32, + full_width: full_width as u32, + full_height: full_height as u32, })?; let sprite_offsets_pos = w.pos()?; @@ -263,7 +273,7 @@ fn write_entry( let sprite_id = sprite.id.unwrap_or(*next_auto_sprite_id); *next_auto_sprite_id = sprite_id.wrapping_add(1); - write_sprite(w, sprite_id, sprite)?; + write_sprite(w, sprite_id, sprite, file_format.has_extended_sprites())?; Ok(sprite_offset) }).collect::>>()?; @@ -325,11 +335,16 @@ fn write_entry( Ok(()) } -fn read_sprite(f: &mut BinReader) -> ReadResult { +fn read_sprite(f: &mut BinReader, extended: bool) -> ReadResult { Ok(Sprite { id: Some(f.read_u32()?), offset: f.read_f32s_2()?, size: f.read_f32s_2()?, + unknown: if extended { + Some(f.read_f32s_5()?) + } else { + None + }, }) } @@ -337,10 +352,15 @@ fn write_sprite( f: &mut BinWriter, sprite_id: u32, // we ignore sprite.id because that can be None sprite: &Sprite, + extended: bool ) -> WriteResult { f.write_u32(sprite_id)?; f.write_f32s(&sprite.offset)?; - f.write_f32s(&sprite.size) + f.write_f32s(&sprite.size)?; + if extended { + f.write_f32s(&sprite.unknown.unwrap_or_else(|| [0.0, 0.0, 1.0, 1.0, 0.0]))?; + } + Ok(()) } #[inline(never)] @@ -390,6 +410,7 @@ fn write_texture(f: &mut BinWriter, data: &TextureData, metadata: &TextureMetada /// Type responsible for dealing with version differences in the container format. struct FileFormat { version: Version, + game: Game, instr_format: Box, } @@ -400,7 +421,11 @@ impl FileFormat { fn from_game(game: Game) -> Self { let version = Version::from_game(game); let instr_format = get_instr_format(version); - FileFormat { version, instr_format } + FileFormat { version, game, instr_format } + } + + fn has_extended_sprites(&self) -> bool { + self.game == Game::Th19 } fn read_header(&self, f: &mut BinReader, emitter: &dyn Emitter) -> ReadResult { @@ -430,10 +455,11 @@ impl FileFormat { let version = f.read_u32()? as _; let memory_priority = f.read_u32()? as _; let thtx_offset = NonZeroU64::new(f.read_u32()? as _) as _; - let has_data = f.read_u16()? as _; - warn_if_nonzero!("unused_2", f.read_u16()?); + let has_data = f.read_u8()? as _; + warn_if_nonzero!("unused_2", f.read_u8()?); + warn_if_nonzero!("unused_3", f.read_u16()?); let next_offset = f.read_u32()? as _; - warn_if_nonzero!("unused_3", f.read_u32()?); + warn_if_nonzero!("unused_4", f.read_u32()?); Ok(EntryHeaderData { version, num_sprites, num_scripts, @@ -443,6 +469,7 @@ impl FileFormat { next_offset, secondary_name_offset, colorkey, memory_priority, thtx_offset, has_data, offset_x: 0, offset_y: 0, low_res_scale: 0, + jpeg_quality: 0, full_width: 0, full_height: 0, }) } else { @@ -459,13 +486,20 @@ impl FileFormat { let offset_y = f.read_u16()? as _; let memory_priority = f.read_u32()? as _; let thtx_offset = NonZeroU64::new(f.read_u32()? as _); - let has_data = f.read_u16()? as _; - let low_res_scale = f.read_u16()? as _; + let has_data = f.read_u8()? as _; + warn_if_nonzero!("unused_1", f.read_u8()?); + let low_res_scale = f.read_u8()? as _; + let jpeg_quality = f.read_u8()? as _; let next_offset = f.read_u32()? as _; + let full_width = f.read_u16()? as _; + let full_height = f.read_u16()? as _; + // header gets padded to 16 dwords + warn_if_nonzero!("header_padding1", f.read_u32()?); + warn_if_nonzero!("header_padding2", f.read_u32()?); + warn_if_nonzero!("header_padding3", f.read_u32()?); + warn_if_nonzero!("header_padding4", f.read_u32()?); + warn_if_nonzero!("header_padding5", f.read_u32()?); - for _ in 0..6 { // header gets padded to 16 dwords - warn_if_nonzero!("header padding", f.read_u32()?); - } Ok(EntryHeaderData { version, num_sprites, num_scripts, rt_width: width, @@ -475,6 +509,7 @@ impl FileFormat { memory_priority, thtx_offset, has_data, secondary_name_offset: None, colorkey: 0, + jpeg_quality, full_width, full_height, }) } } @@ -514,10 +549,14 @@ impl FileFormat { f.write_u16(header.offset_y as _)?; f.write_u32(header.memory_priority as _)?; f.write_u32(header.thtx_offset.map(NonZeroU64::get).unwrap_or(0) as _)?; - f.write_u16(header.has_data as _)?; - f.write_u16(header.low_res_scale as _)?; + f.write_u8(header.has_data as _)?; + f.write_u8(0)?; + f.write_u8(header.low_res_scale as _)?; + f.write_u8(header.jpeg_quality as _)?; f.write_u32(header.next_offset as _)?; - f.write_u32s(&[0; 6])?; + f.write_u16(header.full_width as _)?; + f.write_u16(header.full_height as _)?; + f.write_u32s(&[0; 5])?; } Ok(()) } diff --git a/src/formats/msg.rs b/src/formats/msg.rs index 1616602..e07fb2f 100644 --- a/src/formats/msg.rs +++ b/src/formats/msg.rs @@ -76,15 +76,16 @@ impl Default for ScriptTableEntry { /// An alternative structure closer to the Meta representation. #[derive(Debug, Clone, PartialEq)] -struct SparseScriptTable { +struct MsgMeta { /// The script table is sparsely filled and could potentially have empty entries after the /// last full one, so we must store its true length. table_len: Sp, table: IndexMap, ScriptTableEntry>, + extended_header: Option>, default: ScriptTableEntry, } -impl SparseScriptTable { +impl MsgMeta { fn make_meta(&self) -> meta::Fields { let mut builder = Meta::make_object(); @@ -103,6 +104,10 @@ impl SparseScriptTable { inner.field_default("default", &self.default, &Default::default()); inner.build() }); + + if let Some(extended_header) = &self.extended_header { + builder.field("header", extended_header); + } builder.build_fields() } @@ -131,11 +136,16 @@ impl SparseScriptTable { let table_len = m.get_field("table_len")?.unwrap_or_else(|| { sp!(fields.span => sparse_table_implicit_len(&int_map)) }); - Ok(SparseScriptTable { table_len, table: int_map, default }) + Ok(MsgMeta { + table_len, + table: int_map, + extended_header: m.get_field("header")?, + default + }) }) } - fn densify(&self) -> Vec { + fn make_dense_script_table(&self) -> Vec { (0..self.table_len.value) .map(|index| { self.table.get(&index).unwrap_or_else(|| &self.default).clone() @@ -193,13 +203,13 @@ fn decompile( ) -> Result { let hooks = &*format.language_hooks(); - let sparse_script_table = sparsify_script_table(&msg.dense_table); + let msg_meta = generate_msg_meta(&msg.dense_table, msg.extended_header.clone()); let const_proof = crate::passes::evaluate_const_vars::run(ctx)?; let mut raiser = llir::Raiser::new(hooks, ctx.emitter, ctx, decompile_options, const_proof)?; let mut items = vec![sp!(ast::Item::Meta { keyword: sp!(token![meta]), - fields: sp!(sparse_script_table.make_meta()), + fields: sp!(msg_meta.make_meta()), })]; items.extend(msg.scripts.iter().map(|(ident, instrs)| { let code = raiser.raise_instrs_to_sub_ast(emitter, instrs, ctx)?; @@ -221,7 +231,7 @@ fn decompile( Ok(script) } -fn sparsify_script_table(dense_table: &[ScriptTableEntry]) -> SparseScriptTable { +fn generate_msg_meta(dense_table: &[ScriptTableEntry], extended_header: Option>) -> MsgMeta { let counts = get_counts(dense_table.iter()); // get first index of all nonzero entries @@ -254,7 +264,12 @@ fn sparsify_script_table(dense_table: &[ScriptTableEntry]) -> SparseScriptTable }; let table_len = sp!(dense_table.len() as u32); - SparseScriptTable { table_len, table, default } + MsgMeta { + table_len, + table, + extended_header, + default + } } fn get_counts(items: impl IntoIterator) -> BTreeMap { @@ -329,10 +344,10 @@ fn compile( None => return Err(emit(error!("missing 'meta' section"))), } }; - let sparse_table: SparseScriptTable = { - SparseScriptTable::from_fields(meta).map_err(|e| ctx.emitter.emit(e))? + let msg_meta: MsgMeta = { + MsgMeta::from_fields(meta).map_err(|e| ctx.emitter.emit(e))? }; - let dense_table = sparse_table.densify(); + let dense_table = msg_meta.make_dense_script_table(); let script_table_indices_by_name = get_script_table_indices_by_name(&dense_table); let mut errors = ErrorFlag::new(); @@ -362,13 +377,13 @@ fn compile( errors.into_result(())?; let unused_table_keys = { - sparse_table.table.keys().copied() - .filter(|&key| key >= sparse_table.table_len).collect::>() + msg_meta.table.keys().copied() + .filter(|&key| key >= msg_meta.table_len).collect::>() }; if !unused_table_keys.is_empty() { let mut diag = warning!( message("unused script table entry"), - secondary(sparse_table.table_len, "unused due to this length"), + secondary(msg_meta.table_len, "unused due to this length"), ); for key in unused_table_keys { diag.primary(key.span, format!("unused table entry")); @@ -377,8 +392,8 @@ fn compile( } let used_scripts = { - std::iter::once(sparse_table.default.clone()) - .chain(sparse_table.table.values().cloned()) + std::iter::once(msg_meta.default.clone()) + .chain(msg_meta.table.values().cloned()) .filter_map(|entry| match entry.script.value { ScriptTableOffset::Zero => None, ScriptTableOffset::Name(ref ident) => Some(ident.clone()), @@ -396,7 +411,7 @@ fn compile( Ok(MsgFile { dense_table, scripts, - extended_header: None, + extended_header: msg_meta.extended_header, /// Filename of a read binary file, for display purposes only. binary_filename: None, }) @@ -542,6 +557,10 @@ fn write_msg( let start_pos = w.pos()?; w.write_u32(msg.dense_table.len() as _)?; + + if msg.extended_header.is_some() { + w.write_u32s(&msg.extended_header.as_ref().unwrap())?; + } let script_offsets_pos = w.pos()?; for _ in 0..msg.dense_table.len() { diff --git a/src/formats/std.rs b/src/formats/std.rs index 8714d4c..55e9ff8 100644 --- a/src/formats/std.rs +++ b/src/formats/std.rs @@ -113,6 +113,7 @@ pub struct Object { /// This field determines when objects are drawn relative to 2D sprites, /// as if their polygon scripts had the given `layer(n)` command. pub layer: u16, + pub id: Option, pub pos: [f32; 3], pub size: [f32; 3], pub quads: Vec, @@ -122,6 +123,7 @@ impl FromMeta<'_> for Object { fn from_meta(meta: &Sp) -> Result> { meta.parse_object(|m| Ok(Object { layer: m.expect_renamed_field::("unknown", "layer")? as u16, + id: m.get_field("id")?, pos: m.expect_field("pos")?, size: m.expect_field("size")?, quads: m.expect_field("quads")?, @@ -131,12 +133,16 @@ impl FromMeta<'_> for Object { impl ToMeta for Object { fn to_meta(&self) -> Meta { - Meta::make_object() - .field("layer", &(self.layer as i32)) - .field("pos", &self.pos) - .field("size", &self.size) - .field("quads", &self.quads) - .build() + let mut builder = Meta::make_object(); + if let Some(id) = &self.id { + builder.field("id", id); + } + builder.field("layer", &(self.layer as i32)); + builder.field("pos", &self.pos); + builder.field("size", &self.size); + builder.field("quads", &self.quads); + + builder.build() } } @@ -494,11 +500,21 @@ fn read_object(f: &mut BinReader, emitter: &impl Emitter, expected_id: usize) -> while let Some(quad) = read_quad(f, emitter)? { quads.push(quad); } - Ok(Object { layer, pos, size, quads }) + Ok(Object { + layer, + id: if id as usize == expected_id { + None + } else { + Some(id as u32) + }, + pos, + size, + quads + }) } fn write_object(f: &mut BinWriter, emitter: &impl Emitter, format: &dyn FileFormat, id: usize, x: &Object) -> WriteResult { - f.write_u16(id as u16)?; + f.write_u16(x.id.unwrap_or_else(|| id as u32) as u16)?; f.write_u16(x.layer)?; f.write_f32s(&x.pos)?; f.write_f32s(&x.size)?; diff --git a/src/image/color.rs b/src/image/color.rs index 075f93b..58043dd 100644 --- a/src/image/color.rs +++ b/src/image/color.rs @@ -4,70 +4,102 @@ use std::rc::Rc; use crate::io::{BinRead, BinWrite}; const FORMAT_ARGB_8888: u32 = 1; +const FORMAT_ARGB_1555: u32 = 2; const FORMAT_RGB_565: u32 = 3; +const FORMAT_RGB_888: u32 = 4; const FORMAT_ARGB_4444: u32 = 5; +const FORMAT_ARGB_8332: u32 = 6; const FORMAT_GRAY_8: u32 = 7; +const FORMAT_RGB_332: u32 = 8; #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ColorFormat { Argb8888 = FORMAT_ARGB_8888, + Argb1555 = FORMAT_ARGB_1555, Rgb565 = FORMAT_RGB_565, + Rgb888 = FORMAT_RGB_888, Argb4444 = FORMAT_ARGB_4444, + Argb8332 = FORMAT_ARGB_8332, Gray8 = FORMAT_GRAY_8, + Rgb332 = FORMAT_RGB_332, } impl ColorFormat { pub fn from_format_num(num: u32) -> Option { match num { FORMAT_ARGB_8888 => Some(Self::Argb8888), + FORMAT_ARGB_1555 => Some(Self::Argb1555), FORMAT_RGB_565 => Some(Self::Rgb565), + FORMAT_RGB_888 => Some(Self::Rgb888), FORMAT_ARGB_4444 => Some(Self::Argb4444), + FORMAT_ARGB_8332 => Some(Self::Argb8332), FORMAT_GRAY_8 => Some(Self::Gray8), + FORMAT_RGB_332 => Some(Self::Rgb332), _ => None, } } pub fn get_all() -> Vec { vec![ ColorFormat::Argb8888, + ColorFormat::Argb1555, ColorFormat::Rgb565, + ColorFormat::Rgb888, ColorFormat::Argb4444, + ColorFormat::Argb8332, ColorFormat::Gray8, + ColorFormat::Rgb332, ]} pub fn const_name(&self) -> &'static str { match self { ColorFormat::Argb8888 => "FORMAT_ARGB_8888", + ColorFormat::Argb1555 => "FORMAT_ARGB_1555", ColorFormat::Rgb565 => "FORMAT_RGB_565", + ColorFormat::Rgb888 => "FORMAT_RGB_888", ColorFormat::Argb4444 => "FORMAT_ARGB_4444", + ColorFormat::Argb8332 => "FORMAT_ARGB_8332", ColorFormat::Gray8 => "FORMAT_GRAY_8", + ColorFormat::Rgb332 => "FORMAT_RGB_332", } } pub fn bytes_per_pixel(&self) -> usize { match self { ColorFormat::Argb8888 => Argb8888::BYTES_PER_PIXEL, + ColorFormat::Argb1555 => Argb1555::BYTES_PER_PIXEL, ColorFormat::Rgb565 => Rgb565::BYTES_PER_PIXEL, + ColorFormat::Rgb888 => Rgb888::BYTES_PER_PIXEL, ColorFormat::Argb4444 => Argb4444::BYTES_PER_PIXEL, + ColorFormat::Argb8332 => Argb8332::BYTES_PER_PIXEL, ColorFormat::Gray8 => Gray8::BYTES_PER_PIXEL, + ColorFormat::Rgb332 => Rgb332::BYTES_PER_PIXEL, } } pub fn transcode_to_argb_8888(&self, bytes: &Rc>) -> Rc> { match self { ColorFormat::Argb8888 => Rc::clone(bytes), + ColorFormat::Argb1555 => Rc::new(Argb8888::encode(&Argb1555::decode(bytes))), ColorFormat::Rgb565 => Rc::new(Argb8888::encode(&Rgb565::decode(bytes))), + ColorFormat::Rgb888 => Rc::new(Argb8888::encode(&Rgb888::decode(bytes))), ColorFormat::Argb4444 => Rc::new(Argb8888::encode(&Argb4444::decode(bytes))), + ColorFormat::Argb8332 => Rc::new(Argb8888::encode(&Argb8332::decode(bytes))), ColorFormat::Gray8 => Rc::new(Argb8888::encode(&Gray8::decode(bytes))), + ColorFormat::Rgb332 => Rc::new(Rgb332::encode(&Rgb332::decode(bytes))), } } pub fn transcode_from_argb_8888(&self, bytes: &Rc>) -> Rc> { match self { ColorFormat::Argb8888 => Rc::clone(bytes), + ColorFormat::Argb1555 => Rc::new(Argb1555::encode(&Argb8888::decode(bytes))), ColorFormat::Rgb565 => Rc::new(Rgb565::encode(&Argb8888::decode(bytes))), + ColorFormat::Rgb888 => Rc::new(Rgb888::encode(&Argb8888::decode(bytes))), ColorFormat::Argb4444 => Rc::new(Argb4444::encode(&Argb8888::decode(bytes))), + ColorFormat::Argb8332 => Rc::new(Argb8332::encode(&Argb8888::decode(bytes))), ColorFormat::Gray8 => Rc::new(Gray8::encode(&Argb8888::decode(bytes))), + ColorFormat::Rgb332 => Rc::new(Rgb332::encode(&Argb8888::decode(bytes))), } } @@ -76,9 +108,13 @@ impl ColorFormat { // Slightly transparent magenta where possible // (if fully opaque, thcrap would overlay loaded images instead of overwriting the alpha channel) ColorFormat::Argb8888 => &[0xFF, 0xFF, 0x00, 0xFE], - ColorFormat::Argb4444 => &[0x0F, 0xEF], + ColorFormat::Argb1555 => &[0b000_11111, 0b1_11111_00], ColorFormat::Rgb565 => &[0b000_11111, 0b11111_000], + ColorFormat::Rgb888 => &[0xFF, 0x00, 0xFF], + ColorFormat::Argb4444 => &[0x0F, 0xEF], + ColorFormat::Argb8332 => &[0b111_000_11, 0xFE], ColorFormat::Gray8 => &[0x80], + ColorFormat::Rgb332 => &[0b111_000_11], } } } @@ -96,18 +132,34 @@ impl Components { #[derive(Debug, Copy, Clone, PartialEq, Eq)] struct Argb8888(u32); +/// Format which is the little-endian encoding of a 16-bit integer `0bA_RRRRR_GGGGG_BBBBB`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Argb1555(u16); + /// Format which is the little-endian encoding of a 16-bit integer `0bRRRRR_GGGGGG_BBBBB`. #[derive(Debug, Copy, Clone, PartialEq, Eq)] struct Rgb565(u16); +/// Format which is the little-endian encoding of a 24-bit integer `0xRGB`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Rgb888(u32); + /// Format which is the little-endian encoding of a 16-bit integer `0xARGB`. #[derive(Debug, Copy, Clone, PartialEq, Eq)] struct Argb4444(u16); +/// Format which is the little-endian encoding of a 16-bit integer `0bAAAAAAAA_RRR_GGG_BB`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Argb8332(u16); + /// Format which is a single-byte luminosity channel. #[derive(Debug, Copy, Clone, PartialEq, Eq)] struct Gray8(u8); +/// Format which is single byte encoding of a 8-bit integer `0bRRR_GGG_BB`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Rgb332(u8); + trait ColorBytes: Sized where @@ -157,6 +209,39 @@ impl ColorBytes for Argb8888 { fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u32(self.0) } } +impl From for Components { + fn from(color: Argb1555) -> Components { + let blue = (color.0 & 0x1F) as u8; + let green = ((color.0 >> 5) & 0x1F) as u8; + let red = ((color.0 >> 10) & 0x1F) as u8; + let alpha = ((color.0 >> 15) & 1) as u8; + Components { + blue: change_bit_depth::<5, 8>(blue), + green: change_bit_depth::<5, 8>(green), + red: change_bit_depth::<5, 8>(red), + alpha: change_bit_depth::<1, 8>(alpha), + } + } +} + +impl From for Argb1555 { + fn from(components: Components) -> Self { + let blue = (components.blue >> 3) as u16; + let green = (components.green >> 3) as u16; + let red = (components.red >> 3) as u16; + let alpha = (components.alpha >> 7) as u16; + + Argb1555((alpha << 15) + (red << 10) + (green << 5) + blue) + } +} + +impl ColorBytes for Argb1555 { + const BYTES_PER_PIXEL: usize = 2; + + fn read_color_bytes(mut r: R) -> Result { r.read_u16().map(Argb1555) } + fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u16(self.0) } +} + impl From for Components { fn from(color: Rgb565) -> Components { let blue = (color.0 & 0x1F) as u8; @@ -188,6 +273,50 @@ impl ColorBytes for Rgb565 { fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u16(self.0) } } +impl From for Components { + fn from(color: Rgb888) -> Components { + let blue = (color.0 & 0xFF) as u8; + let green = ((color.0 >> 8) & 0xFF) as u8; + let red = ((color.0 >> 16) & 0xFF) as u8; + Components { + blue, + green, + red, + alpha: 0xFF + } + } +} + +impl From for Rgb888 { + fn from(components: Components) -> Self { + let blue = components.blue as u32; + let green = components.green as u32; + let red = components.red as u32; + + Rgb888((red << 16) + (green << 8) + blue) + } +} + +impl ColorBytes for Rgb888 { + const BYTES_PER_PIXEL: usize = 3; + + fn read_color_bytes(mut r: R) -> Result { + let mut color = r.read_u8()? as u32; + color |= (r.read_u8()? as u32) << 8; + color |= (r.read_u8()? as u32) << 16; + Ok(Rgb888(color)) + } + fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { + let blue = (self.0 & 0xFF) as u8; + let green = ((self.0 >> 8) & 0xFF) as u8; + let red = ((self.0 >> 16) & 0xFF) as u8; + w.write_u8(blue)?; + w.write_u8(green)?; + w.write_u8(red)?; + Ok(()) + } +} + impl From for Components { fn from(color: Argb4444) -> Components { let blue = (color.0 & 0xF) as u8; @@ -221,6 +350,39 @@ impl ColorBytes for Argb4444 { fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u16(self.0) } } +impl From for Components { + fn from(color: Argb8332) -> Components { + let blue = (color.0 & 0x3) as u8; + let green = ((color.0 >> 2) & 0x7) as u8; + let red = ((color.0 >> 5) & 0x7) as u8; + let alpha = ((color.0 >> 8) & 0xFF) as u8; + Components { + blue: change_bit_depth::<2, 8>(blue), + green: change_bit_depth::<3, 8>(green), + red: change_bit_depth::<3, 8>(red), + alpha + } + } +} + +impl From for Argb8332 { + fn from(components: Components) -> Self { + let blue = (components.blue >> 6) as u16; + let green = (components.green >> 5) as u16; + let red = (components.red >> 5) as u16; + let alpha = components.alpha as u16; + + Argb8332((alpha << 8) + (red << 5) + (green << 2) + blue) + } +} + +impl ColorBytes for Argb8332 { + const BYTES_PER_PIXEL: usize = 2; + + fn read_color_bytes(mut r: R) -> Result { r.read_u16().map(Argb8332) } + fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u16(self.0) } +} + impl From for Components { fn from(Gray8(value): Gray8) -> Components { Components { blue: value, green: value, red: value, alpha: 0xFF } @@ -249,6 +411,37 @@ impl ColorBytes for Gray8 { fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u8(self.0) } } +impl From for Components { + fn from(color: Rgb332) -> Components { + let blue = (color.0 & 0x3) as u8; + let green = ((color.0 >> 2) & 0x7) as u8; + let red = ((color.0 >> 5) & 0x7) as u8; + Components { + blue: change_bit_depth::<2, 8>(blue), + green: change_bit_depth::<3, 8>(green), + red: change_bit_depth::<3, 8>(red), + alpha: 0xFF + } + } +} + +impl From for Rgb332 { + fn from(components: Components) -> Self { + let blue = (components.blue >> 6) as u8; + let green = (components.green >> 5) as u8; + let red = (components.red >> 5) as u8; + + Rgb332((red << 5) + (green << 2) + blue) + } +} + +impl ColorBytes for Rgb332 { + const BYTES_PER_PIXEL: usize = 1; + + fn read_color_bytes(mut r: R) -> Result { r.read_u8().map(Rgb332) } + fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u8(self.0) } +} + // take a color value that is N bits large and rescale it to M bits. #[inline(always)] fn change_bit_depth(x: u8) -> u8 { diff --git a/src/io.rs b/src/io.rs index 5f3b111..a8d238d 100644 --- a/src/io.rs +++ b/src/io.rs @@ -317,7 +317,10 @@ pub trait BinRead { fn read_u16(&mut self) -> Result { ReadBytesExt::read_u16::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } fn read_i32(&mut self) -> Result { ReadBytesExt::read_i32::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } fn read_u32(&mut self) -> Result { ReadBytesExt::read_u32::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } + //fn read_i64(&mut self) -> Result { ReadBytesExt::read_i64::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } + //fn read_u64(&mut self) -> Result { ReadBytesExt::read_u64::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } fn read_f32(&mut self) -> Result { ReadBytesExt::read_f32::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } + //fn read_f64(&mut self) -> Result { ReadBytesExt::read_f64::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } fn read_u32s(&mut self, count: usize) -> Result, Self::Err> { (0..count).map(|_| self.read_u32()).collect() } @@ -340,6 +343,9 @@ pub trait BinRead { fn read_f32s_3(&mut self) -> Result<[f32; 3], Self::Err> { Ok([self.read_f32()?, self.read_f32()?, self.read_f32()?]) } + fn read_f32s_5(&mut self) -> Result<[f32; 5], Self::Err> { + Ok([self.read_f32()?, self.read_f32()?, self.read_f32()?, self.read_f32()?, self.read_f32()?]) + } fn read_byte_vec(&mut self, len: usize) -> Result, Self::Err> { let mut buf = vec![0; len]; diff --git a/src/llir/abi.rs b/src/llir/abi.rs index 68957f0..0ef2562 100644 --- a/src/llir/abi.rs +++ b/src/llir/abi.rs @@ -72,6 +72,17 @@ pub enum ArgEncoding { mask: AcceleratingByteMask, furibug: bool, }, + /* + /// `g` in mapfile. Single typed argument + /// 'G' in mapfile. Double typed argument + TypedArg { + is_double: bool, + }, + /// `v` in mapfile. + Variadic { + pattern: Option> + }, + */ } #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] @@ -105,6 +116,7 @@ impl ArgEncoding { Self::Integer { size: 1, .. } => "byte-sized integer", Self::Integer { size: 2, .. } => "word-sized integer", Self::Integer { size: 4, .. } => "dword integer", + //Self::Integer { size: 8, .. } => "qword integer", Self::Integer { size: _, .. } => "integer", Self::JumpOffset => "jump offset", Self::JumpTime => "jump time", @@ -113,6 +125,8 @@ impl ArgEncoding { Self::Padding { size: _ } => "padding", Self::Float { .. } => "float", Self::String { .. } => "string", + //Self::TypedArg { .. } => "type cast argument", + //Self::Variadic { .. } => "variadic", } } @@ -134,6 +148,7 @@ impl ArgEncoding { Enc::Integer { ty_color: None, size: 1, .. } => write!(f, "byte-sized integer"), Enc::Integer { ty_color: None, size: 2, .. } => write!(f, "word-sized integer"), Enc::Integer { ty_color: None, size: 4, .. } => write!(f, "dword integer"), + //Enc::Integer { ty_color: None, size: 8, .. } => write!(f, "qword integer"), Enc::Integer { ty_color: None, size, .. } => write!(f, "{size}-byte integer"), enc => write!(f, "{}", enc.static_descr()), } @@ -159,6 +174,8 @@ impl ArgEncoding { | Self::Integer { immediate: false, .. } | Self::Float { immediate: false, .. } + //| Self::TypedArg { .. } + //| Self::Variadic { .. } => false, } } @@ -392,6 +409,9 @@ fn other_from_attrs(param: &abi_ast::Param, _emitter: &dyn Emitter) -> Result Ok(Some(ArgEncoding::JumpTime)), '_' => Ok(Some(ArgEncoding::Padding { size: 4 })), '-' => Ok(Some(ArgEncoding::Padding { size: 1 })), + //'g' => Ok(Some(ArgEncoding::TypedArg { is_double: false })), + //'G' => Ok(Some(ArgEncoding::TypedArg { is_double: true })), + //'v' => _ => Ok(None), } } From 8d9e7a8fec4aaea6eeb45d9c3a18b49cbf37de9a Mon Sep 17 00:00:00 2001 From: zero318 Date: Mon, 5 May 2025 03:32:13 -0400 Subject: [PATCH 17/26] First attempt at th20 support --- src/core_mapfiles/anm.rs | 6 +++--- src/core_mapfiles/ecl.rs | 10 +++++----- src/core_mapfiles/end.rs | 6 +++--- src/core_mapfiles/msg.rs | 6 +++--- src/core_mapfiles/std.rs | 6 +++--- src/formats/anm/mod.rs | 2 +- src/formats/anm/read_write.rs | 2 +- src/formats/msg.rs | 4 ++-- src/game.rs | 9 ++++++--- src/image/color.rs | 2 +- src/llir/abi.rs | 2 +- 11 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/core_mapfiles/anm.rs b/src/core_mapfiles/anm.rs index aa017a1..8bf2fdb 100644 --- a/src/core_mapfiles/anm.rs +++ b/src/core_mapfiles/anm.rs @@ -32,9 +32,9 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { OUT }, - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => { + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 | Th20 => { static OUT: &CoreSignatures = &CoreSignatures { - inherit: &[ANM_INS_13_19, ANM_VAR], + inherit: &[ANM_INS_13_20, ANM_VAR], ins: &[], var: &[], }; OUT @@ -328,7 +328,7 @@ static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { }; // v8 -static ANM_INS_13_19: &CoreSignatures = &CoreSignatures { +static ANM_INS_13_20: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ // Section A diff --git a/src/core_mapfiles/ecl.rs b/src/core_mapfiles/ecl.rs index 793d045..a9fea59 100644 --- a/src/core_mapfiles/ecl.rs +++ b/src/core_mapfiles/ecl.rs @@ -16,7 +16,7 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { Th12 | Th125 => ECL_12, Th128 | - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => CoreSignatures::EMPTY, + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 | Th20 => CoreSignatures::EMPTY, } } @@ -25,7 +25,7 @@ pub(super) fn timeline_core_signatures(game: Game) -> &'static CoreSignatures { Th06 | Th07 | Th08 | Th09 | Th095 => TIMELINE, Th10 | Alcostg | Th11 | Th12 | Th125 | Th128 | - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => CoreSignatures::EMPTY, + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 | Th20 => CoreSignatures::EMPTY, } } @@ -1061,7 +1061,7 @@ static ECL_095: &'static CoreSignatures = &CoreSignatures { static ECL_10_11: &'static CoreSignatures = &CoreSignatures { - inherit: &[ECL_10_19_COMMON], + inherit: &[ECL_10_20_COMMON], ins: &[ // Section B (Th10, 256, Some(("P(bs=4)ffSSS", None))), @@ -1264,7 +1264,7 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { static ECL_12: &'static CoreSignatures = &CoreSignatures { - inherit: &[ECL_10_19_COMMON], + inherit: &[ECL_10_20_COMMON], ins: &[ // Section B (Th12, 256, Some(("P(bs=4)ffSSS", None))), @@ -1470,7 +1470,7 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { }; -static ECL_10_19_COMMON: &'static CoreSignatures = &CoreSignatures { +static ECL_10_20_COMMON: &'static CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th10, 0, Some(("", None))), diff --git a/src/core_mapfiles/end.rs b/src/core_mapfiles/end.rs index 889675f..ee7f614 100644 --- a/src/core_mapfiles/end.rs +++ b/src/core_mapfiles/end.rs @@ -10,8 +10,8 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { => END_06_09, | Th10 | Th11 | Th12 | Th128 | Th13 - | Th14 | Th15 | Th16 | Th17 | Th18 | Th19 - => END_10_19, + | Th14 | Th15 | Th16 | Th17 | Th18 | Th19 | Th20 + => END_10_20, } } @@ -29,7 +29,7 @@ static END_06_09: &CoreSignatures = &CoreSignatures { var: &[], }; -static END_10_19: &CoreSignatures = &CoreSignatures { +static END_10_20: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th10, 0, Some(("", None))), diff --git a/src/core_mapfiles/msg.rs b/src/core_mapfiles/msg.rs index a166cd5..76d8052 100644 --- a/src/core_mapfiles/msg.rs +++ b/src/core_mapfiles/msg.rs @@ -10,8 +10,8 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { => MSG_06_09, | Th10 | Th11 | Th12 | Th125 | Th128 | Th13 - | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 - => MSG_10_19, + | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 | Th20 + => MSG_10_20, } } @@ -73,7 +73,7 @@ static MSG_06_09: &CoreSignatures = &CoreSignatures { ], var: &[], }; -static MSG_10_19: &CoreSignatures = &CoreSignatures { +static MSG_10_20: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th10, 0, Some(("", None))), diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index 2127811..f5db06f 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -11,8 +11,8 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { => STD_07_09, | Th095 | Th10 | Alcostg | Th11 | Th12 | Th125 | Th128 - | Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 - => STD_095_19 + | Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 | Th20 + => STD_095_20 } } @@ -72,7 +72,7 @@ static STD_07_09: &CoreSignatures = &CoreSignatures { var: &[], }; -static STD_095_19: &CoreSignatures = &CoreSignatures { +static STD_095_20: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th095, 0, Some(("", None))), diff --git a/src/formats/anm/mod.rs b/src/formats/anm/mod.rs index 6783265..ebd5ba9 100644 --- a/src/formats/anm/mod.rs +++ b/src/formats/anm/mod.rs @@ -1214,7 +1214,7 @@ impl Version { Th08 | Th09 => Version::V3, Th095 | Th10 | Alcostg => Version::V4, Th11 | Th12 | Th125 | Th128 => Version::V7, - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => Version::V8, + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 | Th20 => Version::V8, } } diff --git a/src/formats/anm/read_write.rs b/src/formats/anm/read_write.rs index 4ee520d..972a2e0 100644 --- a/src/formats/anm/read_write.rs +++ b/src/formats/anm/read_write.rs @@ -425,7 +425,7 @@ impl FileFormat { } fn has_extended_sprites(&self) -> bool { - self.game == Game::Th19 + self.game >= Game::Th19 } fn read_header(&self, f: &mut BinReader, emitter: &dyn Emitter) -> ReadResult { diff --git a/src/formats/msg.rs b/src/formats/msg.rs index e07fb2f..cb77b19 100644 --- a/src/formats/msg.rs +++ b/src/formats/msg.rs @@ -652,7 +652,7 @@ impl FileFormat { } fn extended_header(&self) -> bool { - self.language == LanguageKey::Msg && self.game == Game::Th19 + self.language == LanguageKey::Msg && self.game >= Game::Th19 } fn language_hooks(&self) -> Box { @@ -663,7 +663,7 @@ impl FileFormat { | Game::Th13 | Game::Th14 | Game::Th143 | Game::Th15 | Game::Th16 | Game::Th165 | Game::Th17 | Game::Th18 | Game::Th185 - | Game::Th19 + | Game::Th19 | Game::Th20 => Box::new(MsgHooks { language: self.language }), | Game::Th095 | Game::Alcostg diff --git a/src/game.rs b/src/game.rs index b3d91be..55078cb 100644 --- a/src/game.rs +++ b/src/game.rs @@ -6,9 +6,9 @@ use crate::diagnostic::Diagnostic; pub enum Game { Th06, Th07, Th08, Th09, Th095, Th10, Alcostg, Th11, Th12, Th125, Th128, Th13, Th14, Th143, Th15, Th16, Th165, Th17, Th18, - Th185, Th19 + Th185, Th19, Th20 } -macro_rules! max_game_str { () => { "th19" }; } +macro_rules! max_game_str { () => { "th20" }; } impl std::str::FromStr for Game { type Err = Diagnostic; @@ -49,6 +49,7 @@ impl std::str::FromStr for Game { 18 => Ok(Game::Th18), 185 => Ok(Game::Th185), 19 => Ok(Game::Th19), + 20 => Ok(Game::Th20), _ => Err(unknown_game()), } } @@ -78,6 +79,7 @@ impl Game { Game::Th18 => "UM", Game::Th185 => "HBM", Game::Th19 => "UDoALG", + Game::Th20 => "FW", } } @@ -104,7 +106,7 @@ impl Game { Game::Th18 => "th18", Game::Th185 => "th185", Game::Th19 => "th19", - + Game::Th20 => "th20", } } @@ -131,6 +133,7 @@ impl Game { Game::Th18 => 18, Game::Th185 => 185, Game::Th19 => 19, + Game::Th20 => 20, } } } diff --git a/src/image/color.rs b/src/image/color.rs index 58043dd..e11deec 100644 --- a/src/image/color.rs +++ b/src/image/color.rs @@ -86,7 +86,7 @@ impl ColorFormat { ColorFormat::Argb4444 => Rc::new(Argb8888::encode(&Argb4444::decode(bytes))), ColorFormat::Argb8332 => Rc::new(Argb8888::encode(&Argb8332::decode(bytes))), ColorFormat::Gray8 => Rc::new(Argb8888::encode(&Gray8::decode(bytes))), - ColorFormat::Rgb332 => Rc::new(Rgb332::encode(&Rgb332::decode(bytes))), + ColorFormat::Rgb332 => Rc::new(Argb8888::encode(&Rgb332::decode(bytes))), } } diff --git a/src/llir/abi.rs b/src/llir/abi.rs index 0ef2562..6d63b7c 100644 --- a/src/llir/abi.rs +++ b/src/llir/abi.rs @@ -48,7 +48,7 @@ pub enum ArgEncoding { arg0: bool, immediate: bool, extend: bool, - format: ast::IntFormat + format: ast::IntFormat, }, /// `o` in mapfile. Max of one per instruction. Is decoded to a label. JumpOffset, From 7a8dd56d201af6afed9e9a816224cda8cd10188e Mon Sep 17 00:00:00 2001 From: Khang Date: Mon, 5 May 2025 04:48:37 -0400 Subject: [PATCH 18/26] Fix th20 std support --- src/formats/std.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/formats/std.rs b/src/formats/std.rs index 55e9ff8..4dc86a9 100644 --- a/src/formats/std.rs +++ b/src/formats/std.rs @@ -116,6 +116,7 @@ pub struct Object { pub id: Option, pub pos: [f32; 3], pub size: [f32; 3], + pub unk: Option, pub quads: Vec, } @@ -126,6 +127,7 @@ impl FromMeta<'_> for Object { id: m.get_field("id")?, pos: m.expect_field("pos")?, size: m.expect_field("size")?, + unk: m.get_field("unk")?, quads: m.expect_field("quads")?, })) } @@ -140,6 +142,9 @@ impl ToMeta for Object { builder.field("layer", &(self.layer as i32)); builder.field("pos", &self.pos); builder.field("size", &self.size); + if let Some(unk) = &self.unk { + builder.field("unk", unk); + } builder.field("quads", &self.quads); builder.build() @@ -399,7 +404,7 @@ fn read_std(reader: &mut BinReader, emitter: &impl Emitter, format: &dyn FileFor let expected_id = i; let value = emitter.chain_with(|f| write!(f, "object at index {i}"), |emitter| { - read_object(reader, emitter, expected_id) + read_object(reader, emitter, format, expected_id) })?; Ok((key, value)) }).collect::>>()?; @@ -487,7 +492,7 @@ fn write_string_128>(f: &mut BinWriter, emitter: &dyn Emitter, s: Ok(()) } -fn read_object(f: &mut BinReader, emitter: &impl Emitter, expected_id: usize) -> ReadResult { +fn read_object(f: &mut BinReader, emitter: &impl Emitter, format: &dyn FileFormat, expected_id: usize) -> ReadResult { let id = f.read_u16()?; if id as usize != expected_id { emitter.emit(warning!("object has non-sequential id (expected {expected_id}, got {id})")).ignore(); @@ -496,6 +501,11 @@ fn read_object(f: &mut BinReader, emitter: &impl Emitter, expected_id: usize) -> let layer = f.read_u16()?; let pos = f.read_f32s_3()?; let size = f.read_f32s_3()?; + let unk = if format.has_obj_unk() { + Some(f.read_f32()?) + } else { + None + }; let mut quads = vec![]; while let Some(quad) = read_quad(f, emitter)? { quads.push(quad); @@ -509,6 +519,7 @@ fn read_object(f: &mut BinReader, emitter: &impl Emitter, expected_id: usize) -> }, pos, size, + unk, quads }) } @@ -518,6 +529,9 @@ fn write_object(f: &mut BinWriter, emitter: &impl Emitter, format: &dyn FileForm f.write_u16(x.layer)?; f.write_f32s(&x.pos)?; f.write_f32s(&x.size)?; + if let Some(unk) = x.unk { + f.write_f32(unk)?; + } for quad in &x.quads { write_quad(f, emitter, format, quad)?; } @@ -629,7 +643,7 @@ fn write_terminal_instance(f: &mut BinWriter) -> WriteResult { fn game_format(game: Game) -> Box { if Game::Th095 <= game { let hooks = StdHooks10; - Box::new(FileFormat10 { hooks }) + Box::new(FileFormat10 { hooks, game }) } else { let has_strips = match game { Game::Th06 | Game::Th07 => false, @@ -652,6 +666,7 @@ struct FileFormat06 { /// STD format, StB to present. struct FileFormat10 { hooks: StdHooks10, + game: Game, } trait FileFormat { @@ -661,6 +676,7 @@ trait FileFormat { fn write_extra(&self, f: &mut BinWriter, emitter: &dyn Emitter, x: &StdExtra) -> WriteResult; fn language_hooks(&self) -> &dyn LanguageHooks; fn has_strips(&self) -> bool; + fn has_obj_unk(&self) -> bool; } impl FileFormat for FileFormat06 { @@ -709,6 +725,7 @@ impl FileFormat for FileFormat06 { fn language_hooks(&self) -> &dyn LanguageHooks { &self.hooks } fn has_strips(&self) -> bool { self.has_strips } + fn has_obj_unk(&self) -> bool { false } } impl FileFormat for FileFormat10 { @@ -739,6 +756,7 @@ impl FileFormat for FileFormat10 { fn language_hooks(&self) -> &dyn LanguageHooks { &self.hooks } fn has_strips(&self) -> bool { false } + fn has_obj_unk(&self) -> bool { self.game >= Game::Th20 } } struct StdHooks06; From ac21a91c81f86b1b45c8d9ffbe8d2ce7410ef4c6 Mon Sep 17 00:00:00 2001 From: Khang Date: Mon, 25 Aug 2025 15:40:52 -0400 Subject: [PATCH 19/26] Fix th20 std support (again) --- src/formats/std.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/formats/std.rs b/src/formats/std.rs index 4dc86a9..6103971 100644 --- a/src/formats/std.rs +++ b/src/formats/std.rs @@ -116,7 +116,7 @@ pub struct Object { pub id: Option, pub pos: [f32; 3], pub size: [f32; 3], - pub unk: Option, + pub unk: Option<[f32; 5]>, pub quads: Vec, } @@ -502,7 +502,7 @@ fn read_object(f: &mut BinReader, emitter: &impl Emitter, format: &dyn FileForma let pos = f.read_f32s_3()?; let size = f.read_f32s_3()?; let unk = if format.has_obj_unk() { - Some(f.read_f32()?) + Some(f.read_f32s_5()?) } else { None }; @@ -530,7 +530,7 @@ fn write_object(f: &mut BinWriter, emitter: &impl Emitter, format: &dyn FileForm f.write_f32s(&x.pos)?; f.write_f32s(&x.size)?; if let Some(unk) = x.unk { - f.write_f32(unk)?; + f.write_f32s(&unk)?; } for quad in &x.quads { write_quad(f, emitter, format, quad)?; From e04f291dd793fd9e3c8e0b295d4e7ac834e34b53 Mon Sep 17 00:00:00 2001 From: zero318 Date: Mon, 25 Aug 2025 19:55:46 -0400 Subject: [PATCH 20/26] Fix more STD/MSG/END stuff for th20 --- src/core_mapfiles/end.rs | 3 +++ src/core_mapfiles/msg.rs | 22 ++++++++++++++++++++++ src/core_mapfiles/std.rs | 2 ++ src/formats/msg.rs | 6 +++--- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/core_mapfiles/end.rs b/src/core_mapfiles/end.rs index ee7f614..cd97ae5 100644 --- a/src/core_mapfiles/end.rs +++ b/src/core_mapfiles/end.rs @@ -50,6 +50,9 @@ static END_10_20: &CoreSignatures = &CoreSignatures { (Th10, 15, Some(("SSN", None))), (Th10, 16, Some(("SSN", None))), (Th10, 17, Some(("SSN", None))), + + (Th20, 3, Some(("m(bs=4;mask=0x77,7,16;furibug)", None))), + (Th20, 9, Some(("CC", None))), ], var: &[], }; diff --git a/src/core_mapfiles/msg.rs b/src/core_mapfiles/msg.rs index 76d8052..a203364 100644 --- a/src/core_mapfiles/msg.rs +++ b/src/core_mapfiles/msg.rs @@ -187,6 +187,28 @@ static MSG_10_20: &CoreSignatures = &CoreSignatures { (Th19, 54, Some(("", None))), (Th19, 55, Some(("", None))), (Th19, 56, Some(("", None))), + + (Th20, 19, Some(("", None))), + (Th20, 37, None), + (Th20, 38, None), + (Th20, 39, None), + (Th20, 40, None), + (Th20, 41, None), + (Th20, 42, None), + (Th20, 43, None), + (Th20, 44, None), + (Th20, 45, None), + (Th20, 46, None), + (Th20, 47, None), + (Th20, 48, None), + (Th20, 49, None), + (Th20, 50, None), + (Th20, 51, None), + (Th20, 52, None), + (Th20, 53, None), + (Th20, 54, None), + (Th20, 55, None), + (Th20, 56, None), ], var: &[], }; diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index f5db06f..c56f617 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -108,6 +108,8 @@ static STD_095_20: &CoreSignatures = &CoreSignatures { (Th14, 20, Some(("f", None))), (Th17, 21, Some(("SSf", None))), + + (Th20, 22, Some(("S", None))), ], var: &[], }; diff --git a/src/formats/msg.rs b/src/formats/msg.rs index cb77b19..5b17624 100644 --- a/src/formats/msg.rs +++ b/src/formats/msg.rs @@ -616,13 +616,13 @@ fn write_msg( fn game_format(game: Game, language: LanguageKey, emitter: &RootEmitter) -> Result { match (game, language) { | (Game::Th095, LanguageKey::Msg) - | (Game::Th095, LanguageKey::End) => Err(emitter.emit(error!("{} does not have MSG files; maybe try 'trumsg --mission'?", game))), | (Game::Alcostg, LanguageKey::Msg) - | (Game::Alcostg, LanguageKey::End) => Err(emitter.emit(error!("{} does not have MSG files", game))), + | (Game::Th095, LanguageKey::End) + | (Game::Alcostg, LanguageKey::End) | (Game::Th125, LanguageKey::End) | (Game::Th143, LanguageKey::End) | (Game::Th165, LanguageKey::End) @@ -652,7 +652,7 @@ impl FileFormat { } fn extended_header(&self) -> bool { - self.language == LanguageKey::Msg && self.game >= Game::Th19 + self.language == LanguageKey::Msg && self.game == Game::Th19 } fn language_hooks(&self) -> Box { From 7778c45d7fc39fb780f0f0d146de9941c7a17132 Mon Sep 17 00:00:00 2001 From: zero318 Date: Fri, 26 Apr 2024 19:41:16 -0400 Subject: [PATCH 21/26] e --- src/ast/mod.rs | 6 +++ src/cli_def.rs | 19 +++++-- src/core_mapfiles/anm.rs | 89 +++++++++++++++++++++++--------- src/core_mapfiles/ecl.rs | 98 ++++++++++++++++++++++++++++-------- src/core_mapfiles/end.rs | 55 ++++++++++++++++++++ src/core_mapfiles/mod.rs | 3 +- src/core_mapfiles/msg.rs | 36 +++++++++++-- src/core_mapfiles/std.rs | 6 +-- src/fmt.rs | 2 +- src/formats/anm/mod.rs | 2 +- src/formats/msg.rs | 48 ++++++++++++++---- src/game.rs | 12 ++++- src/llir/abi.rs | 23 ++++++--- src/mapfile.rs | 2 + src/passes/const_simplify.rs | 6 +++ src/passes/type_check.rs | 6 +++ src/quote.rs | 3 ++ 17 files changed, 340 insertions(+), 76 deletions(-) create mode 100644 src/core_mapfiles/end.rs diff --git a/src/ast/mod.rs b/src/ast/mod.rs index ff16f38..0eb0c4a 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -699,6 +699,9 @@ string_enum! { #[strum(serialize = "~")] BitNot, #[strum(serialize = "sin")] Sin, #[strum(serialize = "cos")] Cos, + #[strum(serialize = "tan")] Tan, + #[strum(serialize = "acos")] Acos, + #[strum(serialize = "atan")] Atan, #[strum(serialize = "sqrt")] Sqrt, #[strum(serialize = "$")] EncodeI, #[strum(serialize = "%")] EncodeF, @@ -715,6 +718,9 @@ impl UnOpKind { UnOpKind::BitNot => OpClass::Bitwise, UnOpKind::Sin => OpClass::FloatMath, UnOpKind::Cos => OpClass::FloatMath, + UnOpKind::Tan => OpClass::FloatMath, + UnOpKind::Acos => OpClass::FloatMath, + UnOpKind::Atan => OpClass::FloatMath, UnOpKind::Sqrt => OpClass::FloatMath, UnOpKind::CastI => OpClass::Cast, UnOpKind::CastF => OpClass::Cast, diff --git a/src/cli_def.rs b/src/cli_def.rs index 690bee4..408905b 100644 --- a/src/cli_def.rs +++ b/src/cli_def.rs @@ -576,7 +576,10 @@ pub mod msg_compile { truth.load_mapfiles_from_pragmas(game, &ast)?; }, MsgMode::Mission => {}, - MsgMode::Ending => return Err(truth.emit(error!("--ending is not yet implemented"))), + MsgMode::Ending => { + load_mapfiles(truth, game, &[LanguageKey::End], mapfile_options)?; + truth.load_mapfiles_from_pragmas(game, &ast)?; + }, } let mut truth = truth.validate_defs()?; @@ -590,7 +593,10 @@ pub mod msg_compile { let msg = truth.compile_mission(game, &ast)?; truth.write_mission(game, out_path, &msg)?; }, - MsgMode::Ending => unreachable!(), + MsgMode::Ending => { + let msg = truth.compile_msg(game, LanguageKey::End, &ast)?; + truth.write_msg(game, LanguageKey::End, out_path, &msg)?; + }, } if let Some(debug_info_path) = debug_info_path { truth.prepare_and_write_debug_info(debug_info_path)?; @@ -636,7 +642,14 @@ pub mod msg_decompile { let msg = truth.read_mission(game, in_path)?; truth.decompile_mission(game, &msg) }, - MsgMode::Ending => return Err(truth.emit(error!("--ending is not yet implemented"))), + MsgMode::Ending => { + let mapfile_options = add_env_mapfile_for_decomp(mapfile_options, ".endm"); + load_mapfiles(truth, game, &[LanguageKey::End], &mapfile_options)?; + + let mut truth = truth.validate_defs()?; + let msg = truth.read_msg(game, LanguageKey::End, in_path)?; + truth.decompile_msg(game, LanguageKey::End, &msg, decompile_options) + }, } } } diff --git a/src/core_mapfiles/anm.rs b/src/core_mapfiles/anm.rs index 9ef283f..aa017a1 100644 --- a/src/core_mapfiles/anm.rs +++ b/src/core_mapfiles/anm.rs @@ -32,9 +32,9 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { OUT }, - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 => { + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => { static OUT: &CoreSignatures = &CoreSignatures { - inherit: &[ANM_INS_13_18, ANM_VAR], + inherit: &[ANM_INS_13_19, ANM_VAR], ins: &[], var: &[], }; OUT @@ -150,9 +150,9 @@ static ANM_INS_07_09: &'static CoreSignatures = &CoreSignatures { (Th07, 60, Some(("ff", None))), (Th07, 61, Some(("ff", Some(IKind::UnOp(U::Sin, Ty::Float))))), (Th07, 62, Some(("ff", Some(IKind::UnOp(U::Cos, Ty::Float))))), - (Th07, 63, Some(("ff", None))), - (Th07, 64, Some(("ff", None))), - (Th07, 65, Some(("ff", None))), + (Th07, 63, Some(("ff", Some(IKind::UnOp(U::Tan, Ty::Float))))), + (Th07, 64, Some(("ff", Some(IKind::UnOp(U::Acos, Ty::Float))))), + (Th07, 65, Some(("ff", Some(IKind::UnOp(U::Atan, Ty::Float))))), (Th07, 66, Some(("f", None))), (Th07, 67, Some(("SSot", Some(IKind::CondJmp(B::Eq, Ty::Int))))), (Th07, 68, Some(("ffot", Some(IKind::CondJmp(B::Eq, Ty::Float))))), @@ -240,9 +240,9 @@ static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { (Th095, 41, Some(("ff", None))), (Th095, 42, Some(("ff", Some(IKind::UnOp(U::Sin, Ty::Float))))), (Th095, 43, Some(("ff", Some(IKind::UnOp(U::Cos, Ty::Float))))), - (Th095, 44, Some(("ff", None))), - (Th095, 45, Some(("ff", None))), - (Th095, 46, Some(("ff", None))), + (Th095, 44, Some(("ff", Some(IKind::UnOp(U::Tan, Ty::Float))))), + (Th095, 45, Some(("ff", Some(IKind::UnOp(U::Acos, Ty::Float))))), + (Th095, 46, Some(("ff", Some(IKind::UnOp(U::Atan, Ty::Float))))), (Th095, 47, Some(("f", None))), (Th095, 48, Some(("fff", None))), (Th095, 49, Some(("fff", None))), @@ -328,9 +328,10 @@ static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { }; // v8 -static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { +static ANM_INS_13_19: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ + // Section A (Th13, 0, Some(("", None))), (Th13, 1, Some(("", None))), (Th13, 2, Some(("", None))), @@ -339,6 +340,8 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 5, Some(("S", Some(IKind::InterruptLabel)))), (Th13, 6, Some(("S", None))), (Th13, 7, Some(("", None))), + + // Section B (Th13, 100, Some(("SS", Some(IKind::AssignOp(A::Assign, Ty::Int))))), (Th13, 101, Some(("ff", Some(IKind::AssignOp(A::Assign, Ty::Float))))), (Th13, 102, Some(("SS", Some(IKind::AssignOp(A::Add, Ty::Int))))), @@ -365,12 +368,14 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 123, Some(("ff", None))), (Th13, 124, Some(("ff", Some(IKind::UnOp(U::Sin, Ty::Float))))), (Th13, 125, Some(("ff", Some(IKind::UnOp(U::Cos, Ty::Float))))), - (Th13, 126, Some(("ff", None))), - (Th13, 127, Some(("ff", None))), - (Th13, 128, Some(("ff", None))), + (Th13, 126, Some(("ff", Some(IKind::UnOp(U::Tan, Ty::Float))))), + (Th13, 127, Some(("ff", Some(IKind::UnOp(U::Acos, Ty::Float))))), + (Th13, 128, Some(("ff", Some(IKind::UnOp(U::Atan, Ty::Float))))), (Th13, 129, Some(("f", None))), (Th13, 130, Some(("ffff", None))), (Th13, 131, Some(("ffff", None))), + + // Section C (Th13, 200, Some(("ot", Some(IKind::Jmp)))), (Th13, 201, Some(("Sot", Some(IKind::CountJmp(B::Ne))))), (Th13, 202, Some(("SSot", Some(IKind::CondJmp(B::Eq, Ty::Int))))), @@ -385,6 +390,8 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 211, Some(("ffot", Some(IKind::CondJmp(B::Gt, Ty::Float))))), (Th13, 212, Some(("SSot", Some(IKind::CondJmp(B::Ge, Ty::Int))))), (Th13, 213, Some(("ffot", Some(IKind::CondJmp(B::Ge, Ty::Float))))), + + // Section D (Th13, 300, Some(("n", None))), (Th13, 301, Some(("nS", None))), (Th13, 302, Some(("S", None))), @@ -398,6 +405,18 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 310, Some(("S", None))), (Th13, 311, Some(("S", None))), (Th13, 312, Some(("SS", None))), + + (Th14, 313, Some(("S", None))), + (Th14, 314, Some(("S", None))), + (Th14, 315, Some(("S", None))), + + (Th143, 316, Some(("", None))), + (Th143, 317, Some(("", None))), + + (Th19, 318, Some((r#"b(imm;enum="bool")---"#, None))), // zero: b(imm;enum="BitBool")--- + (Th19, 319, Some(("nnnn", None))), + + // Section E (Th13, 400, Some(("fff", None))), (Th13, 401, Some(("fff", None))), (Th13, 402, Some(("ff", None))), @@ -437,6 +456,16 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 436, Some(("ff", None))), (Th13, 437, Some(("S", None))), (Th13, 438, Some(("S", None))), + + (Th165, 439, Some(("S", None))), // files use this, but it's not in the jumptable! + + (Th17, 439, None), // ... TH17 doesn't use it ... + + (Th18, 439, Some(("Sff", None))), // ...and TH18 demo reused its ID for something else! + + (Th185, 440, Some(("", None))), + + // Section F (Th13, 500, Some(("N", None))), (Th13, 501, Some(("N", None))), (Th13, 502, Some(("N", None))), @@ -446,6 +475,12 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 506, Some(("Nff", None))), (Th13, 507, Some(("S", None))), (Th13, 508, Some(("S", None))), + + (Th14, 509, Some(("", None))), + + (Th19, 510, Some(("Nff", None))), + + // Section G (Th13, 600, Some(("S", None))), (Th13, 601, Some(("S", None))), (Th13, 602, Some(("S", None))), @@ -456,26 +491,34 @@ static ANM_INS_13_18: &CoreSignatures = &CoreSignatures { (Th13, 607, Some(("ff", None))), (Th13, 608, Some(("ff", None))), - (Th14, 313, Some(("S", None))), - (Th14, 314, Some(("S", None))), - (Th14, 315, Some(("S", None))), - (Th14, 509, Some(("", None))), (Th14, 609, Some(("S", None))), (Th14, 610, Some(("S", None))), - (Th143, 316, Some(("", None))), - (Th143, 317, Some(("", None))), (Th143, 611, Some(("ffS", None))), (Th16, 612, Some(("ff", None))), (Th16, 613, Some(("ff", None))), - (Th165, 439, Some(("S", None))), // files use this, but it's not in the jumptable! - - (Th17, 439, None), // ... TH17 doesn't use it ... - - (Th18, 439, Some(("Sff", None))), // ...and TH18 demo reused its ID for something else! (Th18, 614, Some(("ff", None))), + + (Th19, 615, Some(("ffS", None))), + (Th19, 616, Some(("ffS", None))), + (Th19, 617, Some(("fS", None))), + (Th19, 618, Some(("", None))), + (Th19, 619, Some(("fS", None))), + (Th19, 620, Some(("ffS", None))), + (Th19, 621, Some(("ffS", None))), + (Th19, 622, Some(("ffS", None))), + (Th19, 623, Some(("fffS", None))), + (Th19, 624, Some(("fffS", None))), + (Th19, 625, Some(("ffffS", None))), + (Th19, 626, Some(("ffffS", None))), + (Th19, 627, Some(("ffffS", None))), + (Th19, 628, Some(("fS", None))), + (Th19, 629, Some(("fS", None))), + (Th19, 630, Some(("ffS", None))), + (Th19, 631, Some(("ffS", None))), + (Th19, 632, Some(("ffS", None))), ], var: &[], }; diff --git a/src/core_mapfiles/ecl.rs b/src/core_mapfiles/ecl.rs index 52b4cb3..793d045 100644 --- a/src/core_mapfiles/ecl.rs +++ b/src/core_mapfiles/ecl.rs @@ -13,10 +13,10 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { Th08 | Th09 => ECL_08_09, Th095 => ECL_095, Th10 | Alcostg | Th11 => ECL_10_11, - Th12 => ECL_12, + Th12 | Th125 => ECL_12, - Th125 | Th128 | - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 => CoreSignatures::EMPTY, + Th128 | + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => CoreSignatures::EMPTY, } } @@ -25,7 +25,7 @@ pub(super) fn timeline_core_signatures(game: Game) -> &'static CoreSignatures { Th06 | Th07 | Th08 | Th09 | Th095 => TIMELINE, Th10 | Alcostg | Th11 | Th12 | Th125 | Th128 | - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 => CoreSignatures::EMPTY, + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => CoreSignatures::EMPTY, } } @@ -1061,9 +1061,9 @@ static ECL_095: &'static CoreSignatures = &CoreSignatures { static ECL_10_11: &'static CoreSignatures = &CoreSignatures { - inherit: &[ECL_10_18_COMMON], + inherit: &[ECL_10_19_COMMON], ins: &[ - // Section A + // Section B (Th10, 256, Some(("P(bs=4)ffSSS", None))), (Th10, 257, Some(("P(bs=4)ffSSS", None))), (Th10, 258, Some(("S", None))), @@ -1090,7 +1090,7 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { (Th11, 277, Some(("Sf", None))), (Th11, 278, Some(("S", None))), // Not implemented - // Section B + // Section C (Th10, 280, Some(("ff", None))), (Th10, 281, Some(("SSff", None))), (Th10, 282, Some(("ff", None))), @@ -1124,7 +1124,7 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { (Th11, 306, Some(("Sffffff", None))), (Th11, 307, Some(("", None))), - // Section C + // Section D (Th10, 320, Some(("ff", None))), (Th10, 321, Some(("ff", None))), (Th10, 322, Some(("S(hex)", None))), @@ -1182,7 +1182,7 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { (Th11, 371, Some(("S", None))), (Th11, 372, Some(("S", None))), - // Section D + // Section E (Th10, 400, Some(("S", None))), (Th10, 401, Some(("S", None))), (Th10, 402, Some(("SSS", None))), @@ -1245,10 +1245,14 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { (Th11, 449, Some(("S", None))), (Th11, 450, Some(("S", None))), - // Section E (Didn't exist yet) + // Section F (Didn't exist yet) - // Section F + // Section G (Didn't exist yet) + + // Section H (Th11, 500, Some(("S", None))), // Not implemented + + // Section I (Didn't exist yet) ], var: &[ // This is placed here to avoid putting game-specific @@ -1260,9 +1264,9 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { static ECL_12: &'static CoreSignatures = &CoreSignatures { - inherit: &[ECL_10_18_COMMON], + inherit: &[ECL_10_19_COMMON], ins: &[ - // Section A + // Section B (Th12, 256, Some(("P(bs=4)ffSSS", None))), (Th12, 257, Some(("P(bs=4)ffSSS", None))), (Th12, 258, Some(("S", None))), @@ -1289,8 +1293,9 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { (Th12, 279, Some(("Sff", None))), (Th12, 280, Some(("P(bs=4)ffSSS", None))), (Th12, 281, Some(("SS", None))), + (Th125, 282, Some(("SS", None))), - // Section B + // Section C (Th12, 300, Some(("ff", None))), (Th12, 301, Some(("SSff", None))), (Th12, 302, Some(("ff", None))), @@ -1323,8 +1328,10 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { (Th12, 329, Some(("SSff", None))), (Th12, 330, Some(("ff", None))), (Th12, 331, Some(("SSff", None))), + (Th125, 332, Some(("S", None))), + (Th125, 333, Some(("S", None))), - // Section C + // Section D (Th12, 400, Some(("ff", None))), (Th12, 401, Some(("ff", None))), (Th12, 402, Some(("S(hex)", None))), @@ -1383,7 +1390,18 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { (Th12, 455, Some(("SS", None))), (Th12, 456, Some(("ffS", None))), - // Section D + (Th125, 427, None), + (Th125, 440, None), + (Th125, 454, None), + (Th125, 457, Some(("", None))), + (Th125, 458, Some(("S", None))), + (Th125, 459, Some(("S", None))), + (Th125, 460, Some(("f", None))), + (Th125, 461, Some(("f", None))), + (Th125, 462, Some(("S", None))), + // (Th125, 463, Some(("P(bs=4)", None))), + + // Section E (Th12, 500, Some(("S", None))), (Th12, 501, Some(("S", None))), (Th12, 502, Some(("SSS", None))), @@ -1424,8 +1442,9 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { // Final laser instruction moved (Th12, 534, Some(("S", None))), (Th12, 535, Some(("S", None))), + (Th125, 536, Some(("S", None))), - // Section E + // Section F (Th12, 600, Some(("Sffff", None))), (Th12, 601, Some(("SSSSSS(hex)", None))), (Th12, 602, Some(("S", None))), @@ -1438,15 +1457,20 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { (Th12, 609, Some(("Sf", None))), (Th12, 610, Some(("S", None))), (Th12, 611, Some(("S", None))), + (Th125, 612, Some(("ff", None))), - // Section F + // Section G (Didn't exist yet) + + // Section H (Th12, 700, Some(("S", None))), // Not implemented + + // Section I (Didn't exist yet) ], var: &[], }; -static ECL_10_18_COMMON: &'static CoreSignatures = &CoreSignatures { +static ECL_10_19_COMMON: &'static CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th10, 0, Some(("", None))), @@ -1463,7 +1487,7 @@ static ECL_10_18_COMMON: &'static CoreSignatures = &CoreSignatures { (Th10, 19, Some(("S", None))), (Th10, 20, Some(("SS", None))), (Th10, 21, Some(("", None))), - // (Th10, 30, Some((r#"p(bs=4)v(rep="g")"#, None))), + // (Th10, 30, Some((r#"p(bs=4)v(rep="g")"#, None))), // Implementation removed as of DS (Th10, 40, Some(("S", None))), // Some(IKind::FrameEnter) (Th10, 41, Some(("", None))), // Some(IKind::FrameLeave) (Th10, 42, Some(("S", None))), // Some(IKind::Push(Ty::Int)) @@ -1505,7 +1529,7 @@ static ECL_10_18_COMMON: &'static CoreSignatures = &CoreSignatures { (Th10, 82, Some(("f", None))), (Th10, 83, Some(("S", None))), (Th10, 84, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Int)) - (Th10, 85, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Float)) + (Th10, 85, Some(("", None))), // NOT an intrinsic, since it's broken (Th10, 86, Some(("fff", None))), (Th10, 87, Some(("ffff", None))), @@ -1514,6 +1538,14 @@ static ECL_10_18_COMMON: &'static CoreSignatures = &CoreSignatures { (Alcostg, 88, Some(("", None))), // Some(IKind::StackUnOp(U::Sqrt, Ty::Float)) (Th12, 89, Some(("fff", None))), + + // Finally not broken + (Th125, 85, Some(("", None))), // Some(IKind::StackUnOp(U::Neg, Ty::Float)) + (Th125, 90, Some(("fffff", None))), + (Th125, 91, Some(("SfSSff", None))), + (Th125, 92, Some(("SfSSffff", None))), + + (Th128, 22, Some((r#"SP(bs=4)"#, None))), ], var: &[ (Th10, -10000, Some("$")), @@ -1590,5 +1622,27 @@ static ECL_10_18_COMMON: &'static CoreSignatures = &CoreSignatures { (Th12, -9931, Some("$")), (Th12, -9930, Some("$")), + + (Th125, -9930, Some("$")), + (Th125, -9929, Some("$")), + (Th125, -9928, Some("$")), + (Th125, -9927, Some("$")), + (Th125, -9926, Some("$")), + (Th125, -9925, Some("$")), + (Th125, -9924, Some("$")), + (Th125, -9923, Some("$")), + (Th125, -9922, Some("%")), + (Th125, -9921, Some("%")), + (Th125, -9920, Some("%")), + (Th125, -9919, Some("%")), + (Th125, -9918, Some("%")), + (Th125, -9917, Some("%")), + (Th125, -9916, Some("%")), + (Th125, -9915, Some("%")), + (Th125, -9914, Some("$")), + (Th125, -9913, Some("$")), + (Th125, -9912, Some("$")), + (Th125, -9911, Some("%")), + (Th125, -9910, Some("%")), ], -}; \ No newline at end of file +}; diff --git a/src/core_mapfiles/end.rs b/src/core_mapfiles/end.rs new file mode 100644 index 0000000..889675f --- /dev/null +++ b/src/core_mapfiles/end.rs @@ -0,0 +1,55 @@ +use super::CoreSignatures; +use crate::Game::{self, *}; + +pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { + match game { + | Th095 | Alcostg | Th125 | Th143 | Th165 | Th185 + => EMPTY, + + | Th06 | Th07 | Th08 | Th09 + => END_06_09, + + | Th10 | Th11 | Th12 | Th128 | Th13 + | Th14 | Th15 | Th16 | Th17 | Th18 | Th19 + => END_10_19, + } +} + +// Bunkachou titles have no true END scripts. +static EMPTY: &CoreSignatures = &CoreSignatures { + inherit: &[], + ins: &[], + var: &[], +}; + +static END_06_09: &CoreSignatures = &CoreSignatures { + inherit: &[], + // TODO + ins: &[], + var: &[], +}; + +static END_10_19: &CoreSignatures = &CoreSignatures { + inherit: &[], + ins: &[ + (Th10, 0, Some(("", None))), + (Th10, 1, None), + (Th10, 2, None), + (Th10, 3, Some(("m(bs=4;mask=0x77,7,16)", None))), + (Th10, 4, Some(("", None))), + (Th10, 5, Some(("S", None))), + (Th10, 6, Some(("S", None))), + (Th10, 7, Some(("Sz(bs=4)", None))), + (Th10, 8, Some(("SSN", None))), + (Th10, 9, Some(("C", None))), + (Th10, 10, Some(("z(bs=4)", None))), + (Th10, 11, Some(("", None))), + (Th10, 12, Some(("z(bs=4)", None))), + (Th10, 13, Some(("S", None))), + (Th10, 14, Some(("S", None))), + (Th10, 15, Some(("SSN", None))), + (Th10, 16, Some(("SSN", None))), + (Th10, 17, Some(("SSN", None))), + ], + var: &[], +}; diff --git a/src/core_mapfiles/mod.rs b/src/core_mapfiles/mod.rs index 21de548..34ae1d9 100644 --- a/src/core_mapfiles/mod.rs +++ b/src/core_mapfiles/mod.rs @@ -8,6 +8,7 @@ use crate::llir::IntrinsicInstrKind; mod anm; mod ecl; +mod end; mod msg; mod std; @@ -20,7 +21,7 @@ pub fn core_mapfile(emitter: &RootEmitter, game: Game, language: LanguageKey) -> LanguageKey::Msg => self::msg::core_signatures(game), LanguageKey::Ecl => self::ecl::core_signatures(game), LanguageKey::Timeline => self::ecl::timeline_core_signatures(game), - LanguageKey::End => CoreSignatures::EMPTY, // TODO + LanguageKey::End => self::end::core_signatures(game), LanguageKey::Dummy => CoreSignatures::EMPTY, }; diff --git a/src/core_mapfiles/msg.rs b/src/core_mapfiles/msg.rs index cf54ee1..a166cd5 100644 --- a/src/core_mapfiles/msg.rs +++ b/src/core_mapfiles/msg.rs @@ -3,15 +3,15 @@ use crate::Game::{self, *}; pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { match game { - | Th095 | Th125 + | Th095 | Alcostg => EMPTY, | Th06 | Th07 | Th08 | Th09 => MSG_06_09, - | Th10 | Alcostg | Th11 | Th12 | Th128 | Th13 - | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 - => MSG_10_18, + | Th10 | Th11 | Th12 | Th125 | Th128 | Th13 + | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 + => MSG_10_19, } } @@ -73,7 +73,7 @@ static MSG_06_09: &CoreSignatures = &CoreSignatures { ], var: &[], }; -static MSG_10_18: &CoreSignatures = &CoreSignatures { +static MSG_10_19: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th10, 0, Some(("", None))), @@ -161,6 +161,32 @@ static MSG_10_18: &CoreSignatures = &CoreSignatures { (Th18, 7, Some(("S", None))), (Th18, 13, Some(("SS", None))), (Th18, 36, Some(("", None))), + + (Th185, 19, Some(("S", None))), + (Th185, 37, Some(("", None))), + (Th185, 38, Some(("", None))), + (Th185, 39, Some(("", None))), + (Th185, 40, Some(("m(bs=4;mask=0x77,7,16;furibug)", None))), // Just hoping these string types are correct + (Th185, 41, Some(("m(bs=4;mask=0x77,7,16;furibug)", None))), + + // Th19 Notes: + // 20 doesn't read an argument, check size + (Th19, 31, None), + (Th19, 42, Some(("S", None))), + (Th19, 43, Some(("S", None))), + (Th19, 44, Some(("ff", None))), + (Th19, 45, Some(("ff", None))), + (Th19, 46, Some(("SS", None))), + (Th19, 47, Some(("SS", None))), + (Th19, 48, Some(("S", None))), + (Th19, 49, Some(("S", None))), + (Th19, 50, Some(("S", None))), + (Th19, 51, Some(("S", None))), + (Th19, 52, Some(("", None))), + (Th19, 53, Some(("", None))), + (Th19, 54, Some(("", None))), + (Th19, 55, Some(("", None))), + (Th19, 56, Some(("", None))), ], var: &[], }; diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index 73bd4c5..2127811 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -11,8 +11,8 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { => STD_07_09, | Th095 | Th10 | Alcostg | Th11 | Th12 | Th125 | Th128 - | Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 - => STD_095_18 + | Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 + => STD_095_19 } } @@ -72,7 +72,7 @@ static STD_07_09: &CoreSignatures = &CoreSignatures { var: &[], }; -static STD_095_18: &CoreSignatures = &CoreSignatures { +static STD_095_19: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th095, 0, Some(("", None))), diff --git a/src/fmt.rs b/src/fmt.rs index 7c5480d..d87a0fe 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -892,7 +892,7 @@ impl Format for ast::Expr { token![unop $] | token![unop %] | token![unop int] | token![unop float] | - token![sin] | token![cos] | token![sqrt] + token![sin] | token![cos] | token![tan] | token![acos] | token![atan] | token![sqrt] => out.fmt((op, "(", SuppressParens(x), ")")), }, ast::Expr::XcrementOp { order: ast::XcrementOpOrder::Pre, op, var } => out.fmt((op, var)), diff --git a/src/formats/anm/mod.rs b/src/formats/anm/mod.rs index b82964d..4a2d5a5 100644 --- a/src/formats/anm/mod.rs +++ b/src/formats/anm/mod.rs @@ -1185,7 +1185,7 @@ impl Version { Th08 | Th09 => Version::V3, Th095 | Th10 | Alcostg => Version::V4, Th11 | Th12 | Th125 | Th128 => Version::V7, - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 => Version::V8, + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => Version::V8, } } diff --git a/src/formats/msg.rs b/src/formats/msg.rs index b85aa4c..1616602 100644 --- a/src/formats/msg.rs +++ b/src/formats/msg.rs @@ -22,6 +22,7 @@ use indexmap::IndexMap; pub struct MsgFile { pub dense_table: Vec, pub scripts: IndexMap>, + pub extended_header: Option>, /// Filename of a read binary file, for display purposes only. binary_filename: Option, } @@ -395,6 +396,7 @@ fn compile( Ok(MsgFile { dense_table, scripts, + extended_header: None, /// Filename of a read binary file, for display purposes only. binary_filename: None, }) @@ -436,6 +438,13 @@ fn read_msg( let start_pos = reader.pos()?; let script_table_len = reader.read_u32()?; + + let extended_header = if format.extended_header() { + Some(reader.read_u32s(20)?) + } else { + None + }; + let script_table = { (0..script_table_len).map(|_| { Ok(RawScriptTableEntry { @@ -486,7 +495,7 @@ fn read_msg( }).collect(); let binary_filename = Some(reader.display_filename().to_owned()); - Ok(MsgFile { dense_table, scripts, binary_filename }) + Ok(MsgFile { dense_table, scripts, extended_header, binary_filename }) } #[derive(Debug)] @@ -588,8 +597,24 @@ fn write_msg( fn game_format(game: Game, language: LanguageKey, emitter: &RootEmitter) -> Result { match (game, language) { | (Game::Th095, LanguageKey::Msg) - | (Game::Th125, LanguageKey::Msg) - => Err(emitter.emit(error!("{} does not have stage MSG files; maybe try 'trumsg --mission'?", game))), + | (Game::Th095, LanguageKey::End) + => Err(emitter.emit(error!("{} does not have MSG files; maybe try 'trumsg --mission'?", game))), + + | (Game::Alcostg, LanguageKey::Msg) + | (Game::Alcostg, LanguageKey::End) + => Err(emitter.emit(error!("{} does not have MSG files", game))), + + | (Game::Th125, LanguageKey::End) + | (Game::Th143, LanguageKey::End) + | (Game::Th165, LanguageKey::End) + | (Game::Th185, LanguageKey::End) + => Err(emitter.emit(error!("{} does not have ending MSG files", game))), + + | (Game::Th06, LanguageKey::End) + | (Game::Th07, LanguageKey::End) + | (Game::Th08, LanguageKey::End) + | (Game::Th09, LanguageKey::End) + => Err(emitter.emit(error!("--ending is not yet implemented for {}", game))), _ => Ok(FileFormat { game, language }) } @@ -606,18 +631,23 @@ impl FileFormat { fn table_has_flags(&self) -> bool { self.game >= Game::Th09 } + + fn extended_header(&self) -> bool { + self.language == LanguageKey::Msg && self.game == Game::Th19 + } fn language_hooks(&self) -> Box { match self.game { | Game::Th06 | Game::Th07 | Game::Th08 - | Game::Th09 | Game::Th10 | Game::Alcostg | Game::Th11 - | Game::Th12 | Game::Th128 | Game::Th13 - | Game::Th14 | Game::Th143 | Game::Th15 - | Game::Th16 | Game::Th165 | Game::Th17 - | Game::Th18 + | Game::Th09 | Game::Th10 | Game::Th11 + | Game::Th12 | Game::Th125 | Game::Th128 + | Game::Th13 | Game::Th14 | Game::Th143 + | Game::Th15 | Game::Th16 | Game::Th165 + | Game::Th17 | Game::Th18 | Game::Th185 + | Game::Th19 => Box::new(MsgHooks { language: self.language }), - | Game::Th095 | Game::Th125 + | Game::Th095 | Game::Alcostg => unreachable!(), } } diff --git a/src/game.rs b/src/game.rs index 0301beb..b3d91be 100644 --- a/src/game.rs +++ b/src/game.rs @@ -6,8 +6,9 @@ use crate::diagnostic::Diagnostic; pub enum Game { Th06, Th07, Th08, Th09, Th095, Th10, Alcostg, Th11, Th12, Th125, Th128, Th13, Th14, Th143, Th15, Th16, Th165, Th17, Th18, + Th185, Th19 } -macro_rules! max_game_str { () => { "th18" }; } +macro_rules! max_game_str { () => { "th19" }; } impl std::str::FromStr for Game { type Err = Diagnostic; @@ -46,6 +47,8 @@ impl std::str::FromStr for Game { 165 => Ok(Game::Th165), 17 => Ok(Game::Th17), 18 => Ok(Game::Th18), + 185 => Ok(Game::Th185), + 19 => Ok(Game::Th19), _ => Err(unknown_game()), } } @@ -73,6 +76,8 @@ impl Game { Game::Th165 => "VD", Game::Th17 => "WBaWC", Game::Th18 => "UM", + Game::Th185 => "HBM", + Game::Th19 => "UDoALG", } } @@ -97,6 +102,9 @@ impl Game { Game::Th165 => "th165", Game::Th17 => "th17", Game::Th18 => "th18", + Game::Th185 => "th185", + Game::Th19 => "th19", + } } @@ -121,6 +129,8 @@ impl Game { Game::Th165 => 165, Game::Th17 => 17, Game::Th18 => 18, + Game::Th185 => 185, + Game::Th19 => 19, } } } diff --git a/src/llir/abi.rs b/src/llir/abi.rs index 0bd7eea..68957f0 100644 --- a/src/llir/abi.rs +++ b/src/llir/abi.rs @@ -42,7 +42,14 @@ pub enum ArgEncoding { /// The first argument may have `arg0` if it is two bytes large. This indicates that the argument is /// stored in the arg0 header field of the instruction in EoSD and PCB ECL. (which is mapped to the /// `@arg0` pseudo-argument in raw instruction syntax) - Integer { size: u8, ty_color: Option, arg0: bool, immediate: bool, extend: bool, format: ast::IntFormat }, + Integer { + size: u8, + ty_color: Option, + arg0: bool, + immediate: bool, + extend: bool, + format: ast::IntFormat + }, /// `o` in mapfile. Max of one per instruction. Is decoded to a label. JumpOffset, /// `t` in mapfile. Max of one per instruction, and requires an accompanying `o` arg. @@ -114,12 +121,14 @@ impl ArgEncoding { impl fmt::Display for Impl<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match &self.0 { - Enc::Integer { arg0: true, ty_color, size, immediate, format, extend } => write!( - f, - "{} (in timeline arg0)", - Enc::Integer { extend: *extend, format: *format, immediate: *immediate, arg0: false, ty_color: ty_color.clone(), size: *size }.descr(), - ), + match self.0 { + Enc::Integer { arg0: true, .. } => { + let mut temp = self.0.clone(); + write!(f, "{} (in timeline arg0)", match &mut temp { + Enc::Integer { arg0, .. } => { *arg0 = false; temp }, + _ => unreachable!(), + }.descr()) + }, Enc::Integer { ty_color: Some(en), size: 4, .. } => write!(f, "{}", en.descr()), Enc::Integer { ty_color: Some(en), size, .. } => write!(f, "{size}-byte {}", en.descr()), Enc::Integer { ty_color: None, size: 1, .. } => write!(f, "byte-sized integer"), diff --git a/src/mapfile.rs b/src/mapfile.rs index 6165a5b..a686a3b 100644 --- a/src/mapfile.rs +++ b/src/mapfile.rs @@ -174,6 +174,7 @@ fn mapfile_from_seqmap(seqmap: SeqmapRaw<'_>, emitter: &impl Emitter) -> Result< "!anmmap" => LanguageKey::Anm, "!stdmap" => LanguageKey::Std, "!msgmap" => LanguageKey::Msg, + "!endmap" => LanguageKey::End, TIMELINE_MAP_MAGIC => LanguageKey::Timeline, _ => return Err(emitter.emit(error!( message("bad magic: {:?}", magic), @@ -285,6 +286,7 @@ fn borrowed_seqmap_from_mapfile(mapfile: &Mapfile) -> SeqmapRaw<'_> { LanguageKey::Anm => "!anmmap", LanguageKey::Std => "!stdmap", LanguageKey::Msg => "!msgmap", + LanguageKey::End => "!endmap", LanguageKey::Timeline => TIMELINE_MAP_MAGIC, _ => unimplemented!("unexpected language key: {language:?}"), }; diff --git a/src/passes/const_simplify.rs b/src/passes/const_simplify.rs index 26ead1f..56144af 100644 --- a/src/passes/const_simplify.rs +++ b/src/passes/const_simplify.rs @@ -51,6 +51,9 @@ impl ast::UnOpKind { token![unop ~] => Some(ScalarValue::Int(!x)), token![unop sin] | token![unop cos] | + token![unop tan] | + token![unop acos] | + token![unop atan] | token![unop sqrt] => uncaught_type_error(), token![unop int] => Some(ScalarValue::Int(x)), token![unop float] => Some(ScalarValue::Float(x as f32)), @@ -64,6 +67,9 @@ impl ast::UnOpKind { token![unop ~] => uncaught_type_error(), token![unop sin] => Some(ScalarValue::Float(x.sin())), token![unop cos] => Some(ScalarValue::Float(x.cos())), + token![unop tan] => Some(ScalarValue::Float(x.tan())), + token![unop acos] => Some(ScalarValue::Float(x.acos())), + token![unop atan] => Some(ScalarValue::Float(x.atan())), token![unop sqrt] => Some(ScalarValue::Float(x.sqrt())), token![unop int] => Some(ScalarValue::Int(x as i32)), token![unop float] => Some(ScalarValue::Float(x)), diff --git a/src/passes/type_check.rs b/src/passes/type_check.rs index 96cd6d5..6552a93 100644 --- a/src/passes/type_check.rs +++ b/src/passes/type_check.rs @@ -652,6 +652,9 @@ impl ExprTypeChecker<'_, '_> { | token![unop sin] | token![unop cos] + | token![unop tan] + | token![unop acos] + | token![unop atan] | token![unop sqrt] => self.require_float(arg_ty, op.span, arg_span), } @@ -681,6 +684,9 @@ impl ast::Expr { token![unop sin] | token![unop cos] | + token![unop tan] | + token![unop acos] | + token![unop atan] | token![unop sqrt] => ScalarType::Float, token![unop $] => ScalarType::Int, diff --git a/src/quote.rs b/src/quote.rs index baa1546..6a9c540 100644 --- a/src/quote.rs +++ b/src/quote.rs @@ -33,6 +33,9 @@ macro_rules! token { ($(unop)? ~) => { $crate::ast::UnOpKind::BitNot }; ($(unop)? sin) => { $crate::ast::UnOpKind::Sin }; ($(unop)? cos) => { $crate::ast::UnOpKind::Cos }; + ($(unop)? tan) => { $crate::ast::UnOpKind::Tan }; + ($(unop)? acos) => { $crate::ast::UnOpKind::Acos }; + ($(unop)? atan) => { $crate::ast::UnOpKind::Atan }; ($(unop)? sqrt) => { $crate::ast::UnOpKind::Sqrt }; ( unop $) => { $crate::ast::UnOpKind::EncodeI }; ( unop %) => { $crate::ast::UnOpKind::EncodeF }; From 21c30ddffcf14a6801e1969f375353128aa095b3 Mon Sep 17 00:00:00 2001 From: zero318 Date: Sat, 27 Apr 2024 02:32:08 -0400 Subject: [PATCH 22/26] Fixed roundtrip problems --- src/formats/anm/mod.rs | 31 +++++- src/formats/anm/read_write.rs | 73 ++++++++++--- src/formats/msg.rs | 53 ++++++--- src/formats/std.rs | 32 ++++-- src/image/color.rs | 195 +++++++++++++++++++++++++++++++++- src/io.rs | 6 ++ src/llir/abi.rs | 20 ++++ 7 files changed, 366 insertions(+), 44 deletions(-) diff --git a/src/formats/anm/mod.rs b/src/formats/anm/mod.rs index 4a2d5a5..6783265 100644 --- a/src/formats/anm/mod.rs +++ b/src/formats/anm/mod.rs @@ -225,6 +225,9 @@ pub struct EntrySpecs { /// e.g. the border around the game. (not used for things like `ascii.anm` which have dedicated files /// for each resolution) pub low_res_scale: bool, + pub jpeg_quality: u32, + pub full_width: u32, + pub full_height: u32, } #[derive(Debug, Clone, Default)] @@ -244,6 +247,9 @@ struct WorkingEntrySpecs { offset_y: SoftOption, memory_priority: SoftOption, low_res_scale: SoftOption, + jpeg_quality: SoftOption, + full_width: SoftOption, + full_height: SoftOption, } fn default_memory_priority(version: Version) -> u32 { @@ -267,6 +273,9 @@ fn finalize_entry(fs: &Fs, entry: WorkingEntry, game: Game, emitter: &impl Emitt specs.memory_priority.set_soft_if_missing(default_memory_priority(version)); specs.low_res_scale.set_soft_if_missing(DEFAULT_LOW_RES_SCALE); specs.has_data.set_soft_if_missing(DEFAULT_HAS_DATA); + specs.jpeg_quality.set_soft_if_missing(0); + specs.full_width.set_soft_if_missing(0); + specs.full_height.set_soft_if_missing(0); // Do this now. For missing images that are also missing metadata, // this tends to produce the nicest error message. @@ -314,6 +323,9 @@ fn finalize_entry(fs: &Fs, entry: WorkingEntry, game: Game, emitter: &impl Emitt colorkey: specs.colorkey.into_option().expect("was filled by default"), memory_priority: specs.memory_priority.into_option().expect("was filled by default"), low_res_scale: specs.low_res_scale.into_option().expect("was filled by default"), + jpeg_quality: specs.jpeg_quality.into_option().expect("was filled by default"), + full_width: specs.full_width.into_option().expect("was filled by default"), + full_height: specs.full_height.into_option().expect("was filled by default"), }, texture_metadata: texture_data.as_ref().map(|_| TextureMetadata { width: specs.img_width.into_option().expect("was filled by default"), @@ -534,6 +546,7 @@ impl Entry { let EntrySpecs { rt_width, rt_height, rt_format, colorkey, offset_x, offset_y, memory_priority, low_res_scale, + jpeg_quality, full_width, full_height, } = self.specs; // suppress defaults @@ -562,6 +575,9 @@ impl Entry { .field_opt("rt_format", Some(rt_format).filter(|&x| x != img_format).map(format_to_meta)) .field_opt("memory_priority", Some(memory_priority).filter(|&x| x != default_memory_priority(version))) .field_opt("low_res_scale", Some(low_res_scale).filter(|&x| x != DEFAULT_LOW_RES_SCALE)) + .field_opt("jpeg_quality", Some(jpeg_quality).filter(|&x| x != 0)) + .field_opt("full_width", Some(full_width).filter(|&x| x != 0)) + .field_opt("full_height", Some(full_height).filter(|&x| x != 0)) .field("sprites", &self.sprites) .build_fields() } @@ -641,6 +657,9 @@ impl WorkingEntry { let memory_priority = make_explicit(m.get_field("memory_priority")?); let low_res_scale = make_explicit(m.get_field("low_res_scale")?); let has_data = make_explicit(m.get_field("has_data")?); + let jpeg_quality = make_explicit(m.get_field("jpeg_quality")?); + let full_width = make_explicit(m.get_field("full_width")?); + let full_height = make_explicit(m.get_field("full_height")?); let path: Sp = m.expect_field("path")?; let path_2 = m.get_field("path_2")?; let sprites = m.get_field("sprites")?.unwrap_or_default(); @@ -664,6 +683,7 @@ impl WorkingEntry { img_width, img_height, img_format, colorkey, offset_x, offset_y, memory_priority, has_data, low_res_scale, + jpeg_quality, full_width, full_height, }; let loaded_texture = None; let scripts = Default::default(); @@ -768,17 +788,19 @@ pub struct Sprite { pub id: Option, pub offset: [f32; 2], pub size: [f32; 2], + pub unknown: Option<[f32; 5]>, } impl ToMeta for Sprite { fn to_meta(&self) -> Meta { - let &Sprite { id, offset, size } = self; + let &Sprite { id, offset, size, unknown, } = self; Meta::make_object() .field("x", &offset[0]) .field("y", &offset[1]) .field("w", &size[0]) .field("h", &size[1]) .field_opt("id", id.as_ref()) + .field_opt("unknown", unknown.as_ref()) .build() } } @@ -789,6 +811,7 @@ impl FromMeta<'_> for Sprite { id: m.get_field("id")?, offset: [m.expect_field("x")?, m.expect_field("y")?], size: [m.expect_field("w")?, m.expect_field("h")?], + unknown: m.get_field("unknown")? })) } } @@ -887,6 +910,9 @@ fn update_entry_from_anm_image_source(dest_file: &mut WorkingEntry, src_file: En colorkey: src_colorkey, offset_x: src_offset_x, offset_y: src_offset_y, memory_priority: src_memory_priority, low_res_scale: src_low_res_scale, + jpeg_quality: src_jpeg_quality, + full_width: src_full_width, + full_height: src_full_height, } = src_specs; dest_file.specs.has_data.set_soft(HasData::from(src_texture_data.is_some())); @@ -910,6 +936,9 @@ fn update_entry_from_anm_image_source(dest_file: &mut WorkingEntry, src_file: En dest_file.specs.offset_y.set_soft(src_offset_y); dest_file.specs.memory_priority.set_soft(src_memory_priority); dest_file.specs.low_res_scale.set_soft(src_low_res_scale); + dest_file.specs.jpeg_quality.set_soft(src_jpeg_quality); + dest_file.specs.full_width.set_soft(src_full_width); + dest_file.specs.full_height.set_soft(src_full_height); Ok(()) } diff --git a/src/formats/anm/read_write.rs b/src/formats/anm/read_write.rs index 293d7ef..4ee520d 100644 --- a/src/formats/anm/read_write.rs +++ b/src/formats/anm/read_write.rs @@ -29,7 +29,10 @@ struct EntryHeaderData { thtx_offset: Option, has_data: u32, low_res_scale: u32, + jpeg_quality: u32, next_offset: u64, + full_width: u32, + full_height: u32, } pub fn read_anm( @@ -107,7 +110,7 @@ fn read_entry( let mut sprites_seen_in_entry = IndexSet::new(); let sprites = sprite_offsets.iter().map(|&offset| { reader.seek_to(entry_pos + offset as u64)?; - let sprite = read_sprite(reader)?; + let sprite = read_sprite(reader, format.has_extended_sprites())?; let sprite_id = sprite.id.expect("(bug!) sprite read from binary must always have id"); // Note: Duplicate IDs do happen between different entries, so we don't check that. @@ -164,6 +167,9 @@ fn read_entry( offset_x: header_data.offset_x, offset_y: header_data.offset_y, memory_priority: header_data.memory_priority, low_res_scale: header_data.low_res_scale != 0, + jpeg_quality: header_data.jpeg_quality, + full_width: header_data.full_width, + full_height: header_data.full_height, }; let entry = Entry { @@ -226,7 +232,8 @@ fn write_entry( let EntrySpecs { rt_width, rt_height, rt_format, colorkey, offset_x, offset_y, memory_priority, - low_res_scale, + low_res_scale, jpeg_quality, + full_width, full_height } = entry.specs; file_format.write_header(w, &EntryHeaderData { @@ -241,6 +248,9 @@ fn write_entry( // we will overwrite these later name_offset: 0, secondary_name_offset: None, next_offset: 0, thtx_offset: None, + jpeg_quality: jpeg_quality as u32, + full_width: full_width as u32, + full_height: full_height as u32, })?; let sprite_offsets_pos = w.pos()?; @@ -263,7 +273,7 @@ fn write_entry( let sprite_id = sprite.id.unwrap_or(*next_auto_sprite_id); *next_auto_sprite_id = sprite_id.wrapping_add(1); - write_sprite(w, sprite_id, sprite)?; + write_sprite(w, sprite_id, sprite, file_format.has_extended_sprites())?; Ok(sprite_offset) }).collect::>>()?; @@ -325,11 +335,16 @@ fn write_entry( Ok(()) } -fn read_sprite(f: &mut BinReader) -> ReadResult { +fn read_sprite(f: &mut BinReader, extended: bool) -> ReadResult { Ok(Sprite { id: Some(f.read_u32()?), offset: f.read_f32s_2()?, size: f.read_f32s_2()?, + unknown: if extended { + Some(f.read_f32s_5()?) + } else { + None + }, }) } @@ -337,10 +352,15 @@ fn write_sprite( f: &mut BinWriter, sprite_id: u32, // we ignore sprite.id because that can be None sprite: &Sprite, + extended: bool ) -> WriteResult { f.write_u32(sprite_id)?; f.write_f32s(&sprite.offset)?; - f.write_f32s(&sprite.size) + f.write_f32s(&sprite.size)?; + if extended { + f.write_f32s(&sprite.unknown.unwrap_or_else(|| [0.0, 0.0, 1.0, 1.0, 0.0]))?; + } + Ok(()) } #[inline(never)] @@ -390,6 +410,7 @@ fn write_texture(f: &mut BinWriter, data: &TextureData, metadata: &TextureMetada /// Type responsible for dealing with version differences in the container format. struct FileFormat { version: Version, + game: Game, instr_format: Box, } @@ -400,7 +421,11 @@ impl FileFormat { fn from_game(game: Game) -> Self { let version = Version::from_game(game); let instr_format = get_instr_format(version); - FileFormat { version, instr_format } + FileFormat { version, game, instr_format } + } + + fn has_extended_sprites(&self) -> bool { + self.game == Game::Th19 } fn read_header(&self, f: &mut BinReader, emitter: &dyn Emitter) -> ReadResult { @@ -430,10 +455,11 @@ impl FileFormat { let version = f.read_u32()? as _; let memory_priority = f.read_u32()? as _; let thtx_offset = NonZeroU64::new(f.read_u32()? as _) as _; - let has_data = f.read_u16()? as _; - warn_if_nonzero!("unused_2", f.read_u16()?); + let has_data = f.read_u8()? as _; + warn_if_nonzero!("unused_2", f.read_u8()?); + warn_if_nonzero!("unused_3", f.read_u16()?); let next_offset = f.read_u32()? as _; - warn_if_nonzero!("unused_3", f.read_u32()?); + warn_if_nonzero!("unused_4", f.read_u32()?); Ok(EntryHeaderData { version, num_sprites, num_scripts, @@ -443,6 +469,7 @@ impl FileFormat { next_offset, secondary_name_offset, colorkey, memory_priority, thtx_offset, has_data, offset_x: 0, offset_y: 0, low_res_scale: 0, + jpeg_quality: 0, full_width: 0, full_height: 0, }) } else { @@ -459,13 +486,20 @@ impl FileFormat { let offset_y = f.read_u16()? as _; let memory_priority = f.read_u32()? as _; let thtx_offset = NonZeroU64::new(f.read_u32()? as _); - let has_data = f.read_u16()? as _; - let low_res_scale = f.read_u16()? as _; + let has_data = f.read_u8()? as _; + warn_if_nonzero!("unused_1", f.read_u8()?); + let low_res_scale = f.read_u8()? as _; + let jpeg_quality = f.read_u8()? as _; let next_offset = f.read_u32()? as _; + let full_width = f.read_u16()? as _; + let full_height = f.read_u16()? as _; + // header gets padded to 16 dwords + warn_if_nonzero!("header_padding1", f.read_u32()?); + warn_if_nonzero!("header_padding2", f.read_u32()?); + warn_if_nonzero!("header_padding3", f.read_u32()?); + warn_if_nonzero!("header_padding4", f.read_u32()?); + warn_if_nonzero!("header_padding5", f.read_u32()?); - for _ in 0..6 { // header gets padded to 16 dwords - warn_if_nonzero!("header padding", f.read_u32()?); - } Ok(EntryHeaderData { version, num_sprites, num_scripts, rt_width: width, @@ -475,6 +509,7 @@ impl FileFormat { memory_priority, thtx_offset, has_data, secondary_name_offset: None, colorkey: 0, + jpeg_quality, full_width, full_height, }) } } @@ -514,10 +549,14 @@ impl FileFormat { f.write_u16(header.offset_y as _)?; f.write_u32(header.memory_priority as _)?; f.write_u32(header.thtx_offset.map(NonZeroU64::get).unwrap_or(0) as _)?; - f.write_u16(header.has_data as _)?; - f.write_u16(header.low_res_scale as _)?; + f.write_u8(header.has_data as _)?; + f.write_u8(0)?; + f.write_u8(header.low_res_scale as _)?; + f.write_u8(header.jpeg_quality as _)?; f.write_u32(header.next_offset as _)?; - f.write_u32s(&[0; 6])?; + f.write_u16(header.full_width as _)?; + f.write_u16(header.full_height as _)?; + f.write_u32s(&[0; 5])?; } Ok(()) } diff --git a/src/formats/msg.rs b/src/formats/msg.rs index 1616602..e07fb2f 100644 --- a/src/formats/msg.rs +++ b/src/formats/msg.rs @@ -76,15 +76,16 @@ impl Default for ScriptTableEntry { /// An alternative structure closer to the Meta representation. #[derive(Debug, Clone, PartialEq)] -struct SparseScriptTable { +struct MsgMeta { /// The script table is sparsely filled and could potentially have empty entries after the /// last full one, so we must store its true length. table_len: Sp, table: IndexMap, ScriptTableEntry>, + extended_header: Option>, default: ScriptTableEntry, } -impl SparseScriptTable { +impl MsgMeta { fn make_meta(&self) -> meta::Fields { let mut builder = Meta::make_object(); @@ -103,6 +104,10 @@ impl SparseScriptTable { inner.field_default("default", &self.default, &Default::default()); inner.build() }); + + if let Some(extended_header) = &self.extended_header { + builder.field("header", extended_header); + } builder.build_fields() } @@ -131,11 +136,16 @@ impl SparseScriptTable { let table_len = m.get_field("table_len")?.unwrap_or_else(|| { sp!(fields.span => sparse_table_implicit_len(&int_map)) }); - Ok(SparseScriptTable { table_len, table: int_map, default }) + Ok(MsgMeta { + table_len, + table: int_map, + extended_header: m.get_field("header")?, + default + }) }) } - fn densify(&self) -> Vec { + fn make_dense_script_table(&self) -> Vec { (0..self.table_len.value) .map(|index| { self.table.get(&index).unwrap_or_else(|| &self.default).clone() @@ -193,13 +203,13 @@ fn decompile( ) -> Result { let hooks = &*format.language_hooks(); - let sparse_script_table = sparsify_script_table(&msg.dense_table); + let msg_meta = generate_msg_meta(&msg.dense_table, msg.extended_header.clone()); let const_proof = crate::passes::evaluate_const_vars::run(ctx)?; let mut raiser = llir::Raiser::new(hooks, ctx.emitter, ctx, decompile_options, const_proof)?; let mut items = vec![sp!(ast::Item::Meta { keyword: sp!(token![meta]), - fields: sp!(sparse_script_table.make_meta()), + fields: sp!(msg_meta.make_meta()), })]; items.extend(msg.scripts.iter().map(|(ident, instrs)| { let code = raiser.raise_instrs_to_sub_ast(emitter, instrs, ctx)?; @@ -221,7 +231,7 @@ fn decompile( Ok(script) } -fn sparsify_script_table(dense_table: &[ScriptTableEntry]) -> SparseScriptTable { +fn generate_msg_meta(dense_table: &[ScriptTableEntry], extended_header: Option>) -> MsgMeta { let counts = get_counts(dense_table.iter()); // get first index of all nonzero entries @@ -254,7 +264,12 @@ fn sparsify_script_table(dense_table: &[ScriptTableEntry]) -> SparseScriptTable }; let table_len = sp!(dense_table.len() as u32); - SparseScriptTable { table_len, table, default } + MsgMeta { + table_len, + table, + extended_header, + default + } } fn get_counts(items: impl IntoIterator) -> BTreeMap { @@ -329,10 +344,10 @@ fn compile( None => return Err(emit(error!("missing 'meta' section"))), } }; - let sparse_table: SparseScriptTable = { - SparseScriptTable::from_fields(meta).map_err(|e| ctx.emitter.emit(e))? + let msg_meta: MsgMeta = { + MsgMeta::from_fields(meta).map_err(|e| ctx.emitter.emit(e))? }; - let dense_table = sparse_table.densify(); + let dense_table = msg_meta.make_dense_script_table(); let script_table_indices_by_name = get_script_table_indices_by_name(&dense_table); let mut errors = ErrorFlag::new(); @@ -362,13 +377,13 @@ fn compile( errors.into_result(())?; let unused_table_keys = { - sparse_table.table.keys().copied() - .filter(|&key| key >= sparse_table.table_len).collect::>() + msg_meta.table.keys().copied() + .filter(|&key| key >= msg_meta.table_len).collect::>() }; if !unused_table_keys.is_empty() { let mut diag = warning!( message("unused script table entry"), - secondary(sparse_table.table_len, "unused due to this length"), + secondary(msg_meta.table_len, "unused due to this length"), ); for key in unused_table_keys { diag.primary(key.span, format!("unused table entry")); @@ -377,8 +392,8 @@ fn compile( } let used_scripts = { - std::iter::once(sparse_table.default.clone()) - .chain(sparse_table.table.values().cloned()) + std::iter::once(msg_meta.default.clone()) + .chain(msg_meta.table.values().cloned()) .filter_map(|entry| match entry.script.value { ScriptTableOffset::Zero => None, ScriptTableOffset::Name(ref ident) => Some(ident.clone()), @@ -396,7 +411,7 @@ fn compile( Ok(MsgFile { dense_table, scripts, - extended_header: None, + extended_header: msg_meta.extended_header, /// Filename of a read binary file, for display purposes only. binary_filename: None, }) @@ -542,6 +557,10 @@ fn write_msg( let start_pos = w.pos()?; w.write_u32(msg.dense_table.len() as _)?; + + if msg.extended_header.is_some() { + w.write_u32s(&msg.extended_header.as_ref().unwrap())?; + } let script_offsets_pos = w.pos()?; for _ in 0..msg.dense_table.len() { diff --git a/src/formats/std.rs b/src/formats/std.rs index 8714d4c..55e9ff8 100644 --- a/src/formats/std.rs +++ b/src/formats/std.rs @@ -113,6 +113,7 @@ pub struct Object { /// This field determines when objects are drawn relative to 2D sprites, /// as if their polygon scripts had the given `layer(n)` command. pub layer: u16, + pub id: Option, pub pos: [f32; 3], pub size: [f32; 3], pub quads: Vec, @@ -122,6 +123,7 @@ impl FromMeta<'_> for Object { fn from_meta(meta: &Sp) -> Result> { meta.parse_object(|m| Ok(Object { layer: m.expect_renamed_field::("unknown", "layer")? as u16, + id: m.get_field("id")?, pos: m.expect_field("pos")?, size: m.expect_field("size")?, quads: m.expect_field("quads")?, @@ -131,12 +133,16 @@ impl FromMeta<'_> for Object { impl ToMeta for Object { fn to_meta(&self) -> Meta { - Meta::make_object() - .field("layer", &(self.layer as i32)) - .field("pos", &self.pos) - .field("size", &self.size) - .field("quads", &self.quads) - .build() + let mut builder = Meta::make_object(); + if let Some(id) = &self.id { + builder.field("id", id); + } + builder.field("layer", &(self.layer as i32)); + builder.field("pos", &self.pos); + builder.field("size", &self.size); + builder.field("quads", &self.quads); + + builder.build() } } @@ -494,11 +500,21 @@ fn read_object(f: &mut BinReader, emitter: &impl Emitter, expected_id: usize) -> while let Some(quad) = read_quad(f, emitter)? { quads.push(quad); } - Ok(Object { layer, pos, size, quads }) + Ok(Object { + layer, + id: if id as usize == expected_id { + None + } else { + Some(id as u32) + }, + pos, + size, + quads + }) } fn write_object(f: &mut BinWriter, emitter: &impl Emitter, format: &dyn FileFormat, id: usize, x: &Object) -> WriteResult { - f.write_u16(id as u16)?; + f.write_u16(x.id.unwrap_or_else(|| id as u32) as u16)?; f.write_u16(x.layer)?; f.write_f32s(&x.pos)?; f.write_f32s(&x.size)?; diff --git a/src/image/color.rs b/src/image/color.rs index 075f93b..58043dd 100644 --- a/src/image/color.rs +++ b/src/image/color.rs @@ -4,70 +4,102 @@ use std::rc::Rc; use crate::io::{BinRead, BinWrite}; const FORMAT_ARGB_8888: u32 = 1; +const FORMAT_ARGB_1555: u32 = 2; const FORMAT_RGB_565: u32 = 3; +const FORMAT_RGB_888: u32 = 4; const FORMAT_ARGB_4444: u32 = 5; +const FORMAT_ARGB_8332: u32 = 6; const FORMAT_GRAY_8: u32 = 7; +const FORMAT_RGB_332: u32 = 8; #[repr(u32)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ColorFormat { Argb8888 = FORMAT_ARGB_8888, + Argb1555 = FORMAT_ARGB_1555, Rgb565 = FORMAT_RGB_565, + Rgb888 = FORMAT_RGB_888, Argb4444 = FORMAT_ARGB_4444, + Argb8332 = FORMAT_ARGB_8332, Gray8 = FORMAT_GRAY_8, + Rgb332 = FORMAT_RGB_332, } impl ColorFormat { pub fn from_format_num(num: u32) -> Option { match num { FORMAT_ARGB_8888 => Some(Self::Argb8888), + FORMAT_ARGB_1555 => Some(Self::Argb1555), FORMAT_RGB_565 => Some(Self::Rgb565), + FORMAT_RGB_888 => Some(Self::Rgb888), FORMAT_ARGB_4444 => Some(Self::Argb4444), + FORMAT_ARGB_8332 => Some(Self::Argb8332), FORMAT_GRAY_8 => Some(Self::Gray8), + FORMAT_RGB_332 => Some(Self::Rgb332), _ => None, } } pub fn get_all() -> Vec { vec![ ColorFormat::Argb8888, + ColorFormat::Argb1555, ColorFormat::Rgb565, + ColorFormat::Rgb888, ColorFormat::Argb4444, + ColorFormat::Argb8332, ColorFormat::Gray8, + ColorFormat::Rgb332, ]} pub fn const_name(&self) -> &'static str { match self { ColorFormat::Argb8888 => "FORMAT_ARGB_8888", + ColorFormat::Argb1555 => "FORMAT_ARGB_1555", ColorFormat::Rgb565 => "FORMAT_RGB_565", + ColorFormat::Rgb888 => "FORMAT_RGB_888", ColorFormat::Argb4444 => "FORMAT_ARGB_4444", + ColorFormat::Argb8332 => "FORMAT_ARGB_8332", ColorFormat::Gray8 => "FORMAT_GRAY_8", + ColorFormat::Rgb332 => "FORMAT_RGB_332", } } pub fn bytes_per_pixel(&self) -> usize { match self { ColorFormat::Argb8888 => Argb8888::BYTES_PER_PIXEL, + ColorFormat::Argb1555 => Argb1555::BYTES_PER_PIXEL, ColorFormat::Rgb565 => Rgb565::BYTES_PER_PIXEL, + ColorFormat::Rgb888 => Rgb888::BYTES_PER_PIXEL, ColorFormat::Argb4444 => Argb4444::BYTES_PER_PIXEL, + ColorFormat::Argb8332 => Argb8332::BYTES_PER_PIXEL, ColorFormat::Gray8 => Gray8::BYTES_PER_PIXEL, + ColorFormat::Rgb332 => Rgb332::BYTES_PER_PIXEL, } } pub fn transcode_to_argb_8888(&self, bytes: &Rc>) -> Rc> { match self { ColorFormat::Argb8888 => Rc::clone(bytes), + ColorFormat::Argb1555 => Rc::new(Argb8888::encode(&Argb1555::decode(bytes))), ColorFormat::Rgb565 => Rc::new(Argb8888::encode(&Rgb565::decode(bytes))), + ColorFormat::Rgb888 => Rc::new(Argb8888::encode(&Rgb888::decode(bytes))), ColorFormat::Argb4444 => Rc::new(Argb8888::encode(&Argb4444::decode(bytes))), + ColorFormat::Argb8332 => Rc::new(Argb8888::encode(&Argb8332::decode(bytes))), ColorFormat::Gray8 => Rc::new(Argb8888::encode(&Gray8::decode(bytes))), + ColorFormat::Rgb332 => Rc::new(Rgb332::encode(&Rgb332::decode(bytes))), } } pub fn transcode_from_argb_8888(&self, bytes: &Rc>) -> Rc> { match self { ColorFormat::Argb8888 => Rc::clone(bytes), + ColorFormat::Argb1555 => Rc::new(Argb1555::encode(&Argb8888::decode(bytes))), ColorFormat::Rgb565 => Rc::new(Rgb565::encode(&Argb8888::decode(bytes))), + ColorFormat::Rgb888 => Rc::new(Rgb888::encode(&Argb8888::decode(bytes))), ColorFormat::Argb4444 => Rc::new(Argb4444::encode(&Argb8888::decode(bytes))), + ColorFormat::Argb8332 => Rc::new(Argb8332::encode(&Argb8888::decode(bytes))), ColorFormat::Gray8 => Rc::new(Gray8::encode(&Argb8888::decode(bytes))), + ColorFormat::Rgb332 => Rc::new(Rgb332::encode(&Argb8888::decode(bytes))), } } @@ -76,9 +108,13 @@ impl ColorFormat { // Slightly transparent magenta where possible // (if fully opaque, thcrap would overlay loaded images instead of overwriting the alpha channel) ColorFormat::Argb8888 => &[0xFF, 0xFF, 0x00, 0xFE], - ColorFormat::Argb4444 => &[0x0F, 0xEF], + ColorFormat::Argb1555 => &[0b000_11111, 0b1_11111_00], ColorFormat::Rgb565 => &[0b000_11111, 0b11111_000], + ColorFormat::Rgb888 => &[0xFF, 0x00, 0xFF], + ColorFormat::Argb4444 => &[0x0F, 0xEF], + ColorFormat::Argb8332 => &[0b111_000_11, 0xFE], ColorFormat::Gray8 => &[0x80], + ColorFormat::Rgb332 => &[0b111_000_11], } } } @@ -96,18 +132,34 @@ impl Components { #[derive(Debug, Copy, Clone, PartialEq, Eq)] struct Argb8888(u32); +/// Format which is the little-endian encoding of a 16-bit integer `0bA_RRRRR_GGGGG_BBBBB`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Argb1555(u16); + /// Format which is the little-endian encoding of a 16-bit integer `0bRRRRR_GGGGGG_BBBBB`. #[derive(Debug, Copy, Clone, PartialEq, Eq)] struct Rgb565(u16); +/// Format which is the little-endian encoding of a 24-bit integer `0xRGB`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Rgb888(u32); + /// Format which is the little-endian encoding of a 16-bit integer `0xARGB`. #[derive(Debug, Copy, Clone, PartialEq, Eq)] struct Argb4444(u16); +/// Format which is the little-endian encoding of a 16-bit integer `0bAAAAAAAA_RRR_GGG_BB`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Argb8332(u16); + /// Format which is a single-byte luminosity channel. #[derive(Debug, Copy, Clone, PartialEq, Eq)] struct Gray8(u8); +/// Format which is single byte encoding of a 8-bit integer `0bRRR_GGG_BB`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Rgb332(u8); + trait ColorBytes: Sized where @@ -157,6 +209,39 @@ impl ColorBytes for Argb8888 { fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u32(self.0) } } +impl From for Components { + fn from(color: Argb1555) -> Components { + let blue = (color.0 & 0x1F) as u8; + let green = ((color.0 >> 5) & 0x1F) as u8; + let red = ((color.0 >> 10) & 0x1F) as u8; + let alpha = ((color.0 >> 15) & 1) as u8; + Components { + blue: change_bit_depth::<5, 8>(blue), + green: change_bit_depth::<5, 8>(green), + red: change_bit_depth::<5, 8>(red), + alpha: change_bit_depth::<1, 8>(alpha), + } + } +} + +impl From for Argb1555 { + fn from(components: Components) -> Self { + let blue = (components.blue >> 3) as u16; + let green = (components.green >> 3) as u16; + let red = (components.red >> 3) as u16; + let alpha = (components.alpha >> 7) as u16; + + Argb1555((alpha << 15) + (red << 10) + (green << 5) + blue) + } +} + +impl ColorBytes for Argb1555 { + const BYTES_PER_PIXEL: usize = 2; + + fn read_color_bytes(mut r: R) -> Result { r.read_u16().map(Argb1555) } + fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u16(self.0) } +} + impl From for Components { fn from(color: Rgb565) -> Components { let blue = (color.0 & 0x1F) as u8; @@ -188,6 +273,50 @@ impl ColorBytes for Rgb565 { fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u16(self.0) } } +impl From for Components { + fn from(color: Rgb888) -> Components { + let blue = (color.0 & 0xFF) as u8; + let green = ((color.0 >> 8) & 0xFF) as u8; + let red = ((color.0 >> 16) & 0xFF) as u8; + Components { + blue, + green, + red, + alpha: 0xFF + } + } +} + +impl From for Rgb888 { + fn from(components: Components) -> Self { + let blue = components.blue as u32; + let green = components.green as u32; + let red = components.red as u32; + + Rgb888((red << 16) + (green << 8) + blue) + } +} + +impl ColorBytes for Rgb888 { + const BYTES_PER_PIXEL: usize = 3; + + fn read_color_bytes(mut r: R) -> Result { + let mut color = r.read_u8()? as u32; + color |= (r.read_u8()? as u32) << 8; + color |= (r.read_u8()? as u32) << 16; + Ok(Rgb888(color)) + } + fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { + let blue = (self.0 & 0xFF) as u8; + let green = ((self.0 >> 8) & 0xFF) as u8; + let red = ((self.0 >> 16) & 0xFF) as u8; + w.write_u8(blue)?; + w.write_u8(green)?; + w.write_u8(red)?; + Ok(()) + } +} + impl From for Components { fn from(color: Argb4444) -> Components { let blue = (color.0 & 0xF) as u8; @@ -221,6 +350,39 @@ impl ColorBytes for Argb4444 { fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u16(self.0) } } +impl From for Components { + fn from(color: Argb8332) -> Components { + let blue = (color.0 & 0x3) as u8; + let green = ((color.0 >> 2) & 0x7) as u8; + let red = ((color.0 >> 5) & 0x7) as u8; + let alpha = ((color.0 >> 8) & 0xFF) as u8; + Components { + blue: change_bit_depth::<2, 8>(blue), + green: change_bit_depth::<3, 8>(green), + red: change_bit_depth::<3, 8>(red), + alpha + } + } +} + +impl From for Argb8332 { + fn from(components: Components) -> Self { + let blue = (components.blue >> 6) as u16; + let green = (components.green >> 5) as u16; + let red = (components.red >> 5) as u16; + let alpha = components.alpha as u16; + + Argb8332((alpha << 8) + (red << 5) + (green << 2) + blue) + } +} + +impl ColorBytes for Argb8332 { + const BYTES_PER_PIXEL: usize = 2; + + fn read_color_bytes(mut r: R) -> Result { r.read_u16().map(Argb8332) } + fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u16(self.0) } +} + impl From for Components { fn from(Gray8(value): Gray8) -> Components { Components { blue: value, green: value, red: value, alpha: 0xFF } @@ -249,6 +411,37 @@ impl ColorBytes for Gray8 { fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u8(self.0) } } +impl From for Components { + fn from(color: Rgb332) -> Components { + let blue = (color.0 & 0x3) as u8; + let green = ((color.0 >> 2) & 0x7) as u8; + let red = ((color.0 >> 5) & 0x7) as u8; + Components { + blue: change_bit_depth::<2, 8>(blue), + green: change_bit_depth::<3, 8>(green), + red: change_bit_depth::<3, 8>(red), + alpha: 0xFF + } + } +} + +impl From for Rgb332 { + fn from(components: Components) -> Self { + let blue = (components.blue >> 6) as u8; + let green = (components.green >> 5) as u8; + let red = (components.red >> 5) as u8; + + Rgb332((red << 5) + (green << 2) + blue) + } +} + +impl ColorBytes for Rgb332 { + const BYTES_PER_PIXEL: usize = 1; + + fn read_color_bytes(mut r: R) -> Result { r.read_u8().map(Rgb332) } + fn write_color_bytes(&self, mut w: W) -> Result<(), W::Err> { w.write_u8(self.0) } +} + // take a color value that is N bits large and rescale it to M bits. #[inline(always)] fn change_bit_depth(x: u8) -> u8 { diff --git a/src/io.rs b/src/io.rs index 5f3b111..a8d238d 100644 --- a/src/io.rs +++ b/src/io.rs @@ -317,7 +317,10 @@ pub trait BinRead { fn read_u16(&mut self) -> Result { ReadBytesExt::read_u16::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } fn read_i32(&mut self) -> Result { ReadBytesExt::read_i32::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } fn read_u32(&mut self) -> Result { ReadBytesExt::read_u32::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } + //fn read_i64(&mut self) -> Result { ReadBytesExt::read_i64::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } + //fn read_u64(&mut self) -> Result { ReadBytesExt::read_u64::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } fn read_f32(&mut self) -> Result { ReadBytesExt::read_f32::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } + //fn read_f64(&mut self) -> Result { ReadBytesExt::read_f64::(self._bin_read_reader()).map_err(|e| self._bin_read_io_error(e)) } fn read_u32s(&mut self, count: usize) -> Result, Self::Err> { (0..count).map(|_| self.read_u32()).collect() } @@ -340,6 +343,9 @@ pub trait BinRead { fn read_f32s_3(&mut self) -> Result<[f32; 3], Self::Err> { Ok([self.read_f32()?, self.read_f32()?, self.read_f32()?]) } + fn read_f32s_5(&mut self) -> Result<[f32; 5], Self::Err> { + Ok([self.read_f32()?, self.read_f32()?, self.read_f32()?, self.read_f32()?, self.read_f32()?]) + } fn read_byte_vec(&mut self, len: usize) -> Result, Self::Err> { let mut buf = vec![0; len]; diff --git a/src/llir/abi.rs b/src/llir/abi.rs index 68957f0..0ef2562 100644 --- a/src/llir/abi.rs +++ b/src/llir/abi.rs @@ -72,6 +72,17 @@ pub enum ArgEncoding { mask: AcceleratingByteMask, furibug: bool, }, + /* + /// `g` in mapfile. Single typed argument + /// 'G' in mapfile. Double typed argument + TypedArg { + is_double: bool, + }, + /// `v` in mapfile. + Variadic { + pattern: Option> + }, + */ } #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] @@ -105,6 +116,7 @@ impl ArgEncoding { Self::Integer { size: 1, .. } => "byte-sized integer", Self::Integer { size: 2, .. } => "word-sized integer", Self::Integer { size: 4, .. } => "dword integer", + //Self::Integer { size: 8, .. } => "qword integer", Self::Integer { size: _, .. } => "integer", Self::JumpOffset => "jump offset", Self::JumpTime => "jump time", @@ -113,6 +125,8 @@ impl ArgEncoding { Self::Padding { size: _ } => "padding", Self::Float { .. } => "float", Self::String { .. } => "string", + //Self::TypedArg { .. } => "type cast argument", + //Self::Variadic { .. } => "variadic", } } @@ -134,6 +148,7 @@ impl ArgEncoding { Enc::Integer { ty_color: None, size: 1, .. } => write!(f, "byte-sized integer"), Enc::Integer { ty_color: None, size: 2, .. } => write!(f, "word-sized integer"), Enc::Integer { ty_color: None, size: 4, .. } => write!(f, "dword integer"), + //Enc::Integer { ty_color: None, size: 8, .. } => write!(f, "qword integer"), Enc::Integer { ty_color: None, size, .. } => write!(f, "{size}-byte integer"), enc => write!(f, "{}", enc.static_descr()), } @@ -159,6 +174,8 @@ impl ArgEncoding { | Self::Integer { immediate: false, .. } | Self::Float { immediate: false, .. } + //| Self::TypedArg { .. } + //| Self::Variadic { .. } => false, } } @@ -392,6 +409,9 @@ fn other_from_attrs(param: &abi_ast::Param, _emitter: &dyn Emitter) -> Result Ok(Some(ArgEncoding::JumpTime)), '_' => Ok(Some(ArgEncoding::Padding { size: 4 })), '-' => Ok(Some(ArgEncoding::Padding { size: 1 })), + //'g' => Ok(Some(ArgEncoding::TypedArg { is_double: false })), + //'G' => Ok(Some(ArgEncoding::TypedArg { is_double: true })), + //'v' => _ => Ok(None), } } From 3bdc5fa097b5987196c5b00da1025af447d4709f Mon Sep 17 00:00:00 2001 From: zero318 Date: Mon, 5 May 2025 03:32:13 -0400 Subject: [PATCH 23/26] First attempt at th20 support --- src/core_mapfiles/anm.rs | 6 +++--- src/core_mapfiles/ecl.rs | 10 +++++----- src/core_mapfiles/end.rs | 6 +++--- src/core_mapfiles/msg.rs | 6 +++--- src/core_mapfiles/std.rs | 6 +++--- src/formats/anm/mod.rs | 2 +- src/formats/anm/read_write.rs | 2 +- src/formats/msg.rs | 4 ++-- src/game.rs | 9 ++++++--- src/image/color.rs | 2 +- src/llir/abi.rs | 2 +- 11 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/core_mapfiles/anm.rs b/src/core_mapfiles/anm.rs index aa017a1..8bf2fdb 100644 --- a/src/core_mapfiles/anm.rs +++ b/src/core_mapfiles/anm.rs @@ -32,9 +32,9 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { OUT }, - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => { + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 | Th20 => { static OUT: &CoreSignatures = &CoreSignatures { - inherit: &[ANM_INS_13_19, ANM_VAR], + inherit: &[ANM_INS_13_20, ANM_VAR], ins: &[], var: &[], }; OUT @@ -328,7 +328,7 @@ static ANM_INS_095_128: &'static CoreSignatures = &CoreSignatures { }; // v8 -static ANM_INS_13_19: &CoreSignatures = &CoreSignatures { +static ANM_INS_13_20: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ // Section A diff --git a/src/core_mapfiles/ecl.rs b/src/core_mapfiles/ecl.rs index 793d045..a9fea59 100644 --- a/src/core_mapfiles/ecl.rs +++ b/src/core_mapfiles/ecl.rs @@ -16,7 +16,7 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { Th12 | Th125 => ECL_12, Th128 | - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => CoreSignatures::EMPTY, + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 | Th20 => CoreSignatures::EMPTY, } } @@ -25,7 +25,7 @@ pub(super) fn timeline_core_signatures(game: Game) -> &'static CoreSignatures { Th06 | Th07 | Th08 | Th09 | Th095 => TIMELINE, Th10 | Alcostg | Th11 | Th12 | Th125 | Th128 | - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => CoreSignatures::EMPTY, + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 | Th20 => CoreSignatures::EMPTY, } } @@ -1061,7 +1061,7 @@ static ECL_095: &'static CoreSignatures = &CoreSignatures { static ECL_10_11: &'static CoreSignatures = &CoreSignatures { - inherit: &[ECL_10_19_COMMON], + inherit: &[ECL_10_20_COMMON], ins: &[ // Section B (Th10, 256, Some(("P(bs=4)ffSSS", None))), @@ -1264,7 +1264,7 @@ static ECL_10_11: &'static CoreSignatures = &CoreSignatures { static ECL_12: &'static CoreSignatures = &CoreSignatures { - inherit: &[ECL_10_19_COMMON], + inherit: &[ECL_10_20_COMMON], ins: &[ // Section B (Th12, 256, Some(("P(bs=4)ffSSS", None))), @@ -1470,7 +1470,7 @@ static ECL_12: &'static CoreSignatures = &CoreSignatures { }; -static ECL_10_19_COMMON: &'static CoreSignatures = &CoreSignatures { +static ECL_10_20_COMMON: &'static CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th10, 0, Some(("", None))), diff --git a/src/core_mapfiles/end.rs b/src/core_mapfiles/end.rs index 889675f..ee7f614 100644 --- a/src/core_mapfiles/end.rs +++ b/src/core_mapfiles/end.rs @@ -10,8 +10,8 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { => END_06_09, | Th10 | Th11 | Th12 | Th128 | Th13 - | Th14 | Th15 | Th16 | Th17 | Th18 | Th19 - => END_10_19, + | Th14 | Th15 | Th16 | Th17 | Th18 | Th19 | Th20 + => END_10_20, } } @@ -29,7 +29,7 @@ static END_06_09: &CoreSignatures = &CoreSignatures { var: &[], }; -static END_10_19: &CoreSignatures = &CoreSignatures { +static END_10_20: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th10, 0, Some(("", None))), diff --git a/src/core_mapfiles/msg.rs b/src/core_mapfiles/msg.rs index a166cd5..76d8052 100644 --- a/src/core_mapfiles/msg.rs +++ b/src/core_mapfiles/msg.rs @@ -10,8 +10,8 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { => MSG_06_09, | Th10 | Th11 | Th12 | Th125 | Th128 | Th13 - | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 - => MSG_10_19, + | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 | Th20 + => MSG_10_20, } } @@ -73,7 +73,7 @@ static MSG_06_09: &CoreSignatures = &CoreSignatures { ], var: &[], }; -static MSG_10_19: &CoreSignatures = &CoreSignatures { +static MSG_10_20: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th10, 0, Some(("", None))), diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index 2127811..f5db06f 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -11,8 +11,8 @@ pub(super) fn core_signatures(game: Game) -> &'static CoreSignatures { => STD_07_09, | Th095 | Th10 | Alcostg | Th11 | Th12 | Th125 | Th128 - | Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 - => STD_095_19 + | Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 | Th20 + => STD_095_20 } } @@ -72,7 +72,7 @@ static STD_07_09: &CoreSignatures = &CoreSignatures { var: &[], }; -static STD_095_19: &CoreSignatures = &CoreSignatures { +static STD_095_20: &CoreSignatures = &CoreSignatures { inherit: &[], ins: &[ (Th095, 0, Some(("", None))), diff --git a/src/formats/anm/mod.rs b/src/formats/anm/mod.rs index 6783265..ebd5ba9 100644 --- a/src/formats/anm/mod.rs +++ b/src/formats/anm/mod.rs @@ -1214,7 +1214,7 @@ impl Version { Th08 | Th09 => Version::V3, Th095 | Th10 | Alcostg => Version::V4, Th11 | Th12 | Th125 | Th128 => Version::V7, - Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 => Version::V8, + Th13 | Th14 | Th143 | Th15 | Th16 | Th165 | Th17 | Th18 | Th185 | Th19 | Th20 => Version::V8, } } diff --git a/src/formats/anm/read_write.rs b/src/formats/anm/read_write.rs index 4ee520d..972a2e0 100644 --- a/src/formats/anm/read_write.rs +++ b/src/formats/anm/read_write.rs @@ -425,7 +425,7 @@ impl FileFormat { } fn has_extended_sprites(&self) -> bool { - self.game == Game::Th19 + self.game >= Game::Th19 } fn read_header(&self, f: &mut BinReader, emitter: &dyn Emitter) -> ReadResult { diff --git a/src/formats/msg.rs b/src/formats/msg.rs index e07fb2f..cb77b19 100644 --- a/src/formats/msg.rs +++ b/src/formats/msg.rs @@ -652,7 +652,7 @@ impl FileFormat { } fn extended_header(&self) -> bool { - self.language == LanguageKey::Msg && self.game == Game::Th19 + self.language == LanguageKey::Msg && self.game >= Game::Th19 } fn language_hooks(&self) -> Box { @@ -663,7 +663,7 @@ impl FileFormat { | Game::Th13 | Game::Th14 | Game::Th143 | Game::Th15 | Game::Th16 | Game::Th165 | Game::Th17 | Game::Th18 | Game::Th185 - | Game::Th19 + | Game::Th19 | Game::Th20 => Box::new(MsgHooks { language: self.language }), | Game::Th095 | Game::Alcostg diff --git a/src/game.rs b/src/game.rs index b3d91be..55078cb 100644 --- a/src/game.rs +++ b/src/game.rs @@ -6,9 +6,9 @@ use crate::diagnostic::Diagnostic; pub enum Game { Th06, Th07, Th08, Th09, Th095, Th10, Alcostg, Th11, Th12, Th125, Th128, Th13, Th14, Th143, Th15, Th16, Th165, Th17, Th18, - Th185, Th19 + Th185, Th19, Th20 } -macro_rules! max_game_str { () => { "th19" }; } +macro_rules! max_game_str { () => { "th20" }; } impl std::str::FromStr for Game { type Err = Diagnostic; @@ -49,6 +49,7 @@ impl std::str::FromStr for Game { 18 => Ok(Game::Th18), 185 => Ok(Game::Th185), 19 => Ok(Game::Th19), + 20 => Ok(Game::Th20), _ => Err(unknown_game()), } } @@ -78,6 +79,7 @@ impl Game { Game::Th18 => "UM", Game::Th185 => "HBM", Game::Th19 => "UDoALG", + Game::Th20 => "FW", } } @@ -104,7 +106,7 @@ impl Game { Game::Th18 => "th18", Game::Th185 => "th185", Game::Th19 => "th19", - + Game::Th20 => "th20", } } @@ -131,6 +133,7 @@ impl Game { Game::Th18 => 18, Game::Th185 => 185, Game::Th19 => 19, + Game::Th20 => 20, } } } diff --git a/src/image/color.rs b/src/image/color.rs index 58043dd..e11deec 100644 --- a/src/image/color.rs +++ b/src/image/color.rs @@ -86,7 +86,7 @@ impl ColorFormat { ColorFormat::Argb4444 => Rc::new(Argb8888::encode(&Argb4444::decode(bytes))), ColorFormat::Argb8332 => Rc::new(Argb8888::encode(&Argb8332::decode(bytes))), ColorFormat::Gray8 => Rc::new(Argb8888::encode(&Gray8::decode(bytes))), - ColorFormat::Rgb332 => Rc::new(Rgb332::encode(&Rgb332::decode(bytes))), + ColorFormat::Rgb332 => Rc::new(Argb8888::encode(&Rgb332::decode(bytes))), } } diff --git a/src/llir/abi.rs b/src/llir/abi.rs index 0ef2562..6d63b7c 100644 --- a/src/llir/abi.rs +++ b/src/llir/abi.rs @@ -48,7 +48,7 @@ pub enum ArgEncoding { arg0: bool, immediate: bool, extend: bool, - format: ast::IntFormat + format: ast::IntFormat, }, /// `o` in mapfile. Max of one per instruction. Is decoded to a label. JumpOffset, From e9c3d28fa2e37cdef56d24c0002d14cd416281a7 Mon Sep 17 00:00:00 2001 From: Khang Date: Mon, 5 May 2025 04:48:37 -0400 Subject: [PATCH 24/26] Fix th20 std support --- src/formats/std.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/formats/std.rs b/src/formats/std.rs index 55e9ff8..4dc86a9 100644 --- a/src/formats/std.rs +++ b/src/formats/std.rs @@ -116,6 +116,7 @@ pub struct Object { pub id: Option, pub pos: [f32; 3], pub size: [f32; 3], + pub unk: Option, pub quads: Vec, } @@ -126,6 +127,7 @@ impl FromMeta<'_> for Object { id: m.get_field("id")?, pos: m.expect_field("pos")?, size: m.expect_field("size")?, + unk: m.get_field("unk")?, quads: m.expect_field("quads")?, })) } @@ -140,6 +142,9 @@ impl ToMeta for Object { builder.field("layer", &(self.layer as i32)); builder.field("pos", &self.pos); builder.field("size", &self.size); + if let Some(unk) = &self.unk { + builder.field("unk", unk); + } builder.field("quads", &self.quads); builder.build() @@ -399,7 +404,7 @@ fn read_std(reader: &mut BinReader, emitter: &impl Emitter, format: &dyn FileFor let expected_id = i; let value = emitter.chain_with(|f| write!(f, "object at index {i}"), |emitter| { - read_object(reader, emitter, expected_id) + read_object(reader, emitter, format, expected_id) })?; Ok((key, value)) }).collect::>>()?; @@ -487,7 +492,7 @@ fn write_string_128>(f: &mut BinWriter, emitter: &dyn Emitter, s: Ok(()) } -fn read_object(f: &mut BinReader, emitter: &impl Emitter, expected_id: usize) -> ReadResult { +fn read_object(f: &mut BinReader, emitter: &impl Emitter, format: &dyn FileFormat, expected_id: usize) -> ReadResult { let id = f.read_u16()?; if id as usize != expected_id { emitter.emit(warning!("object has non-sequential id (expected {expected_id}, got {id})")).ignore(); @@ -496,6 +501,11 @@ fn read_object(f: &mut BinReader, emitter: &impl Emitter, expected_id: usize) -> let layer = f.read_u16()?; let pos = f.read_f32s_3()?; let size = f.read_f32s_3()?; + let unk = if format.has_obj_unk() { + Some(f.read_f32()?) + } else { + None + }; let mut quads = vec![]; while let Some(quad) = read_quad(f, emitter)? { quads.push(quad); @@ -509,6 +519,7 @@ fn read_object(f: &mut BinReader, emitter: &impl Emitter, expected_id: usize) -> }, pos, size, + unk, quads }) } @@ -518,6 +529,9 @@ fn write_object(f: &mut BinWriter, emitter: &impl Emitter, format: &dyn FileForm f.write_u16(x.layer)?; f.write_f32s(&x.pos)?; f.write_f32s(&x.size)?; + if let Some(unk) = x.unk { + f.write_f32(unk)?; + } for quad in &x.quads { write_quad(f, emitter, format, quad)?; } @@ -629,7 +643,7 @@ fn write_terminal_instance(f: &mut BinWriter) -> WriteResult { fn game_format(game: Game) -> Box { if Game::Th095 <= game { let hooks = StdHooks10; - Box::new(FileFormat10 { hooks }) + Box::new(FileFormat10 { hooks, game }) } else { let has_strips = match game { Game::Th06 | Game::Th07 => false, @@ -652,6 +666,7 @@ struct FileFormat06 { /// STD format, StB to present. struct FileFormat10 { hooks: StdHooks10, + game: Game, } trait FileFormat { @@ -661,6 +676,7 @@ trait FileFormat { fn write_extra(&self, f: &mut BinWriter, emitter: &dyn Emitter, x: &StdExtra) -> WriteResult; fn language_hooks(&self) -> &dyn LanguageHooks; fn has_strips(&self) -> bool; + fn has_obj_unk(&self) -> bool; } impl FileFormat for FileFormat06 { @@ -709,6 +725,7 @@ impl FileFormat for FileFormat06 { fn language_hooks(&self) -> &dyn LanguageHooks { &self.hooks } fn has_strips(&self) -> bool { self.has_strips } + fn has_obj_unk(&self) -> bool { false } } impl FileFormat for FileFormat10 { @@ -739,6 +756,7 @@ impl FileFormat for FileFormat10 { fn language_hooks(&self) -> &dyn LanguageHooks { &self.hooks } fn has_strips(&self) -> bool { false } + fn has_obj_unk(&self) -> bool { self.game >= Game::Th20 } } struct StdHooks06; From 471b51d67a2d236949bb7a89114c1e65905c75bf Mon Sep 17 00:00:00 2001 From: Khang Date: Mon, 25 Aug 2025 15:40:52 -0400 Subject: [PATCH 25/26] Fix th20 std support (again) --- src/formats/std.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/formats/std.rs b/src/formats/std.rs index 4dc86a9..6103971 100644 --- a/src/formats/std.rs +++ b/src/formats/std.rs @@ -116,7 +116,7 @@ pub struct Object { pub id: Option, pub pos: [f32; 3], pub size: [f32; 3], - pub unk: Option, + pub unk: Option<[f32; 5]>, pub quads: Vec, } @@ -502,7 +502,7 @@ fn read_object(f: &mut BinReader, emitter: &impl Emitter, format: &dyn FileForma let pos = f.read_f32s_3()?; let size = f.read_f32s_3()?; let unk = if format.has_obj_unk() { - Some(f.read_f32()?) + Some(f.read_f32s_5()?) } else { None }; @@ -530,7 +530,7 @@ fn write_object(f: &mut BinWriter, emitter: &impl Emitter, format: &dyn FileForm f.write_f32s(&x.pos)?; f.write_f32s(&x.size)?; if let Some(unk) = x.unk { - f.write_f32(unk)?; + f.write_f32s(&unk)?; } for quad in &x.quads { write_quad(f, emitter, format, quad)?; From 1a5964ed2e2d87238d3f3033c176bc84d8bf28c9 Mon Sep 17 00:00:00 2001 From: zero318 Date: Mon, 25 Aug 2025 19:55:46 -0400 Subject: [PATCH 26/26] Fix more STD/MSG/END stuff for th20 --- src/core_mapfiles/end.rs | 3 +++ src/core_mapfiles/msg.rs | 22 ++++++++++++++++++++++ src/core_mapfiles/std.rs | 2 ++ src/formats/msg.rs | 6 +++--- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/core_mapfiles/end.rs b/src/core_mapfiles/end.rs index ee7f614..cd97ae5 100644 --- a/src/core_mapfiles/end.rs +++ b/src/core_mapfiles/end.rs @@ -50,6 +50,9 @@ static END_10_20: &CoreSignatures = &CoreSignatures { (Th10, 15, Some(("SSN", None))), (Th10, 16, Some(("SSN", None))), (Th10, 17, Some(("SSN", None))), + + (Th20, 3, Some(("m(bs=4;mask=0x77,7,16;furibug)", None))), + (Th20, 9, Some(("CC", None))), ], var: &[], }; diff --git a/src/core_mapfiles/msg.rs b/src/core_mapfiles/msg.rs index 76d8052..a203364 100644 --- a/src/core_mapfiles/msg.rs +++ b/src/core_mapfiles/msg.rs @@ -187,6 +187,28 @@ static MSG_10_20: &CoreSignatures = &CoreSignatures { (Th19, 54, Some(("", None))), (Th19, 55, Some(("", None))), (Th19, 56, Some(("", None))), + + (Th20, 19, Some(("", None))), + (Th20, 37, None), + (Th20, 38, None), + (Th20, 39, None), + (Th20, 40, None), + (Th20, 41, None), + (Th20, 42, None), + (Th20, 43, None), + (Th20, 44, None), + (Th20, 45, None), + (Th20, 46, None), + (Th20, 47, None), + (Th20, 48, None), + (Th20, 49, None), + (Th20, 50, None), + (Th20, 51, None), + (Th20, 52, None), + (Th20, 53, None), + (Th20, 54, None), + (Th20, 55, None), + (Th20, 56, None), ], var: &[], }; diff --git a/src/core_mapfiles/std.rs b/src/core_mapfiles/std.rs index f5db06f..c56f617 100644 --- a/src/core_mapfiles/std.rs +++ b/src/core_mapfiles/std.rs @@ -108,6 +108,8 @@ static STD_095_20: &CoreSignatures = &CoreSignatures { (Th14, 20, Some(("f", None))), (Th17, 21, Some(("SSf", None))), + + (Th20, 22, Some(("S", None))), ], var: &[], }; diff --git a/src/formats/msg.rs b/src/formats/msg.rs index cb77b19..5b17624 100644 --- a/src/formats/msg.rs +++ b/src/formats/msg.rs @@ -616,13 +616,13 @@ fn write_msg( fn game_format(game: Game, language: LanguageKey, emitter: &RootEmitter) -> Result { match (game, language) { | (Game::Th095, LanguageKey::Msg) - | (Game::Th095, LanguageKey::End) => Err(emitter.emit(error!("{} does not have MSG files; maybe try 'trumsg --mission'?", game))), | (Game::Alcostg, LanguageKey::Msg) - | (Game::Alcostg, LanguageKey::End) => Err(emitter.emit(error!("{} does not have MSG files", game))), + | (Game::Th095, LanguageKey::End) + | (Game::Alcostg, LanguageKey::End) | (Game::Th125, LanguageKey::End) | (Game::Th143, LanguageKey::End) | (Game::Th165, LanguageKey::End) @@ -652,7 +652,7 @@ impl FileFormat { } fn extended_header(&self) -> bool { - self.language == LanguageKey::Msg && self.game >= Game::Th19 + self.language == LanguageKey::Msg && self.game == Game::Th19 } fn language_hooks(&self) -> Box {