From 282529a93335fa771e755f088250dad4fe3b2eae Mon Sep 17 00:00:00 2001 From: Romain Giot Date: Sat, 19 Aug 2023 15:59:14 +0200 Subject: [PATCH] [cpclib-asm] Fix a crash when handling BANK directive --- cpclib-asm/basm_doc.md | 2 ++ cpclib-asm/src/assembler/mod.rs | 33 ++++++++++++++++----- cpclib-asm/src/assembler/page_info.rs | 2 +- cpclib-asm/src/implementation/expression.rs | 2 +- cpclib-basm/tests/asm/good_bank.asm | 31 +++++++++++++++++++ cpclib-basm/tests/asm/good_write_direct.asm | 30 +++++++++++++++++++ 6 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 cpclib-basm/tests/asm/good_bank.asm create mode 100644 cpclib-basm/tests/asm/good_write_direct.asm diff --git a/cpclib-asm/basm_doc.md b/cpclib-asm/basm_doc.md index 9fb9e0aa..7ed7494d 100644 --- a/cpclib-asm/basm_doc.md +++ b/cpclib-asm/basm_doc.md @@ -92,6 +92,8 @@ On the code space ($), not physical space ($$) When used with no argument, a bank corresponds to a memory area outside of the snapshot. All things read&write in memory are thus uncorrelated to the snapshot. Sections do not apply in a bank. +`BANK page` is similar to `WRITE DIRECT -1 -1 page` + ## Labels related ## = diff --git a/cpclib-asm/src/assembler/mod.rs b/cpclib-asm/src/assembler/mod.rs index aac921ba..90e3b27e 100644 --- a/cpclib-asm/src/assembler/mod.rs +++ b/cpclib-asm/src/assembler/mod.rs @@ -1126,6 +1126,17 @@ impl Env { } } + fn page_info_for_logical_address_mut(&mut self, address: u16) -> &mut PageInformation { + match &self.selected_bank { + Some(idx) => &mut self.banks[*idx].1, // TODO check if this code is valid + None => { + let active_page = + self.logical_to_physical_address(address).page() as usize; + &mut self.pages_info_sna[active_page] + } + } + } + fn written_bytes(&mut self) -> &mut BitVec { match &self.selected_bank { Some(idx) => &mut self.banks[*idx].2, @@ -1865,12 +1876,15 @@ impl Env { Some(exp) => { // prefix provided, we explicitely want one configuration let mmr = self.resolve_expr_must_never_fail(exp)?.int()?; + if mmr < 0xC0 || mmr > 0xC7 { return Err(AssemblerError::MMRError { value: mmr }); } let mmr = mmr as u8; self.ga_mmr = mmr; + + // we do not change the output address (there is no reason to do that) } None => { // nothing provided, we write in a temporary area @@ -3815,6 +3829,7 @@ pub fn assemble_opcode( } fn visit_org(address: &Expr, address2: Option<&Expr>, env: &mut Env) -> Result<(), AssemblerError> { + // org $ set org to the output address (cf. rasm) let code_adr = if address2.is_none() && address == &"$".into() { if env.start_address().is_none() { @@ -3836,18 +3851,21 @@ fn visit_org(address: &Expr, address2: Option<&Expr>, env: &mut Env) -> Result<( }; // TODO Check overlapping region - let page_info = env.active_page_info_mut(); - page_info.logical_outputadr = output_adr as _; - page_info.logical_codeadr = code_adr as _; - page_info.fail_next_write_if_zero = false; + { + let page_info = env.page_info_for_logical_address_mut(output_adr as _); + page_info.logical_outputadr = output_adr as _; + page_info.logical_codeadr = code_adr as _; + page_info.fail_next_write_if_zero = false; + } // Specify start address at first use - env.active_page_info_mut().startadr = match env.start_address() { + env.page_info_for_logical_address_mut(output_adr as _).startadr = match env.start_address() { Some(val) => val.min(env.logical_output_address()), None => env.logical_output_address() } .into(); + env.output_address = output_adr as _; env.update_dollar(); @@ -3865,9 +3883,10 @@ fn visit_org(address: &Expr, address2: Option<&Expr>, env: &mut Env) -> Result<( file: file!(), line: line!(), msg: format!( - "BUG in assembler:{}!= {}", + "BUG in assembler: 0x{:x}!=0x{:x} in pass {:?}", env.logical_output_address(), - env.logical_output_address() + env.output_address, + env.pass ) }); } diff --git a/cpclib-asm/src/assembler/page_info.rs b/cpclib-asm/src/assembler/page_info.rs index 7690b24f..4a6e962b 100644 --- a/cpclib-asm/src/assembler/page_info.rs +++ b/cpclib-asm/src/assembler/page_info.rs @@ -11,7 +11,7 @@ pub type ProtectedArea = std::ops::RangeInclusive; /// A stock CPC 6128 is composed of two pages #[derive(Debug, Clone)] pub struct PageInformation { - /// Start adr to use to write binary files. No use when working with snapshots. + /// Start adr to use to write binary files. Not use when working with snapshots. pub(crate) startadr: Option, /// maximum address reached when working with 64k data pub(crate) maxadr: u16, diff --git a/cpclib-asm/src/implementation/expression.rs b/cpclib-asm/src/implementation/expression.rs index 30d9e975..1d4fd06c 100644 --- a/cpclib-asm/src/implementation/expression.rs +++ b/cpclib-asm/src/implementation/expression.rs @@ -80,7 +80,7 @@ impl<'a, E:ExprEvaluationExt> ExprEvaluationExt for UnaryFunctionWrapper<'a,E> { if arg < 0.into() || arg > 0xFFFF.into() { return Err(AssemblerError::ExpressionError(ExpressionError::OwnError( Box::new(AssemblerError::AssemblingError { - msg: format!("Impossible to read memory address {}", arg) + msg: format!("Impossible to read memory address 0x{:X}", arg) }) ))); } diff --git a/cpclib-basm/tests/asm/good_bank.asm b/cpclib-basm/tests/asm/good_bank.asm new file mode 100644 index 00000000..55be5f9d --- /dev/null +++ b/cpclib-basm/tests/asm/good_bank.asm @@ -0,0 +1,31 @@ + ; Set up a unique value in various banks + BANK 0xc0 + org 0x4000 + 0 + db 0xc0 + + BANK 0xc4 + org 0x4000 + 1 + db 0xc4 + + + BANK 0xc5 + org 0x4000 + 2 + db 0xc5 + + BANK 0xc6 + org 0x4000 + 3 + db 0xc6 + + + BANK 0xc7 + org 0x4000 + 4 + db 0xc7 + + + BANKSET 0 + assert memory(0x4000 + 0) == 0xC0 + + BANKSET 1 + assert memory(0x4000 + 2) == 0xC5 + assert memory(0x8000 + 3) == 0xC6 + assert memory(0xC000 + 4) == 0xC7 \ No newline at end of file diff --git a/cpclib-basm/tests/asm/good_write_direct.asm b/cpclib-basm/tests/asm/good_write_direct.asm new file mode 100644 index 00000000..e518a7b0 --- /dev/null +++ b/cpclib-basm/tests/asm/good_write_direct.asm @@ -0,0 +1,30 @@ + WRITE DIRECT -1, -1, 0xc0 + org 0x4000+0 + db 0xc0 + + WRITE DIRECT -1, -1, 0xc4 + org 0x4000+1 + db 0xc4 + + + WRITE DIRECT -1, -1, 0xc5 + org 0x4000+2 + db 0xc5 + + WRITE DIRECT -1, -1, 0xc6 + org 0x4000+3 + db 0xc6 + + + WRITE DIRECT -1, -1, 0xc7 + org 0x4000+4 + db 0xc7 + + + BANKSET 0 + assert memory(0x4000 + 0) == 0xC0 + + BANKSET 1 + assert memory(0x4000 + 2) == 0xC5 + assert memory(0x8000 + 3) == 0xC6 + assert memory(0xC000 + 4) == 0xC7 \ No newline at end of file