1pub mod control;
2pub mod delayed_command;
3pub mod file;
4pub mod function;
5pub mod list;
6pub mod listing_output;
7pub mod r#macro;
8pub mod matrix;
9pub mod page_info;
10pub mod report;
11pub mod save_command;
12pub mod section;
13pub mod stable_ticker;
14pub mod string;
15pub mod support;
16pub mod symbols_output;
17
18pub mod embedded;
19pub mod processed_token;
20
21use std::borrow::BorrowMut;
22use std::collections::{BTreeMap, HashMap, HashSet};
23use std::fmt;
24use std::fmt::{Debug, Display};
25use std::io::Write;
26use std::ops::{Deref, Neg};
27use std::sync::{Arc, RwLock};
28use std::time::Instant;
29
30use cpclib_basic::*;
31use cpclib_common::bitvec::prelude::BitVec;
32use cpclib_common::camino::{Utf8Path, Utf8PathBuf};
33use cpclib_common::chars::{Charset, char_to_amscii};
34use cpclib_common::event::EventObserver;
35use cpclib_common::itertools::Itertools;
36use cpclib_common::smallvec::SmallVec;
37use cpclib_common::smol_str::SmolStr;
38use cpclib_common::winnow::stream::UpdateSlice;
39use cpclib_disc::built_info;
40use cpclib_files::{FileType, StorageSupport};
41use cpclib_sna::*;
42use cpclib_tokens::ToSimpleToken;
43use file::AnyFileNameOwned;
44use processed_token::build_processed_token;
45use support::banks::DecoratedPages;
46use support::cpr::CprAssembler;
47use support::sna::SnaAssembler;
48#[cfg(all(not(target_arch = "wasm32"), feature = "rayon"))]
49use {cpclib_common::rayon::prelude::*, rayon_cond::CondIterator};
50
51use self::control::ControlOutputStore;
52use self::function::{Function, FunctionBuilder, HardCodedFunction};
53use self::listing_output::*;
54use self::processed_token::ProcessedToken;
55use self::report::SavedFile;
56use self::string::PreprocessedFormattedString;
57use self::symbols_output::{SymbolOutputFormat, SymbolOutputGenerator};
58use crate::assembler::processed_token::visit_processed_tokens;
59use crate::delayed_command::*;
60use crate::page_info::PageInformation;
61use crate::preamble::*;
62#[cfg(not(target_arch = "wasm32"))]
63use crate::progress::Progress;
64use crate::report::Report;
65use crate::save_command::*;
66use crate::section::Section;
67use crate::stable_ticker::*;
68use crate::{AssemblingOptions, MemoryPhysicalAddress};
69
70#[derive(Clone, Copy, PartialEq)]
71enum OutputKind {
72 Snapshot,
73 Cpr,
74 FreeBank
75}
76
77const MAX_SIZE: usize = 4;
79const MMR_PAGES_SELECTION: [u8; 9] = [
80 0xC0,
81 0b1100_0001,
82 0b1100_1001,
83 0b1101_0001,
84 0b1101_1001,
85 0b1110_0001,
86 0b1110_1001,
87 0b1111_0001,
88 0b1111_1001
89];
90
91#[allow(missing_docs)]
92pub type Bytes = SmallVec<[u8; MAX_SIZE]>;
93
94#[derive(Clone, Debug)]
95pub struct EnvOptions {
96 parse: ParserOptions,
97 assemble: AssemblingOptions,
98 observer: Arc<dyn EnvEventObserver>
99}
100
101impl Default for EnvOptions {
102 fn default() -> Self {
103 Self {
104 parse: Default::default(),
105 assemble: Default::default(),
106 observer: Arc::new(())
107 }
108 }
109}
110
111impl From<AssemblingOptions> for EnvOptions {
112 fn from(ass: AssemblingOptions) -> EnvOptions {
113 let mut opt = Self::default();
114 opt.assemble = ass;
115 opt
116 }
117}
118
119impl EnvOptions {
120 delegate::delegate! {
121 to self.parse {
122 pub fn context_builder(self) -> ParserContextBuilder;
123 }
124
125 to self.assemble {
126 pub fn case_sensitive(&self) -> bool;
127 pub fn symbols(&self) -> &cpclib_tokens::symbols::SymbolsTable;
128 pub fn symbols_mut(&mut self) -> &mut cpclib_tokens::symbols::SymbolsTable;
129 pub fn save_behavior(&self) -> cpclib_disc::amsdos::AmsdosAddBehavior;
130
131 pub fn write_listing_output<W: 'static + Write + Send + Sync>(
132 &mut self,
133 writer: W
134 ) -> &mut AssemblingOptions;
135
136 }
137 }
138
139 pub fn new(
140 parse: ParserOptions,
141 assemble: AssemblingOptions,
142 observer: Arc<dyn EnvEventObserver>
143 ) -> Self {
144 Self {
145 parse,
146 assemble,
147 observer
148 }
149 }
150
151 pub fn parse_options(&self) -> &ParserOptions {
152 &self.parse
153 }
154
155 pub fn assemble_options(&self) -> &AssemblingOptions {
156 &self.assemble
157 }
158
159 #[cfg(not(target_arch = "wasm32"))]
160 pub fn show_progress(&self) -> bool {
161 self.parse.show_progress
162 }
163
164 #[cfg(target_arch = "wasm32")]
165 pub fn show_progress(&self) -> bool {
166 false
167 }
168}
169
170fn add_index(m: &mut Bytes, idx: i32) -> Result<(), AssemblerError> {
172 if !(-128..=127).contains(&idx) {
174 eprintln!("Index error {}", idx);
176 }
177 let val = (idx & 0xFF) as u8;
178 add_byte(m, val);
179 Ok(())
180}
181
182fn add_byte(m: &mut Bytes, b: u8) {
183 m.push(b);
184}
185
186fn add_word(m: &mut Bytes, w: u16) {
187 m.push((w % 256) as u8);
188 m.push((w / 256) as u8);
189}
190
191fn add_index_register_code(m: &mut Bytes, r: IndexRegister16) {
192 add_byte(m, indexed_register16_to_code(r));
193}
194
195const DD: u8 = 0xDD;
196const FD: u8 = 0xFD;
197
198pub trait MyDefault {
199 fn default() -> Self;
200}
201
202#[derive(Clone, Copy, Debug, PartialEq, Eq)]
208pub enum AssemblingPass {
209 Uninitialized,
210 FirstPass,
211 SecondPass, Finished,
213 ListingPass }
215impl fmt::Display for AssemblingPass {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 let content = match self {
218 AssemblingPass::Uninitialized => "Uninitialized",
219 AssemblingPass::FirstPass => "1",
220 AssemblingPass::SecondPass => "2",
221 AssemblingPass::Finished => "Finished",
222 AssemblingPass::ListingPass => "Listing"
223 };
224 write!(f, "{}", content)
225 }
226}
227
228#[allow(missing_docs)]
229#[allow(unused)]
230impl AssemblingPass {
231 fn is_uninitialized(self) -> bool {
232 match self {
233 AssemblingPass::Uninitialized => true,
234 _ => false
235 }
236 }
237
238 pub fn is_finished(self) -> bool {
239 match self {
240 AssemblingPass::Finished => true,
241 _ => false
242 }
243 }
244
245 pub fn is_first_pass(self) -> bool {
246 match self {
247 AssemblingPass::FirstPass => true,
248 _ => false
249 }
250 }
251
252 pub fn is_second_pass(self) -> bool {
253 match self {
254 AssemblingPass::SecondPass => true,
255 _ => false
256 }
257 }
258
259 pub fn is_listing_pass(self) -> bool {
260 match self {
261 AssemblingPass::ListingPass => true,
262 _ => false
263 }
264 }
265
266 fn next_pass(self) -> Self {
267 match self {
268 AssemblingPass::Uninitialized => AssemblingPass::FirstPass,
269 AssemblingPass::FirstPass => AssemblingPass::SecondPass,
270 AssemblingPass::SecondPass => AssemblingPass::Finished,
271 AssemblingPass::Finished | AssemblingPass::ListingPass => panic!()
272 }
273 }
274}
275
276pub trait Visited {
279 fn visited(&self, env: &mut Env) -> Result<(), AssemblerError>;
281}
282
283impl Visited for Token {
284 fn visited(&self, env: &mut Env) -> Result<(), AssemblerError> {
285 visit_token(self, env)
286 }
287}
288
289impl Visited for LocatedToken {
290 fn visited(&self, env: &mut Env) -> Result<(), AssemblerError> {
291 visit_located_token(self, env).map_err(|e| e.locate(self.span().clone()))
293 }
294}
295
296type AssemblerWarning = AssemblerError;
297
298#[derive(Clone)]
300struct CrunchedSectionState {
301 crunched_section_start: Option<Z80Span>
305}
306
307impl CrunchedSectionState {
308 pub fn new(span: Option<Z80Span>) -> Self {
309 CrunchedSectionState {
310 crunched_section_start: span
311 }
312 }
313}
314
315#[derive(Clone)]
316pub struct CharsetEncoding {
317 lut: std::collections::HashMap<char, i32>
318}
319
320impl Default for CharsetEncoding {
321 fn default() -> Self {
322 Self::new()
323 }
324}
325
326impl CharsetEncoding {
327 pub fn new() -> Self {
328 let mut enc = Self {
329 lut: Default::default()
330 };
331 enc.reset();
332 enc
333 }
334
335 pub fn reset(&mut self) {
336 self.lut.clear()
337 }
338
339 pub fn update(&mut self, spec: &CharsetFormat, env: &mut Env) -> Result<(), AssemblerError> {
340 match spec {
341 CharsetFormat::Reset => self.reset(),
342 CharsetFormat::CharsList(l, s) => {
343 let mut s = env.resolve_expr_must_never_fail(s)?.int()?;
344 for c in l.iter() {
345 self.lut.insert(*c, s);
346 s += 1;
347 }
348 },
349 CharsetFormat::Char(c, i) => {
350 let c = env.resolve_expr_must_never_fail(c)?.char()?;
351 let i = env.resolve_expr_must_never_fail(i)?.int()?;
352 self.lut.insert(c, i);
353 },
354 CharsetFormat::Interval(a, b, s) => {
355 let a = env.resolve_expr_must_never_fail(a)?.char()?;
356 let b = env.resolve_expr_must_never_fail(b)?.char()?;
357 let mut s = env.resolve_expr_must_never_fail(s)?.int()?;
358 for c in a..=b {
359 self.lut.insert(c, s);
360 s += 1;
361 }
362 }
363 }
364
365 Ok(())
366 }
367
368 pub fn transform_char(&self, c: char) -> u8 {
369 self.lut
370 .get(&c)
371 .cloned()
372 .unwrap_or_else(|| char_to_amscii(c, Charset::English).unwrap_or(c as _) as i32)
373 as _
374 }
375
376 pub fn transform_string(&self, s: &str) -> Vec<u8> {
377 s.chars().map(|c| self.transform_char(c)).collect_vec()
378 }
379}
380
381pub trait EnvEventObserver: EventObserver {}
382
383impl<T> EnvEventObserver for T where T: EventObserver {}
384
385#[allow(missing_docs)]
387pub struct Env {
388 lookup_directory_stack: Vec<Utf8PathBuf>,
390
391 pass: AssemblingPass,
393 options: EnvOptions,
394 real_nb_passes: usize,
395 can_skip_next_passes: RwLock<bool>,
398 request_additional_pass: RwLock<bool>,
400 requested_additional_pass: bool,
402
403 crunched_section_state: Option<CrunchedSectionState>,
405
406 stable_counters: StableTickerCounters,
408
409 ga_mmr: u8,
411 output_address: u16,
413
414 sna: SnaAssembler,
419 sna_version: cpclib_sna::SnapshotVersion,
421
422 cpr: Option<CprAssembler>,
424
425 free_banks: DecoratedPages,
427
428 macro_seed: usize,
430
431 charset_encoding: CharsetEncoding,
432
433 byte_written: bool,
436
437 symbols: SymbolsTableCaseDependent,
438
439 return_value: Option<ExprResult>,
441 functions: BTreeMap<String, Arc<Function>>,
442
443 run_options: Option<(u16, Option<u16>)>,
445
446 output_trigger: Option<ListingOutputTrigger>,
448 symbols_output: SymbolOutputGenerator,
450
451 warnings: Vec<AssemblerWarning>,
452
453 nested_rorg: usize,
455
456 sections: HashMap<String, Arc<RwLock<Section>>>,
458 current_section: Option<Arc<RwLock<Section>>>,
460
461 saved_files: Option<Vec<SavedFile>>,
462
463 previous_pass_discarded_errors: HashSet<String>,
465 current_pass_discarded_errors: HashSet<String>,
467
468 if_token_adr_to_used_decision: HashMap<usize, bool>,
469 if_token_adr_to_unused_decision: HashMap<usize, bool>,
470
471 included_paths: HashSet<Utf8PathBuf>,
472
473 map_counter: i32,
474
475 repeat_start: ExprResult,
477 repeat_step: ExprResult,
478
479 extra_print_from_function: RwLock<Vec<PrintOrPauseCommand>>,
481 extra_failed_assert_from_function: RwLock<Vec<FailedAssertCommand>>,
482
483 pub(crate) assembling_control_current_output_commands: Vec<ControlOutputStore>
485}
486
487impl Default for Env {
488 fn default() -> Self {
489 Env::new(Default::default())
490 }
491}
492
493impl Clone for Env {
494 fn clone(&self) -> Self {
495 Self {
496 lookup_directory_stack: self.lookup_directory_stack.clone(),
497 options: self.options.clone(),
498 can_skip_next_passes: (*self.can_skip_next_passes.read().unwrap().deref()).into(),
499 request_additional_pass: (*self.request_additional_pass.read().unwrap().deref()).into(),
500 pass: self.pass,
501 real_nb_passes: self.real_nb_passes,
502 crunched_section_state: self.crunched_section_state.clone(),
503 stable_counters: self.stable_counters.clone(),
504 ga_mmr: self.ga_mmr,
505 output_address: self.output_address,
506 sna: self.sna.clone(),
507 sna_version: self.sna_version,
508 free_banks: self.free_banks.clone(),
509 macro_seed: self.macro_seed,
510 charset_encoding: self.charset_encoding.clone(),
511 byte_written: self.byte_written,
512 symbols: self.symbols.clone(),
513 run_options: self.run_options,
514 output_trigger: self.output_trigger.clone(),
515 symbols_output: self.symbols_output.clone(),
516 warnings: self.warnings.clone(),
517 nested_rorg: self.nested_rorg,
518 sections: self.sections.clone(),
519 current_section: self.current_section.clone(),
520 saved_files: self.saved_files.clone(),
521
522 if_token_adr_to_used_decision: self.if_token_adr_to_used_decision.clone(),
523 if_token_adr_to_unused_decision: self.if_token_adr_to_unused_decision.clone(),
524 requested_additional_pass: self.requested_additional_pass,
525
526 functions: self.functions.clone(),
527 return_value: self.return_value.clone(),
528
529 current_pass_discarded_errors: self.current_pass_discarded_errors.clone(),
530 previous_pass_discarded_errors: self.previous_pass_discarded_errors.clone(),
531
532 included_paths: self.included_paths.clone(),
533 extra_print_from_function: self
534 .extra_print_from_function
535 .read()
536 .unwrap()
537 .clone()
538 .into(),
539 extra_failed_assert_from_function: self
540 .extra_failed_assert_from_function
541 .read()
542 .unwrap()
543 .clone()
544 .into(),
545
546 map_counter: self.map_counter,
547
548 cpr: self.cpr.clone(),
549
550 repeat_start: self.repeat_start.clone(),
551 repeat_step: self.repeat_step.clone(),
552
553 assembling_control_current_output_commands: self
554 .assembling_control_current_output_commands
555 .clone()
556 }
557 }
558}
559impl fmt::Debug for Env {
560 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
561 write!(
562 f,
563 "Env{{ pass: {:?}, symbols {:?} }}",
564 self.pass,
565 self.symbols()
566 )
567 }
568}
569
570impl Env {
572 pub fn options(&self) -> &EnvOptions {
573 &self.options
574 }
575
576 pub fn symbols(&self) -> &SymbolsTableCaseDependent {
577 &self.symbols
578 }
579
580 pub fn symbols_mut(&mut self) -> &mut SymbolsTableCaseDependent {
581 &mut self.symbols
582 }
583
584 pub fn build_fname<E: ExprEvaluationExt + Debug>(
585 &mut self,
586 exp: &E
587 ) -> Result<String, AssemblerError> {
588 let fname = match self.resolve_expr_must_never_fail(exp) {
589 Ok(fname) => Ok(fname),
590 Err(e) => {
591 match &e {
592 AssemblerError::UnknownSymbol { symbol, .. }
594 | AssemblerError::RelocatedError {
595 error: box AssemblerError::UnknownSymbol { symbol, .. },
596 ..
597 } => {
598 let exp_str = exp.to_string();
599 if exp_str.as_str() == symbol.as_str() {
600 Ok(exp_str.into())
601 }
602 else {
603 Err(e)
604 }
605 },
606 _ => Err(e)
607 }
608 }
609 }?;
610 let fname = if fname.is_string() {
611 fname.string()?.to_owned()
612 }
613 else {
614 fname.to_string()
615 };
616 Ok(fname)
617 }
618
619 pub fn resolve_expr_may_fail_in_first_pass<E: ExprEvaluationExt>(
625 &mut self,
626 exp: &E
627 ) -> Result<ExprResult, AssemblerError> {
628 self.resolve_expr_may_fail_in_first_pass_with_default(exp, 0)
629 }
630
631 pub fn resolve_index_may_fail_in_first_pass<E: ExprEvaluationExt>(
632 &mut self,
633 (op, exp): (BinaryOperation, &E)
634 ) -> Result<ExprResult, AssemblerError> {
635 let res = self.resolve_expr_may_fail_in_first_pass(exp)?;
636 let res = if op == BinaryOperation::Sub {
637 res.neg()?
638 }
639 else {
640 res
641 };
642 Ok(res)
643 }
644
645 pub fn resolve_expr_may_fail_in_first_pass_with_default<
646 E: ExprEvaluationExt,
647 R: Into<ExprResult>
648 >(
649 &mut self,
650 exp: &E,
651 r: R
652 ) -> Result<ExprResult, AssemblerError> {
653 self.track_used_symbols(exp);
654
655 match exp.resolve(self) {
656 Ok(value) => Ok(value),
657 Err(e) => {
658 if let Some(commands) = self.assembling_control_current_output_commands.last() {
660 if !commands.has_remaining_passes() {
661 return Err(e);
662 }
663 }
664
665 if self.pass.is_first_pass() {
666 *self.can_skip_next_passes.write().unwrap() = false;
667 Ok(r.into())
668 }
669 else {
670 Err(e)
671 }
672 }
673 }
674 }
675
676 fn resolve_expr_must_never_fail<E: ExprEvaluationExt>(
679 &mut self,
680 exp: &E
681 ) -> Result<ExprResult, AssemblerError> {
682 match exp.resolve(self) {
683 Ok(value) => Ok(value),
684 Err(e) => {
685 if self.pass.is_first_pass() {
686 *self.can_skip_next_passes.write().unwrap() = false;
687 Err(e)
688 }
689 else {
690 Err(e)
691 }
692 },
693 }
694 }
695
696 pub(crate) fn add_function_parameter_to_symbols_table<S: Into<Symbol>, V: Into<Value>>(
697 &mut self,
698 symbol: S,
699 value: V
700 ) -> Result<(), AssemblerError> {
701 let symbol = symbol.into();
702 self.symbols
707 .set_symbol_to_value(symbol, ValueAndSource::new_unlocated(value))?;
708 Ok(())
709 }
710
711 fn add_symbol_to_symbol_table<E: Into<Value>>(
715 &mut self,
716 label: &str,
717 value: E,
718 location: Option<Source>
719 ) -> Result<(), AssemblerError> {
720 let already_present = self.symbols().contains_symbol(label)?;
721 let value = value.into();
722 let value = ValueAndSource::new(value, location);
723
724 match (already_present, self.pass) {
725 (true, AssemblingPass::FirstPass) => {
726 Err(AssemblerError::SymbolAlreadyExists {
727 symbol: label.to_string()
728 })
729 },
730 (false, AssemblingPass::SecondPass) => {
731 if !self.requested_additional_pass && !*self.request_additional_pass.read().unwrap()
733 {
734 Err(AssemblerError::IncoherentCode {
735 msg: format!(
736 "Label {} is not present in the symbol table in pass {}. There is an issue with some conditional code.",
737 label, self.pass
738 )
739 })
740 }
741 else {
742 self.symbols_mut().set_symbol_to_value(label, value)?;
743 Ok(())
744 }
745 },
746 (false, AssemblingPass::ListingPass) => {
747 panic!();
748 Err(AssemblerError::IncoherentCode {
749 msg: format!(
750 "Label {} is not present in the symbol table in pass {}. There is an issue with some conditional code.",
751 label, self.pass
752 )
753 })
754 },
755 (false, AssemblingPass::FirstPass) | (false, AssemblingPass::Uninitialized) => {
756 self.symbols_mut().set_symbol_to_value(label, value)?;
757 Ok(())
758 },
759 (true, AssemblingPass::SecondPass | AssemblingPass::ListingPass) => {
760 self.symbols_mut().update_symbol_to_value(label, value)?;
761 Ok(())
762 },
763 (..) => {
764 panic!(
765 "add_symbol_to_symbol_table / unmanaged case {}, {}, {} {:#?}",
766 self.pass, label, already_present, value
767 )
768 }
769 }
770 }
771
772 fn track_used_symbols<E: ExprEvaluationExt>(&mut self, e: &E) {
774 e.symbols_used()
775 .into_iter()
776 .for_each(|symbol| self.symbols.use_symbol(symbol))
777 }
778}
779impl Env {
781 pub fn report(&self, start: &Instant) -> Report {
782 Report::from((self, start))
783 }
784}
785
786impl Env {
788 #[inline]
789 fn included_marks_reset(&mut self) {
790 self.included_paths.clear();
791 }
792
793 #[inline]
794 fn included_marks_includes(&self, path: &Utf8PathBuf) -> bool {
795 self.included_paths.contains(path)
796 }
797
798 #[inline]
799 fn included_marks_add(&mut self, path: Utf8PathBuf) {
800 self.included_paths.insert(path);
801 }
802}
803
804impl Env {
806 fn set_current_working_directory<P: Into<Utf8PathBuf>>(&mut self, p: P) {
807 self.lookup_directory_stack.push(p.into())
808 }
809
810 pub fn enter_current_working_file<P: AsRef<Utf8Path>>(&mut self, f: P) {
811 let f = f.as_ref();
812 debug_assert!(f.is_file() || f.starts_with("inner://"));
813 self.set_current_working_directory(f.parent().unwrap());
814 }
815
816 pub fn leave_current_working_file(&mut self) -> Option<Utf8PathBuf> {
817 self.lookup_directory_stack.pop()
818 }
819
820 pub fn get_current_working_directory(&self) -> Option<&Utf8Path> {
821 self.lookup_directory_stack.last().map(|p| p.as_path())
822 }
823
824 pub fn has_current_working_directory(&self) -> bool {
825 !self.lookup_directory_stack.is_empty()
826 }
827}
828
829impl Env {
831 pub fn add_error_discardable_one_pass(
833 &mut self,
834 e: AssemblerError
835 ) -> Result<(), AssemblerError> {
836 let repr = SimplerAssemblerError(&e).to_string();
837 if self.previous_pass_discarded_errors.contains(&repr) {
838 Err(e)
839 }
840 else {
841 self.current_pass_discarded_errors.insert(repr);
842 Ok(())
843 }
844 }
845}
846impl Env {
848 fn enter_namespace(&mut self, namespace: &str) -> Result<(), AssemblerError> {
849 if namespace.contains(".") {
850 return Err(AssemblerError::AssemblingError {
851 msg: format!("Invalid namespace \"{}\"", namespace)
852 });
853 }
854 self.symbols_mut().enter_namespace(namespace);
855 Ok(())
856 }
857
858 fn leave_namespace(&mut self) -> Result<Symbol, AssemblerError> {
859 self.symbols_mut().leave_namespace().map_err(|e| e.into())
860 }
861}
862
863impl Env {
864 fn output_kind(&self) -> OutputKind {
866 if self.cpr.is_some() {
867 OutputKind::Cpr
868 }
869 else if self.free_banks.selected_index.is_some() {
870 OutputKind::FreeBank
871 }
872 else {
873 OutputKind::Snapshot
874 }
875 }
876}
877
878#[allow(missing_docs)]
879impl Env {
880 pub fn with_table(symbols: &SymbolsTable) -> Self {
884 let mut env = Self::new(Default::default());
885 env.symbols.set_table(symbols.clone());
886 env.pass = AssemblingPass::SecondPass;
887 env
888 }
889
890 pub fn with_table_case_dependent(symbols: &SymbolsTableCaseDependent) -> Self {
892 let mut env = Self::new(Default::default());
893 env.symbols = symbols.clone();
894 env.pass = AssemblingPass::SecondPass;
895 env
896 }
897
898 pub fn warnings(&self) -> &[AssemblerWarning] {
899 &self.warnings
900 }
901
902 fn handle_output_trigger(&mut self, new: &LocatedToken) {
904 if self.pass.is_listing_pass() && self.output_trigger.is_some() {
905 let code_addr = self.logical_code_address();
906 let phy_addr = self.logical_to_physical_address(self.logical_output_address());
907
908 let kind = if self.crunched_section_state.is_some() {
909 AddressKind::CrunchedArea
910 }
911 else {
912 AddressKind::Address
913 };
914
915 let trig = self.output_trigger.as_mut().unwrap();
916
917 trig.new_token(new, code_addr as _, kind, phy_addr);
918 }
919 }
920
921 fn retrieve_options_symbols(&mut self) {
922 let symbols = self
923 .options()
924 .symbols()
925 .available_symbols()
926 .cloned()
927 .collect_vec();
928 for symbol in symbols {
929 let value = self
930 .options()
931 .symbols()
932 .any_value(symbol.clone())
933 .unwrap()
934 .unwrap()
935 .clone();
936
937 self.symbols_mut().set_symbol_to_value(symbol, value);
938 }
939 }
940
941 pub(crate) fn start_new_pass(&mut self) {
944 if self.options().assemble_options().debug() {
945 eprintln!("Start a new pass {}", self.pass());
946 self.handle_print();
947 self.generate_symbols_output(
948 std::io::stderr().borrow_mut(),
949 SymbolOutputFormat::Winape
950 );
951 }
952
953 self.included_marks_reset();
954 self.requested_additional_pass |= !self.current_pass_discarded_errors.is_empty();
955
956 let mut can_change_request = true;
957 if !self.pass.is_listing_pass() {
958 self.pass = if self.real_nb_passes == 0
959 || !*self.can_skip_next_passes.read().unwrap().deref()
960 {
961 if *self.request_additional_pass.read().unwrap() {
962 if self.pass.is_first_pass() {
963 can_change_request = false;
964 }
965 AssemblingPass::SecondPass
966 }
967 else {
968 self.pass.next_pass()
969 }
970 }
971 else if !*self.request_additional_pass.read().unwrap() {
972 AssemblingPass::Finished
973 }
974 else {
975 AssemblingPass::SecondPass
976 };
977 }
978
979 if !self.pass.is_finished() || self.pass.is_listing_pass() {
980 if !self.pass.is_listing_pass() {
981 self.real_nb_passes += 1;
982 }
983
984 std::mem::swap(
985 &mut self.current_pass_discarded_errors,
986 &mut self.previous_pass_discarded_errors
987 );
988 self.current_pass_discarded_errors.clear();
989
990 self.stable_counters.new_pass();
991 self.run_options = None;
992
993 self.sna.reset_written_bytes();
994 if let Some(cpr) = self.cpr.as_mut() {
995 cpr.reset_written_bytes()
996 }
997 self.free_banks.reset_written_bytes();
998
999 self.warnings.retain(|elem| !elem.is_override_memory());
1000 self.sna.pages_info.iter_mut().for_each(|p| p.new_pass());
1001
1002 self.sections
1003 .iter_mut()
1004 .for_each(|s| s.1.write().unwrap().new_pass());
1005 self.current_section = None;
1006
1007 self.free_banks.pages.iter_mut().for_each(|bank| {
1008 bank.1.new_pass();
1009 bank.2.fill(false);
1010 });
1011 self.free_banks.selected_index = None;
1012
1013 self.output_address = 0;
1015 let page_info = self.active_page_info_mut();
1016 page_info.logical_outputadr = 0;
1017 page_info.logical_codeadr = 0;
1018 self.update_dollar();
1019
1020 self.ga_mmr = 0xC0;
1021 self.macro_seed = 0;
1022 self.charset_encoding.reset();
1023 self.can_skip_next_passes = true.into();
1027 if can_change_request {
1028 self.request_additional_pass = false.into();
1029 }
1030
1031 self.symbols.new_pass();
1033 self.retrieve_options_symbols();
1034
1035 if self.options.show_progress() {
1036 #[cfg(not(target_arch = "wasm32"))]
1037 Progress::progress().new_pass();
1038 }
1039 }
1040
1041 if AssemblingPass::FirstPass == self.pass {
1042 self.add_symbol_to_symbol_table(
1043 "BASM_VERSION",
1044 built_info::PKG_VERSION.to_owned(),
1045 None
1046 );
1047 self.add_symbol_to_symbol_table("BASM", 1, None);
1048 self.add_symbol_to_symbol_table("BASM_FEATURE_HFE", cfg!(feature = "hfe"), None);
1049 }
1050 }
1051
1052 pub fn handle_post_actions<'token, T>(
1055 &mut self,
1056 tokens: &'token [T]
1057 ) -> Result<(Option<RemuChunk>, Option<WabpChunk>), AssemblerError>
1058 where
1059 T: Visited + ToSimpleToken + Debug + Sync + ListingElement + MayHaveSpan,
1060 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
1061 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
1062 ExprEvaluationExt + ExprElement,
1063 ProcessedToken<'token, T>: FunctionBuilder
1064 {
1065 self.handle_print()?;
1066 self.handle_assert()?;
1067
1068 let remu_in_sna = self
1069 .options()
1070 .assemble_options()
1071 .get_flag(crate::AssemblingOptionFlags::SnaRemu);
1072 let remu_in_file = self
1073 .options()
1074 .assemble_options()
1075 .get_flag(crate::AssemblingOptionFlags::RemuInFile);
1076 let wabp_in_file = self
1077 .options()
1078 .assemble_options()
1079 .get_flag(crate::AssemblingOptionFlags::WabpInFile);
1080
1081 let mut remu = if remu_in_file || remu_in_sna {
1082 Some(RemuChunk::empty())
1083 }
1084 else {
1085 None
1086 };
1087
1088 let mut wabp = if wabp_in_file {
1089 Some(WabpChunk::empty())
1090 }
1091 else {
1092 None
1093 };
1094
1095 self.handle_breakpoints(&mut remu.as_mut(), &mut wabp.as_mut())?;
1096 self.handle_sna_symbols(&mut remu.as_mut())?;
1097
1098 if let Some(remu) = &remu
1099 && remu_in_sna
1100 {
1101 self.sna.add_chunk(remu.clone());
1102 }
1103
1104 if self.options().assemble_options().output_builder.is_some() {
1106 let mut tokens = processed_token::build_processed_tokens_list(tokens, self)
1107 .expect("No errors must occur here");
1108 self.pass = AssemblingPass::ListingPass;
1109 self.start_new_pass();
1110 processed_token::visit_processed_tokens(&mut tokens, self)
1111 .map_err(|e| eprintln!("{}", e))
1112 .expect("No error can arise in listing output mode; there is a bug somewhere");
1113 }
1114
1115 self.saved_files = Some(self.handle_file_save()?);
1119
1120 Ok((remu, wabp))
1121 }
1122
1123 fn handle_sna_symbols(
1125 &mut self,
1126 remu: &mut Option<&mut RemuChunk>
1127 ) -> Result<(), AssemblerError> {
1128 let options = self.options().assemble_options().clone();
1129 if options.get_flag(crate::AssemblingOptionFlags::SnaSymb) {
1130 let ace_chunk = self.symbols_output.build_ace_snapshot_chunk(self.symbols());
1131 self.sna.add_chunk(ace_chunk);
1132 }
1133
1134 if options.get_flag(crate::AssemblingOptionFlags::SnaRemu) {
1135 self.symbols_output
1136 .fill_remu_snapshot_chunk(self.symbols(), remu.as_mut().unwrap());
1137 }
1138
1139 Ok(())
1140 }
1141
1142 fn handle_breakpoints(
1146 &mut self,
1147 remu: &mut Option<&mut RemuChunk>,
1148 wabp: &mut Option<&mut WabpChunk>
1149 ) -> Result<(), AssemblerError> {
1150 let mut winape_chunk = if self
1151 .options()
1152 .assemble_options()
1153 .get_flag(crate::AssemblingOptionFlags::SnaBrks)
1154 {
1155 Some(WinapeBreakPointChunk::empty())
1156 }
1157 else {
1158 None
1159 };
1160 let mut ace_chunk = if self
1161 .options()
1162 .assemble_options()
1163 .get_flag(crate::AssemblingOptionFlags::SnaBrkc)
1164 {
1165 Some(AceBreakPointChunk::empty())
1166 }
1167 else {
1168 None
1169 };
1170
1171 let pages_mmr = MMR_PAGES_SELECTION;
1172 for (activepage, _page) in pages_mmr[0..self.sna.pages_info.len()].iter().enumerate() {
1173 for brk in self.sna.pages_info[activepage].collect_breakpoints() {
1174 let info = AssemblerError::RelocatedInfo {
1175 info: Box::new(AssemblerError::AssemblingError {
1176 msg: format!("Add a breakpoint: {} ", brk.info_repr())
1177 }),
1178 span: brk.span.as_ref().unwrap().clone()
1179 };
1180 eprint!("{}", info);
1181
1182 if let Some(chunk) = winape_chunk.as_mut() {
1183 if let Some(brk) = brk.winape() {
1184 chunk.add_breakpoint(brk);
1185 }
1186 }
1187 if let Some(chunk) = ace_chunk.as_mut() {
1188 if let Some(brk) = brk.ace() {
1189 chunk.add_breakpoint(brk);
1190 }
1191 }
1192
1193 if let Some(chunk) = remu.as_mut() {
1194 chunk.add_entry(&brk.remu().into());
1195 }
1196
1197 if let Some(chunk) = wabp.as_mut() {
1198 chunk.add_breakpoint(brk.wabp());
1199 }
1200 }
1201 }
1202
1203 if let Some(chunk) = winape_chunk
1204 && chunk.nb_breakpoints() > 0
1205 {
1206 self.sna.add_chunk(chunk);
1207 }
1208
1209 if let Some(chunk) = ace_chunk
1210 && chunk.nb_breakpoints() > 0
1211 {
1212 self.sna.add_chunk(chunk);
1213 }
1214
1215 Ok(())
1216 }
1217
1218 fn handle_assert(&mut self) -> Result<(), AssemblerError> {
1219 let backup = self.ga_mmr;
1220
1221 let pages_mmr = MMR_PAGES_SELECTION;
1223
1224 let mut assert_failures: Option<AssemblerError> = None;
1225
1226 let mut handle_page = |page: &PageInformation| {
1227 let mut l_errors = page.collect_assert_failure();
1228 match (&mut assert_failures, &mut l_errors) {
1229 (_, Ok(_)) => {
1230 },
1232 (
1233 Some(AssemblerError::MultipleErrors { errors: e1 }),
1234 Err(AssemblerError::MultipleErrors { errors: e2 })
1235 ) => {
1236 e1.append(e2);
1237 },
1238 (None, Err(l_errors)) => {
1239 assert_failures = Some(l_errors.clone());
1240 },
1241 _ => unreachable!()
1242 }
1243 };
1244
1245 for (activepage, page) in pages_mmr[0..self.sna.pages_info.len()].iter().enumerate() {
1246 self.ga_mmr = *page;
1247 let page = &self.sna.pages_info[activepage];
1248 handle_page(page);
1249 }
1250
1251 for page in self.free_banks.page_infos() {
1252 handle_page(page);
1253 }
1254
1255 if let Some(cpr) = self.cpr.as_ref() {
1256 for page in cpr.page_infos() {
1257 handle_page(page)
1258 }
1259 }
1260
1261 self.ga_mmr = backup;
1262
1263 if let Some(errors) = assert_failures {
1266 Err(errors)
1267 }
1268 else {
1269 Ok(())
1270 }
1271 }
1272
1273 pub fn observer(&self) -> Arc<dyn EnvEventObserver> {
1274 Arc::clone(&self.options().observer)
1275 }
1276
1277 pub fn handle_print(&mut self) -> Result<(), AssemblerError> {
1278 let backup = self.ga_mmr;
1279
1280 let pages_mmr = MMR_PAGES_SELECTION;
1282
1283 let mut print_errors: Option<AssemblerError> = None;
1284 let observer = self.observer();
1285
1286 let mut handle_page_info = |page: &PageInformation| {
1287 let mut l_errors = page.execute_print_or_pause(observer.deref());
1288 match (&mut print_errors, &mut l_errors) {
1289 (_, Ok(_)) => {
1290 },
1292 (
1293 Some(AssemblerError::MultipleErrors { errors: e1 }),
1294 Err(AssemblerError::MultipleErrors { errors: e2 })
1295 ) => {
1296 e1.append(e2);
1297 },
1298 (None, Err(l_errors)) => {
1299 print_errors = Some(l_errors.clone());
1300 },
1301 _ => unreachable!()
1302 }
1303 };
1304
1305 for (activepage, page) in pages_mmr[0..self.sna.pages_info.len()].iter().enumerate() {
1307 self.ga_mmr = *page;
1308 let page_info = &self.sna.pages_info[activepage];
1309
1310 handle_page_info(page_info);
1311 }
1312 self.ga_mmr = backup;
1313
1314 for page in self.free_banks.page_infos() {
1316 handle_page_info(page);
1317 }
1318
1319 if let Some(cpr) = self.cpr.as_ref() {
1321 for page in cpr.page_infos() {
1322 handle_page_info(page);
1323 }
1324 }
1325
1326 if let Some(errors) = print_errors {
1329 Err(errors)
1330 }
1331 else {
1332 Ok(())
1333 }
1334 }
1335
1336 fn handle_file_save(&mut self) -> Result<Vec<SavedFile>, AssemblerError> {
1337 let backup = self.ga_mmr;
1338
1339 let pages_mmr = MMR_PAGES_SELECTION;
1341
1342 let mut saved_files = Vec::new();
1343
1344 let nb_files_to_save = {
1346 let mut nb_files_to_save: u64 = 0;
1347 nb_files_to_save += pages_mmr[0..self.sna.pages_info.len()]
1348 .iter()
1349 .enumerate()
1350 .map(|(activepage, page)| {
1351 self.ga_mmr = *page;
1352 self.sna.pages_info[activepage].nb_files_to_save() as u64
1353 })
1354 .sum::<u64>();
1355 nb_files_to_save += self
1356 .free_banks
1357 .pages
1358 .iter()
1359 .map(|b| b.1.nb_files_to_save() as u64)
1360 .sum::<u64>();
1361
1362 nb_files_to_save
1363 };
1364
1365 if self.options.show_progress() {
1366 #[cfg(not(target_arch = "wasm32"))]
1367 Progress::progress().create_save_bar(nb_files_to_save);
1368 }
1369
1370 for (activepage, _page) in pages_mmr[0..self.sna.pages_info.len()].iter().enumerate() {
1372 for mma in self.sna.pages_info[activepage].get_save_mmrs() {
1376 self.ga_mmr = mma;
1377 let mut saved = self.sna.pages_info[activepage].execute_save(self, mma)?;
1378 saved_files.append(&mut saved);
1379 }
1380 }
1381
1382 self.ga_mmr = 0xC0;
1384
1385 #[cfg(all(not(target_arch = "wasm32"), feature = "rayon"))]
1386 let iter = {
1387 let can_save_in_parallel = self.banks.iter().all(|b| b.1.can_save_in_parallel());
1388 CondIterator::new(&self.banks, can_save_in_parallel)
1389 };
1390 #[cfg(any(target_arch = "wasm32", not(feature = "rayon")))]
1391 let iter = self.free_banks.pages.iter();
1392 let mut saved = iter
1393 .map(|bank| bank.1.execute_save(self, self.ga_mmr))
1394 .collect::<Result<Vec<_>, AssemblerError>>()?;
1395 for s in &mut saved {
1396 saved_files.append(s);
1397 }
1398
1399 if self.options().show_progress() {
1400 #[cfg(not(target_arch = "wasm32"))]
1401 Progress::progress().finish_save();
1402 }
1403 self.ga_mmr = backup;
1405 Ok(saved_files)
1406 }
1407}
1408
1409impl Env {
1411 fn active_page_info(&self) -> &PageInformation {
1413 match self.output_kind() {
1414 OutputKind::Snapshot => {
1415 let active_page = self
1416 .logical_to_physical_address(self.output_address)
1417 .to_memory()
1418 .page() as usize;
1419 &self.sna.pages_info[active_page]
1420 },
1421 OutputKind::Cpr => {
1422 self.cpr
1423 .as_ref()
1424 .unwrap()
1425 .selected_active_page_info()
1426 .unwrap()
1427 },
1428 OutputKind::FreeBank => self.free_banks.selected_active_page_info().unwrap()
1429 }
1430 }
1431
1432 fn active_page_info_mut(&mut self) -> &mut PageInformation {
1433 match self.output_kind() {
1434 OutputKind::Snapshot => {
1435 let active_page = self
1436 .logical_to_physical_address(self.output_address)
1437 .to_memory()
1438 .page() as usize;
1439 &mut self.sna.pages_info[active_page]
1440 },
1441 OutputKind::Cpr => {
1442 let cpr = self.cpr.as_mut().unwrap();
1443 cpr.selected_active_page_info_mut().unwrap()
1444 },
1445 OutputKind::FreeBank => self.free_banks.selected_active_page_info_mut().unwrap()
1446 }
1447 }
1448
1449 fn page_info_for_logical_address_mut(&mut self, address: u16) -> &mut PageInformation {
1450 match self.output_kind() {
1451 OutputKind::Snapshot => {
1452 let active_page =
1453 self.logical_to_physical_address(address).to_memory().page() as usize;
1454 &mut self.sna.pages_info[active_page]
1455 },
1456 OutputKind::Cpr => {
1457 self.cpr
1458 .as_mut()
1459 .unwrap()
1460 .selected_active_page_info_mut()
1461 .unwrap()
1462 },
1463 OutputKind::FreeBank => self.free_banks.selected_active_page_info_mut().unwrap()
1464 }
1465 }
1466
1467 fn written_bytes(&self) -> &BitVec {
1468 match self.output_kind() {
1469 OutputKind::Snapshot => &self.sna.written_bytes,
1470 OutputKind::Cpr => {
1471 self.cpr
1472 .as_ref()
1473 .unwrap()
1474 .selected_written_bytes()
1475 .expect("No bank selected")
1476 },
1477 OutputKind::FreeBank => {
1478 self.free_banks
1479 .selected_written_bytes()
1480 .expect("No bank selected")
1481 },
1482 }
1483 }
1484
1485 pub fn logical_output_address(&self) -> u16 {
1487 self.active_page_info().logical_outputadr
1488 }
1489
1490 pub fn physical_output_address(&self) -> PhysicalAddress {
1491 self.logical_to_physical_address(self.logical_output_address())
1492 }
1493
1494 pub fn physical_code_address(&self) -> PhysicalAddress {
1495 self.logical_to_physical_address(self.logical_code_address())
1496 }
1497
1498 pub fn logical_code_address(&self) -> u16 {
1500 self.active_page_info().logical_codeadr
1501 }
1502
1503 pub fn output_limit_address(&self) -> u16 {
1504 self.active_page_info().output_limit
1505 }
1506
1507 pub fn code_limit_address(&self) -> u16 {
1508 self.active_page_info().code_limit
1509 }
1510
1511 pub fn start_address(&self) -> Option<u16> {
1512 self.active_page_info().startadr
1513 }
1514
1515 pub fn maximum_address(&self) -> u16 {
1516 self.active_page_info().maxadr
1517 }
1518
1519 pub fn update_dollar(&mut self) {
1521 if let Some(cpr) = &self.cpr {
1522 if cpr.is_empty() {
1523 return;
1524 }
1525 }
1526
1527 let code_addr = self.logical_to_physical_address(self.logical_code_address());
1528 let output_addr = self.logical_to_physical_address(self.logical_output_address());
1529
1530 self.symbols.set_current_address(code_addr);
1531 self.symbols.set_current_output_address(output_addr);
1532 }
1533
1534 pub fn get_memory(&self, start: u16, size: u16) -> Vec<u8> {
1538 let mut mem = Vec::new();
1540 let start = start as u32;
1541 let size = size as u32;
1542 for pos in start..(start + size) {
1543 let address = self.logical_to_physical_address(pos as _);
1544 mem.push(self.peek(&address));
1545 }
1546 mem
1547 }
1548
1549 pub fn produced_bytes(&self) -> Vec<u8> {
1551 let (start, length) = match self.start_address() {
1552 Some(start) => {
1553 if start > self.maximum_address() {
1554 (0, 0)
1555 }
1556 else {
1557 (start, self.maximum_address() as usize - start as usize + 1)
1558 }
1559 },
1560 None => (0, 0)
1561 };
1562
1563 self.get_memory(start, length as _)
1564 }
1565
1566 pub fn loading_address(&self) -> Option<u16> {
1568 self.start_address()
1569 }
1570
1571 pub fn execution_address(&self) -> Option<u16> {
1574 self.start_address()
1575 }
1576
1577 pub fn output_byte(&mut self, v: u8) -> Result<bool, AssemblerError> {
1580 if self.logical_output_address() != self.output_address {
1582 return Err(AssemblerError::BugInAssembler {
1583 file: file!(),
1584 line: line!(),
1585 msg: format!(
1586 "Sync issue with output address (0x{:x} != 0x{:x})",
1587 self.logical_output_address(),
1588 self.output_address
1589 )
1590 });
1591 }
1592
1593 let physical_output_address: PhysicalAddress = self.physical_output_address();
1595 let physical_code_address: PhysicalAddress = self.physical_code_address();
1596
1597 if self.physical_output_address().address() > self.output_limit_address()
1600 || (self.active_page_info().fail_next_write_if_zero && self.logical_code_address() == 0)
1601 {
1602 return Err(AssemblerError::OutputExceedsLimits(
1603 physical_output_address,
1604 self.output_limit_address() as _
1605 ));
1606 }
1607
1608 if self.logical_code_address() > self.code_limit_address()
1609 || (self.active_page_info().fail_next_write_if_zero && self.logical_code_address() == 0)
1610 {
1611 return Err(AssemblerError::OutputExceedsLimits(
1612 physical_code_address,
1613 self.code_limit_address() as _
1614 ));
1615 }
1616 for protected_area in &self.active_page_info().protected_areas {
1617 if protected_area.contains(&{ self.logical_code_address() }) {
1618 return Err(AssemblerError::OutputProtected {
1619 area: protected_area.clone(),
1620 address: self.logical_code_address() as _
1621 });
1622 }
1623 }
1624
1625 self.byte_written = true;
1626 if let Some(commands) = self.assembling_control_current_output_commands.last_mut() {
1627 commands.store_byte(v);
1628 }
1629
1630 self.active_page_info_mut().maxadr =
1633 self.maximum_address().max(self.logical_output_address());
1634 if self.active_page_info_mut().startadr.is_none() {
1635 self.active_page_info_mut().startadr = Some(self.logical_output_address());
1636 };
1637
1638 let abstract_address = physical_output_address.offset_in_cpc();
1639 let already_used = if let Some(access) = self.written_bytes().get(abstract_address as usize)
1640 {
1641 *access
1642 }
1643 else {
1644 return Err(AssemblerError::BugInAssembler {
1645 file: file!(),
1646 line: line!(),
1647 msg: format!(
1648 "Wrong size of memory access {} > {}",
1649 abstract_address,
1650 self.written_bytes().len()
1651 )
1652 });
1653 };
1654
1655 let r#override = if already_used {
1656 let r#override = AssemblerWarning::OverrideMemory(physical_output_address, 1);
1657 if self.allow_memory_override() {
1658 self.add_warning(r#override);
1659 true
1660 }
1661 else {
1662 return Err(r#override);
1663 }
1664 }
1665 else {
1666 false
1667 };
1668
1669 if self.free_banks.selected_index.is_none() {
1670 if let Some(section) = &self.current_section {
1671 let section = section.read().unwrap();
1672 if !section.contains(physical_output_address.address()) {
1673 return Err(AssemblerError::AssemblingError {
1674 msg: format!(
1675 "SECTION error: write address 0x{:x} out of range [Ox{:}-Ox{:}]",
1676 physical_output_address.address(),
1677 section.start,
1678 section.stop
1679 )
1680 });
1681 }
1682 }
1683 }
1684
1685 match self.output_kind() {
1686 OutputKind::Snapshot => {
1687 self.sna.set_byte(abstract_address, v);
1688 },
1689 OutputKind::Cpr => {
1690 self.cpr
1691 .as_mut()
1692 .unwrap()
1693 .set_byte(self.output_address, v)?;
1694 },
1695 OutputKind::FreeBank => {
1696 self.free_banks.set_byte(self.output_address, v);
1697 }
1698 }
1699
1700 if self.pass.is_listing_pass() && self.output_trigger.is_some() {
1702 self.output_trigger.as_mut().unwrap().write_byte(v);
1703 }
1704
1705 self.active_page_info_mut().logical_outputadr =
1706 self.logical_output_address().wrapping_add(1);
1707 self.output_address = self.logical_output_address();
1708 self.active_page_info_mut().logical_codeadr = self.logical_code_address().wrapping_add(1);
1709
1710 if self.logical_output_address() == 0 {
1712 self.active_page_info_mut().fail_next_write_if_zero = true;
1713 }
1714
1715 {
1716 let (output, code) = (
1717 self.active_page_info().logical_outputadr,
1718 self.active_page_info().logical_codeadr
1719 );
1720
1721 if let Some(section) = &mut self.current_section {
1722 let mut section = section.write().unwrap();
1723 section.output_adr = output;
1724 section.code_adr = code;
1725 section.max_output_adr = section.max_output_adr.max(output);
1726 }
1727 }
1728
1729 self.update_dollar();
1730
1731 Ok(r#override)
1732 }
1733
1734 pub fn allow_memory_override(&self) -> bool {
1735 true }
1737
1738 pub fn output_bytes(&mut self, bytes: &[u8]) -> Result<(), AssemblerError> {
1740 let mut previously_overrided = false;
1743 for b in bytes.iter() {
1744 let currently_overrided = self.output_byte(*b)?;
1745
1746 if self.options().assemble_options().enable_warnings {
1747 match (previously_overrided, currently_overrided) {
1748 (true, true) => {
1749 let extra_override_idx = self
1751 .warnings
1752 .iter_mut()
1753 .rev()
1754 .position(|w| {
1755 if let AssemblerError::OverrideMemory(..) = w {
1756 true
1757 }
1758 else {
1759 false
1760 }
1761 })
1762 .unwrap(); self.warnings
1764 .remove(self.warnings.len() - 1 - extra_override_idx); let r#override = self
1768 .warnings
1769 .iter_mut()
1770 .rev()
1771 .find(|w| {
1772 if let AssemblerError::OverrideMemory(..) = w {
1773 true
1774 }
1775 else {
1776 false
1777 }
1778 })
1779 .unwrap(); match r#override {
1783 AssemblerError::OverrideMemory(_, size) => {
1784 *size += 1;
1785 },
1786 _ => unreachable!()
1787 };
1788 },
1789 _ => {
1790 }
1792 }
1793 }
1794
1795 previously_overrided = currently_overrided;
1796 }
1797
1798 Ok(())
1799 }
1800
1801 pub fn peek(&self, address: &PhysicalAddress) -> u8 {
1802 match self.output_kind() {
1804 OutputKind::Snapshot => {
1805 let address = address.to_memory().offset_in_cpc();
1806 self.sna.get_byte(address)
1807 },
1808 OutputKind::Cpr => {
1809 let address = address.to_cpr().address();
1810 self.cpr.as_ref().unwrap().get_byte(address as _).unwrap()
1811 },
1812 OutputKind::FreeBank => {
1813 let address = address.to_bank().address();
1814 self.free_banks.get_byte(address as _).unwrap()
1815 }
1816 }
1817 }
1818
1819 pub fn poke(&mut self, byte: u8, address: &PhysicalAddress) -> Result<(), AssemblerError> {
1820 match self.output_kind() {
1822 OutputKind::Snapshot => {
1823 let address = address.to_memory().offset_in_cpc();
1824 self.sna.set_byte(address, byte)
1825 },
1826 OutputKind::Cpr => {
1827 let address = address.to_cpr().address();
1828 self.cpr.as_mut().unwrap().set_byte(address as _, byte)?
1829 },
1830 OutputKind::FreeBank => {
1831 let address = address.to_bank().address();
1832 self.free_banks.set_byte(address as _, byte)
1833 }
1834 }
1835
1836 Ok(())
1837 }
1838
1839 pub fn size(&self) -> u16 {
1842 if self.start_address().is_none() {
1843 panic!("Unable to compute size now");
1844 }
1845 else {
1846 self.logical_output_address() - self.start_address().unwrap()
1847 }
1848 }
1849
1850 pub fn eval(&mut self, expr: &Expr) -> Result<ExprResult, AssemblerError> {
1852 expr.resolve(self)
1853 }
1854
1855 pub fn sna(&self) -> &cpclib_sna::Snapshot {
1856 &self.sna
1857 }
1858
1859 pub fn sna_version(&self) -> cpclib_sna::SnapshotVersion {
1860 self.sna_version
1861 }
1862
1863 pub fn save_sna<P: AsRef<Utf8Path>>(&self, fname: P) -> Result<(), std::io::Error> {
1864 self.sna().save(fname, self.sna_version())
1865 }
1866
1867 pub fn save_cpr<P: AsRef<Utf8Path>>(&self, fname: P) -> Result<(), AssemblerError> {
1868 let cpr_asm = self.cpr.as_ref().unwrap();
1869 let cpr = cpr_asm.build_cpr()?;
1870 cpr.save(fname)
1871 .map_err(|e| AssemblerError::IOError { msg: e.to_string() })
1872 }
1873
1874 fn absolute_to_relative_may_fail_in_first_pass(
1876 &self,
1877 address: i32,
1878 opcode_delta: i32
1879 ) -> Result<u8, AssemblerError> {
1880 match absolute_to_relative(address, opcode_delta, self.symbols()) {
1881 Ok(value) => Ok(value),
1882 Err(error) => {
1883 if self.pass.is_first_pass() {
1884 Ok(0)
1885 }
1886 else {
1887 Err(AssemblerError::RelativeAddressUncomputable {
1888 address,
1889 pass: self.pass,
1890 error: Box::new(error)
1891 })
1892 }
1893 },
1894 }
1895 }
1896}
1897
1898impl Env {
1899 #[inline(always)]
1900 pub fn add_warning(&mut self, warning: AssemblerWarning) {
1901 if self.options().assemble_options().enable_warnings {
1902 self.warnings.push(warning);
1903 }
1904 }
1905}
1906
1907impl Env {
1909 fn visit_org<E: ExprElement + ExprEvaluationExt + Debug>(
1910 &mut self,
1911 address: &E,
1912 address2: Option<&E>
1913 ) -> Result<(), AssemblerError> {
1914 let code_adr = if address2.is_none() && address.is_label_value("$") {
1916 if self.start_address().is_none() {
1917 return Err(AssemblerError::InvalidArgument {
1918 msg: "ORG: $ cannot be used now".into()
1919 });
1920 }
1921 self.logical_output_address() as i32
1922 }
1923 else {
1924 self.resolve_expr_must_never_fail(address)?.int()?
1925 };
1926
1927 let output_adr = if let Some(address2) = address2 {
1928 if address2.is_label_value("$") {
1929 self.logical_output_address() as i32 }
1931 else {
1932 self.resolve_expr_must_never_fail(address2)?.int()?
1933 }
1934 }
1935 else {
1936 code_adr
1937 };
1938
1939 if let Some(commands) = self.assembling_control_current_output_commands.last_mut() {
1940 commands.store_org(code_adr as _, output_adr as _);
1941 }
1942
1943 self.visit_org_set_arguments(code_adr as _, output_adr as _)
1944 }
1945
1946 pub fn visit_org_set_arguments(
1947 &mut self,
1948 code_adr: u16,
1949 output_adr: u16
1950 ) -> Result<(), AssemblerError> {
1951 {
1955 let page_info = self.page_info_for_logical_address_mut(output_adr as _);
1956 page_info.logical_outputadr = output_adr as _;
1957 page_info.logical_codeadr = code_adr as _;
1958 page_info.fail_next_write_if_zero = false;
1959 }
1960
1961 self.page_info_for_logical_address_mut(output_adr as _)
1963 .startadr = match self.start_address() {
1964 Some(val) => val.min(self.logical_output_address()),
1965 None => self.logical_output_address()
1966 }
1967 .into();
1968
1969 self.output_address = output_adr as _;
1970 self.update_dollar();
1971
1972 if self.pass.is_listing_pass() && self.output_trigger.is_some() {
1974 let output_adr = self.logical_to_physical_address(output_adr as _);
1975 let trigger = self.output_trigger.as_mut().unwrap();
1976
1977 trigger.replace_code_address(&code_adr.into());
1978 trigger.replace_physical_address(output_adr);
1979 }
1980
1981 if self.logical_output_address() != self.output_address {
1982 return Err(AssemblerError::BugInAssembler {
1983 file: file!(),
1984 line: line!(),
1985 msg: format!(
1986 "BUG in assembler: 0x{:x}!=0x{:x} in pass {:?}",
1987 self.logical_output_address(),
1988 self.output_address,
1989 self.pass
1990 )
1991 });
1992 }
1993
1994 Ok(())
1995 }
1996
1997 fn visit_breakpoint<E: ExprEvaluationExt + ExprElement + MayHaveSpan>(
1998 &mut self,
1999 address: Option<&E>,
2000 r#type: Option<&RemuBreakPointType>,
2001 access: Option<&RemuBreakPointAccessMode>,
2002 run: Option<&RemuBreakPointRunMode>,
2003 mask: Option<&E>,
2004 size: Option<&E>,
2005 value: Option<&E>,
2006 value_mask: Option<&E>,
2007 condition: Option<&E>,
2008 name: Option<&E>,
2009 step: Option<&E>,
2010 span: Option<&Z80Span>
2011 ) -> Result<(), AssemblerError> {
2012 let brk = if r#type.is_none()
2013 && access.is_none()
2014 && run.is_none()
2015 && mask.is_none()
2016 && size.is_none()
2017 && value.is_none()
2018 && value_mask.is_none()
2019 && condition.is_none()
2020 && name.is_none()
2021 && step.is_none()
2022 {
2023 let (current_address, page): (u16, u8) = if let Some(exp) = address {
2025 if exp.is_label() {
2026 let label = exp.label();
2027 let symbols = self.symbols();
2028 let value: &Value = symbols.any_value(label)?.unwrap();
2029 match value {
2030 Value::Expr(expr_result) => (expr_result.int()? as _, 0),
2031 Value::Address(physical_address) => {
2032 (
2033 physical_address.address(),
2034 physical_address.remu_bank() as _
2035 )
2036 }, _ => todo!()
2038 }
2039 }
2040 else {
2041 let current_address = self.resolve_expr_must_never_fail(exp)?.int()?;
2042 let page = 0; (current_address as _, page)
2044 }
2045 }
2046 else {
2047 let current_address = self.logical_code_address();
2048 let page = match self
2051 .logical_to_physical_address(current_address)
2052 .to_memory()
2053 .page()
2054 {
2055 0 => 0,
2056 1 => 1,
2057 _ => {
2058 return Err(AssemblerError::BugInAssembler {
2059 file: file!(),
2060 line: line!(),
2061 msg: format!(
2062 "Page selection not handled 0x{:x}",
2063 self.logical_to_physical_address(current_address)
2064 .to_memory()
2065 .page()
2066 )
2067 });
2068 }
2069 };
2070
2071 (current_address, page)
2072 };
2073
2074 BreakpointCommand::new_simple(current_address, page, span.cloned())
2075 }
2076 else {
2077 let mut brk = AdvancedRemuBreakPoint::default();
2080 brk.addr = if let Some(address) = address {
2081 self.resolve_expr_must_never_fail(address)?.int()? as u16
2082 }
2083 else {
2084 self.logical_code_address()
2085 };
2086 if let Some(r#type) = r#type {
2087 brk.brk_type = r#type.clone();
2088 }
2089 if let Some(access) = access {
2090 brk.access_mode = access.clone();
2091 }
2092 if let Some(run) = run {
2093 brk.run_mode = run.clone();
2094 }
2095 if let Some(mask) = mask {
2096 brk.mask = self.resolve_expr_may_fail_in_first_pass(mask)?.int()? as u16;
2097 }
2098 if let Some(size) = size {
2099 brk.size = self.resolve_expr_may_fail_in_first_pass(size)?.int()? as u16;
2100 }
2101 if let Some(value) = value {
2102 brk.value = self.resolve_expr_may_fail_in_first_pass(value)?.int()? as u8;
2103 }
2104 if let Some(value_mask) = value_mask {
2105 brk.val_mask = self
2106 .resolve_expr_may_fail_in_first_pass(value_mask)?
2107 .int()? as u8;
2108 }
2109 if let Some(step) = step {
2110 brk.step = Some(self.resolve_expr_may_fail_in_first_pass(step)?.int()? as _);
2111 }
2112 if let Some(condition) = condition {
2113 let cond = self.resolve_expr_may_fail_in_first_pass(condition)?;
2114 let cond = cond.string()?;
2115 brk.condition.replace(String127::try_new(cond).map_err(|e| {
2116 let e = AssemblerError::AssemblingError {
2117 msg: "Condition is too long".to_owned()
2118 };
2119 if condition.has_span() {
2120 e.locate(condition.span().clone())
2121 }
2122 else {
2123 e
2124 }
2125 })?);
2126 }
2127 if let Some(name) = name {
2128 let n = self.resolve_expr_may_fail_in_first_pass(name)?;
2129 let n = n.string()?;
2130 brk.name.replace(String127::try_new(n).map_err(|e| {
2131 let e = AssemblerError::AssemblingError {
2132 msg: "Name is too long".to_owned()
2133 };
2134 if name.has_span() {
2135 e.locate(name.span().clone())
2136 }
2137 else {
2138 e
2139 }
2140 })?);
2141 }
2142
2143 BreakpointCommand::from((brk, span.cloned()))
2144 };
2145
2146 if self
2147 .options()
2148 .assemble_options()
2149 .get_flag(crate::AssemblingOptionFlags::BreakpointAsOpcode)
2150 {
2151 self.output_byte(0xED)?;
2154 self.output_byte(0xFF)?;
2155 }
2156 else {
2157 self.active_page_info_mut().add_breakpoint_command(brk);
2158 }
2159
2160 Ok(())
2161 }
2162}
2163
2164#[allow(missing_docs)]
2165impl Env {
2166 pub fn generate_symbols_output<W: Write>(
2168 &self,
2169 w: &mut W,
2170 fmt: SymbolOutputFormat
2171 ) -> std::io::Result<()> {
2172 self.symbols_output.generate(w, self.symbols(), fmt)
2173 }
2174
2175 pub fn visit_listing<T: ListingElement + Visited + MayHaveSpan>(
2178 &mut self,
2179 listing: &[T]
2180 ) -> Result<(), AssemblerError> {
2181 for token in listing.iter() {
2182 token.visited(self)?;
2183 }
2184
2185 Ok(())
2186 }
2187
2188 fn visit_limit<E: ExprEvaluationExt>(&mut self, exp: &E) -> Result<(), AssemblerError> {
2190 let value = self.resolve_expr_must_never_fail(exp)?.int()?;
2191 let in_crunched_section = self.crunched_section_state.is_some();
2192
2193 if value <= 0 {
2194 return Err(AssemblerError::AssemblingError {
2195 msg: format!("It is a nonsense to define a limit of {value}")
2196 });
2197 }
2198
2199 if value > 0xFFFF {
2200 return Err(AssemblerError::AssemblingError {
2201 msg: format!(
2202 "It is a nonsense to define a limit of {value} that exceeds hardware limitations."
2203 )
2204 });
2205 }
2206
2207 if in_crunched_section {
2208 self.active_page_info_mut().code_limit = value as _;
2209 if self.code_limit_address() <= self.maximum_address() {
2210 return Err(AssemblerError::OutputAlreadyExceedsLimits(
2211 self.code_limit_address() as _
2212 ));
2213 }
2214 if self.code_limit_address() == 0 {
2215 eprintln!("[WARNING] Do you really want to set a limit of 0 ?");
2216 }
2217 }
2218 else {
2219 self.active_page_info_mut().output_limit = value as _;
2220 if self.output_limit_address() <= self.maximum_address() {
2221 return Err(AssemblerError::OutputAlreadyExceedsLimits(
2222 self.output_limit_address() as _
2223 ));
2224 }
2225 if self.output_limit_address() == 0 {
2226 eprintln!("[WARNING] Do you really want to set a limit of 0 ?");
2227 }
2228 }
2229
2230 Ok(())
2231 }
2232
2233 fn visit_map<E: ExprEvaluationExt>(&mut self, exp: &E) -> Result<(), AssemblerError> {
2234 let value = self.resolve_expr_must_never_fail(exp)?.int()?;
2235 self.map_counter = value;
2236
2237 Ok(())
2238 }
2239
2240 fn handle_global_and_local_labels<'s>(
2242 &mut self,
2243 label: &'s str
2244 ) -> Result<&'s str, AssemblerError> {
2245 let label = if let Some(dot_pos) = label[1..].find(".") {
2246 let global = &label[0..(dot_pos + 1)];
2247 let local = &label[(dot_pos + 1)..label.len()];
2248 let current = self.symbols().get_current_label().as_ref();
2249 if global != current {
2250 self.symbols_mut().set_current_label(global)?;
2251 }
2252 local
2253 }
2254 else {
2255 label
2256 };
2257
2258 Ok(label)
2259 }
2260
2261 fn visit_label<S: SourceString + MayHaveSpan>(
2262 &mut self,
2263 label_span: S
2264 ) -> Result<(), AssemblerError> {
2265 let label = self.symbols().normalize_symbol(label_span.as_str());
2266 let label = label.value();
2267
2268 let res = if self.symbols().contains_symbol(label)?
2270 && (self.pass.is_first_pass()
2271 || !(self.symbols().kind(label)? == "address"
2272 || self.symbols().kind(label)? == "any"))
2273 {
2274 Err(AssemblerError::AlreadyDefinedSymbol {
2275 symbol: self
2276 .symbols()
2277 .extend_local_and_patterns_for_symbol(label)
2278 .map(std::convert::Into::<SmolStr>::into)
2279 .unwrap_or_else(|_| SmolStr::from(label)),
2280 kind: self.symbols().kind(label)?.into(),
2281 here: self
2282 .symbols()
2283 .any_value(label)
2284 .unwrap()
2285 .unwrap()
2286 .location()
2287 .cloned()
2288 })
2289 }
2290 else {
2291 let label = self.handle_global_and_local_labels(label)?;
2294 if !label.starts_with('.') {
2296 self.symbols_mut().set_current_label(label);
2297 }
2298
2299 let value = self.symbols().current_address().unwrap_or_default();
2301 let addr = self.logical_to_physical_address(value);
2302
2303 self.add_symbol_to_symbol_table(
2304 label,
2305 addr,
2306 label_span.possible_span().map(|s| s.into())
2307 )
2308 };
2309
2310 if let Err(AssemblerError::AlreadyDefinedSymbol {
2312 symbol: _,
2313 kind,
2314 here: _
2315 }) = &res
2316 {
2317 if kind == "macro" || kind == "struct" {
2318 let message = AssemblerError::AssemblingError {
2319 msg:
2320 "Use (void) for macros or structs with no parameters to disambiguate them with labels"
2321 .to_owned()
2322 };
2323 if self.options().assemble_options().force_void() {
2324 return Err(message);
2325 }
2326 else {
2327 }
2329
2330 let macro_token = Token::MacroCall(label.into(), Default::default());
2332 let mut processed_token = build_processed_token(¯o_token, self)?;
2333 processed_token.visited(self)
2334 }
2335 else {
2336 res
2337 }
2338 }
2339 else {
2340 res
2341 }
2342 }
2343
2344 fn visit_noexport<S: AsRef<str> + Display>(
2345 &mut self,
2346 labels: &[S]
2347 ) -> Result<(), AssemblerError> {
2348 if labels.is_empty() {
2349 self.symbols_output.forbid_all_symbols();
2350 }
2351 else {
2352 labels
2353 .iter()
2354 .for_each(|l| self.symbols_output.forbid_symbol(l.as_ref()));
2355 }
2356
2357 Ok(())
2358 }
2359
2360 fn visit_export<S: AsRef<str> + Display>(
2361 &mut self,
2362 labels: &[S]
2363 ) -> Result<(), AssemblerError> {
2364 if labels.is_empty() {
2365 self.symbols_output.allow_all_symbols();
2366 }
2367 else {
2368 labels
2369 .iter()
2370 .for_each(|l| self.symbols_output.allow_symbol(l.as_ref()));
2371 }
2372
2373 Ok(())
2374 }
2375
2376 fn visit_multi_pushes<D: DataAccessElem>(&mut self, regs: &[D]) -> Result<(), AssemblerError> {
2377 let result = regs
2378 .iter()
2379 .map(|reg| assemble_push(reg))
2380 .collect::<Result<Vec<_>, AssemblerError>>()?;
2381 let result = result.into_iter().flatten().collect_vec();
2382 self.output_bytes(&result)
2383 }
2384
2385 fn visit_multi_pops<D: DataAccessElem>(&mut self, regs: &[D]) -> Result<(), AssemblerError> {
2386 let result = regs
2387 .iter()
2388 .map(|reg| assemble_pop(reg))
2389 .collect::<Result<Vec<_>, AssemblerError>>()?;
2390 let result = result.into_iter().flatten().collect_vec();
2391 self.output_bytes(&result)
2392 }
2393
2394 pub fn visit_macro_definition(
2396 &mut self,
2397 name: &str,
2398 arguments: &[&str],
2399 code: &str,
2400 source: Option<&Z80Span>,
2401 flavor: AssemblerFlavor
2402 ) -> Result<(), AssemblerError> {
2403 if let Some(r#macro) = self.symbols().macro_value(name)? {
2405 if r#macro.code().trim() == code.trim() {
2406 return Ok(());
2407 }
2408 else {
2409 let diff = prettydiff::diff_lines(r#macro.code().trim(), code.trim())
2410 .names("Previous macro", "Current macro")
2411 .set_show_lines(true)
2412 .set_diff_only(true)
2413 .format();
2414 let msg = format!("Macro name `{name}` already exists. {}", diff);
2415 return Err(AssemblerError::AlreadyRenderedError(msg));
2416 }
2417 }
2418
2419 if self.pass.is_first_pass() && self.symbols().contains_symbol(name)? {
2421 return Err(AssemblerError::SymbolAlreadyExists {
2422 symbol: name.to_owned()
2423 });
2424 }
2425
2426 let location: Option<Source> = source.map(|s| s.into());
2427 let source = source.map(|s| s.into());
2428
2429 let r#macro = Macro::new(name.into(), arguments, code.to_owned(), source, flavor);
2430 self.symbols_mut()
2431 .set_symbol_to_value(name, ValueAndSource::new(r#macro, location))?;
2432 Ok(())
2433 }
2434
2435 pub fn visit_waitnops<E: ExprEvaluationExt>(
2436 &mut self,
2437 count: &E
2438 ) -> Result<(), AssemblerError> {
2439 let bytes = self.assemble_nop(Mnemonic::Nop, Some(count))?;
2441 self.output_bytes(&bytes)?;
2442
2443 let count = self.resolve_expr_may_fail_in_first_pass(count)?.int()? as _;
2444 self.stable_counters.update_counters(count);
2445 Ok(())
2446 }
2447
2448 pub fn visit_struct_definition<
2449 T: ListingElement + ToSimpleToken,
2450 S1: SourceString,
2451 S2: AsRef<str>
2452 >(
2453 &mut self,
2454 name: S1,
2455 content: &[(S2, T)],
2456 span: Option<&Z80Span>
2457 ) -> Result<(), AssemblerError> {
2458 if self.pass.is_first_pass() && self.symbols().contains_symbol(name.as_str())? {
2459 return Err(AssemblerError::SymbolAlreadyExists {
2460 symbol: name.as_str().to_owned()
2461 });
2462 }
2463
2464 let r#struct = Struct::new(name.as_str(), content, span.map(|s| s.into()));
2465 let mut index = 0;
2467
2468 for (f, s) in r#struct.fields_size(self.symbols()) {
2469 self.symbols_mut()
2470 .set_symbol_to_value(format!("{}.{}", name, f), ValueAndSource::new(index, span))?;
2471 index += s;
2472 }
2473
2474 self.symbols_mut()
2475 .set_symbol_to_value(name.as_str(), ValueAndSource::new(r#struct, span))?;
2476
2477 Ok(())
2478 }
2479
2480 pub fn visit_buildcpr(&mut self) -> Result<(), AssemblerError> {
2481 if self.pass.is_first_pass() {
2482 self.cpr = Some(CprAssembler::default());
2483 }
2484 else {
2485 self.cpr.as_mut().unwrap().select(0);
2486 }
2487
2488 self.free_banks.selected_index = None; self.ga_mmr = 0xC0;
2490
2491 Ok(())
2492 }
2493
2494 pub fn visit_buildsna(
2495 &mut self,
2496 version: Option<&SnapshotVersion>
2497 ) -> Result<(), AssemblerError> {
2498 self.sna_version = version.cloned().unwrap_or(SnapshotVersion::V3);
2499 self.free_banks.selected_index = None;
2500 Ok(())
2501 }
2502
2503 pub fn visit_assembler_control<C: AssemblerControlCommand>(
2504 &mut self,
2505 cmd: &C,
2506 span: Option<&Z80Span>
2507 ) -> Result<(), AssemblerError> {
2508 if cmd.is_restricted_assembling_environment() {
2509 return Err(AssemblerError::BugInAssembler {
2510 file: file!(),
2511 line: line!(),
2512 msg: "BUG in assembler. This has to be handled in processed_tokens".to_string()
2513 });
2514 }
2515 else if cmd.is_print_at_parse_state() {
2516 }
2518 else {
2519 assert!(cmd.is_print_at_assembling_state());
2520 let print_or_error =
2521 match self.prepropress_string_formatted_expression(cmd.get_formatted_expr()) {
2522 Ok(msg) => either::Either::Left(msg),
2523 Err(error) => either::Either::Right(error)
2524 };
2525
2526 PrintCommand {
2527 prefix: Some(format!("[PASS{}] ", self.pass)),
2528 span: span.cloned(),
2529 print_or_error
2530 }
2531 .execute(self.observer().deref()); }
2533 Ok(())
2534 }
2535
2536 pub fn visit_align<E: ExprEvaluationExt>(
2537 &mut self,
2538 boundary: &E,
2539 fill: Option<&E>
2540 ) -> Result<(), AssemblerError> {
2541 let boundary = self.resolve_expr_must_never_fail(boundary)?.int()? as u16;
2542 let fill = match fill {
2543 Some(fill) => self.resolve_expr_may_fail_in_first_pass(fill)?.int()? as u8,
2544 None => 0
2545 };
2546
2547 const OUTPUT_ALIGN: bool = false; while if OUTPUT_ALIGN {
2550 self.logical_output_address()
2551 }
2552 else {
2553 self.logical_code_address()
2554 } % boundary
2555 != 0
2556 {
2557 self.output_byte(fill)?;
2558 }
2559
2560 Ok(())
2561 }
2562
2563 fn get_section_description(&self, name: &str) -> Result<Section, AssemblerError> {
2564 match self.sections.get(name) {
2565 Some(section) => Ok(section.read().unwrap().clone()),
2566 None => {
2567 Err(AssemblerError::AssemblingError {
2568 msg: format!("Section '{}' does not exists", name)
2569 })
2570 },
2571 }
2572 }
2573
2574 fn visit_section<S: SourceString>(&mut self, name: S) -> Result<(), AssemblerError> {
2575 let section = match self.sections.get(name.as_str()) {
2576 Some(section) => section,
2577 None => {
2578 return Err(AssemblerError::AssemblingError {
2579 msg: format!("Section '{}' does not exists", name)
2580 });
2581 }
2582 };
2583
2584 let (output_adr, code_adr, mmr, warning) = {
2585 let section = section.read().unwrap();
2586
2587 let warning = if section.mmr != self.ga_mmr {
2588 Some(AssemblerError::AssemblingError {
2589 msg: format!(
2590 "Gate Array configuration is not coherent with the section. We manually set it (0x{:x} expected instead of 0x{:x})",
2591 section.mmr, self.ga_mmr
2592 )
2593 })
2594 }
2595 else {
2596 None
2597 };
2598
2599 (section.output_adr, section.code_adr, section.mmr, warning)
2600 };
2601
2602 self.current_section = Some(Arc::clone(section));
2603
2604 self.ga_mmr = mmr;
2605 self.output_address = output_adr;
2606
2607 self.active_page_info_mut().logical_outputadr = output_adr;
2608 self.active_page_info_mut().logical_codeadr = code_adr;
2609
2610 self.update_dollar();
2611 if let Some(o) = self.output_trigger.as_mut() {
2612 o.replace_code_address(&code_adr.into())
2613 }
2614
2615 if let Some(warning) = warning {
2616 self.add_warning(warning);
2617 }
2618
2619 Ok(())
2620 }
2621
2622 fn visit_range<E: ExprEvaluationExt, S: SourceString>(
2623 &mut self,
2624 name: S,
2625 start: &E,
2626 stop: &E
2627 ) -> Result<(), AssemblerError> {
2628 let start = self.resolve_expr_must_never_fail(start)?.int()? as u16;
2629 let stop = self.resolve_expr_must_never_fail(stop)?.int()? as u16;
2630 let mmr = self.ga_mmr;
2631
2632 if let Some(section) = self.sections.get(name.as_str()) {
2633 let section = section.read().unwrap();
2634 if start != section.start
2635 || stop != section.stop
2636 || name.as_str() != section.name
2637 || mmr != section.mmr
2638 {
2639 return Err(AssemblerError::AssemblingError {
2640 msg: format!(
2641 "Section '{}' is already defined from 0x{:x} to 0x{:x} in 0x{:x}",
2642 section.name, section.start, section.stop, section.mmr
2643 )
2644 });
2645 }
2646 }
2647 else {
2648 let section = Arc::new(RwLock::new(Section::new(name.as_str(), start, stop, mmr)));
2649
2650 self.sections.insert(name.as_str().to_owned(), section);
2651 }
2652
2653 Ok(())
2654 }
2655
2656 fn visit_next_and_co<
2657 E: ExprElement + ExprEvaluationExt,
2658 S1: SourceString + MayHaveSpan,
2659 S2: SourceString
2660 >(
2661 &mut self,
2662 destination: S1,
2663 source: S2,
2664 delta: Option<&E>,
2665 can_override: bool
2666 ) -> Result<(), AssemblerError> {
2667 if !can_override
2668 && self.symbols.contains_symbol(destination.as_str())?
2669 && self.pass.is_first_pass()
2670 {
2671 let kind = self.symbols().kind(Symbol::from(destination.as_str()))?;
2672 return Err(AssemblerError::AlreadyDefinedSymbol {
2673 symbol: destination.as_str().into(),
2674 kind: kind.into(),
2675 here: None
2676 });
2677 }
2678
2679 let value = self.resolve_expr_must_never_fail(&Expr::Label(source.as_str().into()))?;
2681 if can_override {
2682 self.symbols_mut()
2683 .assign_symbol_to_value(destination.as_str(), value.clone())?;
2684 }
2685 else {
2686 self.add_symbol_to_symbol_table(
2687 destination.as_str(),
2688 value.clone(),
2689 destination.possible_span().map(|s| s.into())
2690 )?;
2691 }
2692 if let Some(o) = self.output_trigger.as_mut() {
2693 o.replace_code_address(&value)
2694 }
2695
2696 let delta = match delta {
2698 Some(delta) => self.resolve_expr_must_never_fail(delta)?,
2699 None => 1.into()
2700 };
2701 let value = (value + delta)?;
2702
2703 self.symbols_mut()
2704 .assign_symbol_to_value(source.as_str(), value)?;
2705
2706 Ok(())
2707 }
2708
2709 pub fn logical_to_physical_address(&self, address: u16) -> PhysicalAddress {
2712 match self.output_kind() {
2713 OutputKind::Snapshot => MemoryPhysicalAddress::new(address, self.ga_mmr).into(),
2714 OutputKind::Cpr => {
2715 CprPhysicalAddress::new(
2716 address,
2717 self.cpr.as_ref().unwrap().selected_bloc().unwrap()
2718 )
2719 .into()
2720 },
2721 OutputKind::FreeBank => {
2722 BankPhysicalAddress::new(address, self.free_banks.selected_index().unwrap()).into()
2723 },
2724 }
2725 }
2726
2727 fn visit_skip<E: ExprEvaluationExt>(&mut self, exp: &E) -> Result<(), AssemblerError> {
2728 let amount = self.resolve_expr_must_never_fail(exp)?.int()?;
2729
2730 let amount = amount as u16;
2735
2736 let codeaddr = self
2737 .active_page_info()
2738 .logical_codeadr
2739 .wrapping_add(amount as _);
2740 let outputadr = self
2741 .active_page_info()
2742 .logical_outputadr
2743 .wrapping_add(amount as _);
2744
2745 self.active_page_info_mut().logical_codeadr = codeaddr;
2746 self.active_page_info_mut().logical_outputadr = outputadr;
2747
2748 self.update_dollar();
2749 self.output_address = outputadr;
2750 Ok(())
2751 }
2752
2753 fn visit_page_or_bank<E: ExprEvaluationExt>(
2755 &mut self,
2756 exp: Option<&E>
2757 ) -> Result<(), AssemblerError> {
2758 if self.nested_rorg > 0 {
2759 return Err(AssemblerError::NotAllowed);
2760 }
2761
2762 let output_kind = self.output_kind();
2763
2764 match exp {
2765 Some(exp) => {
2766 let exp = self.resolve_expr_must_never_fail(exp)?.int()?;
2768 self.free_banks.selected_index = None;
2769
2770 if output_kind == OutputKind::Cpr {
2771 if !(0..=31).contains(&exp) {
2772 return Err(AssemblerError::AssemblingError {
2773 msg: format!("Value {exp} is not compatible. [0-31]")
2774 });
2775 }
2776
2777 if let Some(cpr) = &mut self.cpr {
2778 cpr.select(exp as u8);
2779
2780 let page_info = self.active_page_info_mut();
2781 page_info.logical_outputadr = 0;
2782 page_info.logical_codeadr = 0;
2783 self.ga_mmr = 0xC0;
2784 self.output_address = 0
2785 }
2786 }
2787 else {
2788 let mmr = exp;
2791 if !(0xC0..=0xC7).contains(&mmr) {
2792 return Err(AssemblerError::MMRError { value: mmr });
2793 }
2794
2795 let mmr = mmr as u8;
2796 self.ga_mmr = mmr;
2797
2798 if mmr >= 0xC4 && self.sna.pages_info.len() < 2 {
2800 self.sna.resize(2.max(self.sna.pages_info.len()));
2801 }
2802
2803 }
2805 },
2806 None => {
2807 if output_kind == OutputKind::Cpr {
2808 todo!("Need to implement this behavior")
2809 }
2810
2811 if self.pass.is_first_pass() {
2813 self.free_banks.add_new_and_select();
2814 }
2815 else {
2816 self.free_banks.select_next()?;
2817 }
2818
2819 self.ga_mmr = 0xC0;
2820 self.output_address = 0;
2821 let page_info = self.active_page_info_mut();
2822 page_info.logical_outputadr = 0;
2823 page_info.logical_codeadr = 0;
2824 }
2825 }
2826
2827 Ok(())
2828 }
2829
2830 fn visit_pageset<E: ExprEvaluationExt>(&mut self, exp: &E) -> Result<(), AssemblerError> {
2832 if self.nested_rorg > 0 {
2833 return Err(AssemblerError::NotAllowed);
2834 }
2835
2836 let page = self.resolve_expr_must_never_fail(exp)?.int()? as u8; self.select_page(page)?;
2840 Ok(())
2841 }
2842
2843 fn select_page(&mut self, page: u8) -> Result<(), AssemblerError> {
2844 if self.nested_rorg > 0 {
2845 return Err(AssemblerError::NotAllowed);
2846 }
2847
2848 if
2849 page >= 8 {
2851 return Err(AssemblerError::InvalidArgument {
2852 msg: format!(
2853 "{} is invalid. BANKSET only accept values from 0 to 7",
2854 page
2855 )
2856 });
2857 }
2858
2859 if page == 0 {
2860 self.ga_mmr = 0b1100_0000;
2861 }
2862 else {
2863 self.ga_mmr = 0b1100_0010 + ((page - 1) << 3);
2864 }
2865
2866 let page = page as usize;
2867 let expected_nb_pages = self.sna.pages_info.len().max(page + 1);
2868 if expected_nb_pages > self.sna.pages_info.len() {
2869 self.sna.resize(expected_nb_pages);
2870 }
2871 debug_assert_eq!(self.sna.pages_info.len(), expected_nb_pages);
2872
2873 self.output_address = self.logical_output_address();
2874 self.update_dollar();
2875 Ok(())
2876 }
2877
2878 pub fn visit_undef<S: SourceString>(&mut self, label: S) -> Result<(), AssemblerError> {
2880 match self.symbols_mut().remove_symbol(label.as_str())? {
2881 Some(_) => Ok(()),
2882 None => {
2883 Err(AssemblerError::UnknownSymbol {
2884 symbol: label.as_str().into(),
2885 closest: self
2886 .symbols()
2887 .closest_symbol(label.as_str(), SymbolFor::Number)?
2888 })
2889 },
2890 }
2891 }
2892
2893 pub fn visit_protect<E: ExprEvaluationExt>(
2894 &mut self,
2895 start: &E,
2896 stop: &E
2897 ) -> Result<(), AssemblerError> {
2898 if self.pass.is_first_pass() {
2899 let start = self.resolve_expr_must_never_fail(start)?.int()? as u16;
2900 let stop = self.resolve_expr_must_never_fail(stop)?.int()? as u16;
2901
2902 self.active_page_info_mut()
2903 .protected_areas
2904 .push(start..=stop);
2905 }
2906
2907 Ok(())
2908 }
2909
2910 #[inline]
2911 fn prepropress_string_formatted_expression(
2912 &mut self,
2913 info: &[FormattedExpr]
2914 ) -> Result<PreprocessedFormattedString, AssemblerError> {
2915 PreprocessedFormattedString::try_new(info, self)
2916 }
2917
2918 pub fn visit_print(&mut self, info: &[FormattedExpr], span: Option<&Z80Span>) {
2920 let print_or_error = match self.prepropress_string_formatted_expression(info) {
2921 Ok(msg) => either::Either::Left(msg),
2922 Err(error) => either::Either::Right(error)
2923 };
2924
2925 self.active_page_info_mut().add_print_command(PrintCommand {
2926 prefix: None,
2927 span: span.cloned(),
2928 print_or_error
2929 })
2930 }
2931
2932 pub fn visit_pause(&mut self, span: Option<&Z80Span>) {
2933 self.active_page_info_mut()
2934 .add_pause_command(span.cloned().into());
2935 }
2936
2937 pub fn visit_fail(&mut self, info: Option<&[FormattedExpr]>) -> Result<(), AssemblerError> {
2938 let repr = info
2939 .map(|info| self.prepropress_string_formatted_expression(info))
2940 .unwrap_or_else(|| Ok(Default::default()))?;
2941 Err(AssemblerError::Fail {
2942 msg: repr.to_string()
2943 })
2944 }
2945
2946 pub fn visit_save<E: ExprEvaluationExt + Debug>(
2948 &mut self,
2949 amsdos_fname: &E,
2950 address: Option<&E>,
2951 size: Option<&E>,
2952 save_type: Option<&SaveType>,
2953 dsk_fname: Option<&E>,
2954 _side: Option<&E>
2955 ) -> Result<(), AssemblerError> {
2956 if cfg!(target_arch = "wasm32") {
2957 return Err(AssemblerError::AssemblingError {
2958 msg: "SAVE directive is not allowed in a web-based assembling.".to_owned()
2959 });
2960 }
2961
2962 let from = match address {
2963 Some(address) => {
2964 let address = self.resolve_expr_must_never_fail(address)?.int()?;
2965 if address < 0 {
2966 return Err(AssemblerError::AssemblingError {
2967 msg: format!(
2968 "Cannot SAVE {amsdos_fname} as the address ({address}) is invalid."
2969 )
2970 });
2971 }
2972 Some(address)
2973 },
2974 None => None
2975 };
2976
2977 let size = match size {
2978 Some(size) => {
2979 let size = self.resolve_expr_must_never_fail(size)?.int()?;
2980 if size < 0 {
2981 return Err(AssemblerError::AssemblingError {
2982 msg: format!("Cannot SAVE {amsdos_fname} as the size ({size}) is invalid.")
2983 });
2984 }
2985 Some(size)
2986 },
2987 None => None
2988 };
2989
2990 if let Some(from) = &from {
2991 if let Some(size) = &size {
2992 if 0x10000 - *from < *size {
2993 return Err(AssemblerError::AssemblingError {
2994 msg: format!(
2995 "Cannot SAVE {amsdos_fname} as the address+size ({}) is out of bounds.",
2996 *from + *size
2997 )
2998 });
2999 }
3000 }
3001 }
3002
3003 let amsdos_fname = self.build_fname(amsdos_fname)?;
3004 let any_fname: AnyFileNameOwned = match dsk_fname {
3005 Some(dsk_fname) => {
3006 AnyFileNameOwned::new_in_image(self.build_fname(dsk_fname)?, amsdos_fname)
3007 },
3008 None => AnyFileNameOwned::from(amsdos_fname.as_str())
3009 };
3010 let any_fname = any_fname.as_any_filename();
3011
3012 let (amsdos_fname, dsk_fname) = (any_fname.content_filename(), any_fname.image_filename());
3013
3014 let amsdos_fname = Utf8PathBuf::from(amsdos_fname);
3015 let dsk_fname = dsk_fname.map(Utf8PathBuf::from);
3016
3017 if let Some(SaveType::Disc(disc)) = &save_type {
3019 let dsk_fname = dsk_fname.as_ref().unwrap();
3020 let lower_fname = dsk_fname.as_str().to_ascii_lowercase();
3021 match disc {
3022 DiscType::Dsk => {
3023 if !(lower_fname.ends_with(".dsk") || lower_fname.ends_with(".edsk")) {
3024 return Err(AssemblerError::InvalidArgument {
3025 msg: format!("{dsk_fname} has not a DSK compatible extension")
3026 });
3027 }
3028 },
3029 DiscType::Hfe => {
3030 if !lower_fname.ends_with(".hfe") {
3031 return Err(AssemblerError::InvalidArgument {
3032 msg: format!("{dsk_fname} has not a HFE compatible extension")
3033 });
3034 }
3035
3036 #[cfg(not(feature = "hfe"))]
3037 Err(AssemblerError::InvalidArgument {
3038 msg: format!(
3039 "{dsk_fname} cannot be saved. No HFE support is included with this version of basm"
3040 )
3041 })?
3042 },
3043 DiscType::Auto => {
3044 if !(lower_fname.ends_with(".dsk")
3045 || lower_fname.ends_with(".edsk")
3046 || lower_fname.ends_with(".hfe"))
3047 {
3048 return Err(AssemblerError::InvalidArgument {
3049 msg: format!("{dsk_fname} has not a DSK or HFE compatible extension")
3050 });
3051 }
3052
3053 #[cfg(not(feature = "hfe"))]
3054 if lower_fname.ends_with(".hfe") {
3055 Err(AssemblerError::InvalidArgument {
3056 msg: format!(
3057 "{dsk_fname} cannot be saved. No HFE support is included with this version of basm"
3058 )
3059 })?
3060 }
3061 }
3062 }
3063 }
3064
3065 let file = match (save_type, dsk_fname, amsdos_fname) {
3066 (Some(save_type), Some(dsk_fname), amsdos_fname) => {
3067 let support = match save_type {
3068 SaveType::Disc(_) => StorageSupport::Disc(dsk_fname),
3069 SaveType::Tape => StorageSupport::Tape(dsk_fname),
3070 _ => StorageSupport::Disc(dsk_fname)
3071 };
3072 let file_type = match save_type {
3073 SaveType::AmsdosBas => FileType::AmsdosBas,
3074 SaveType::AmsdosBin => FileType::AmsdosBin,
3075 SaveType::Ascii => FileType::Ascii,
3076 SaveType::Disc(_) | SaveType::Tape => FileType::Auto };
3078 SaveFile::new(support, (file_type, amsdos_fname))
3079 },
3080 (None, Some(dsk_fname), amsdos_fname) => {
3081 SaveFile::new(
3082 StorageSupport::Disc(dsk_fname),
3083 (FileType::Auto, amsdos_fname)
3084 )
3085 },
3086 (Some(save_type), None, amsdos_fname) => {
3087 let file_type = match save_type {
3088 SaveType::AmsdosBas => FileType::AmsdosBas,
3089 SaveType::AmsdosBin => FileType::AmsdosBin,
3090 SaveType::Ascii => FileType::Ascii,
3091 SaveType::Disc(_) | SaveType::Tape => {
3092 unimplemented!("Handle the error message");
3093 }
3094 };
3095 SaveFile::new(StorageSupport::Host, (file_type, amsdos_fname))
3096 },
3097 (None, None, amsdos_fname) => {
3098 SaveFile::new(StorageSupport::Host, (FileType::Ascii, amsdos_fname))
3099 },
3100 (a, b, c) => unimplemented!("{a:?} {b:?} {c:?}")
3101 };
3102
3103 let mmr = self.ga_mmr;
3105 let page_info = self.active_page_info_mut();
3106 page_info.add_save_command(SaveCommand::new(from, size, file, mmr));
3107
3108 Ok(())
3109 }
3110
3111 pub fn visit_charset(&mut self, format: &CharsetFormat) -> Result<(), AssemblerError> {
3112 let mut new_charset = CharsetEncoding::new();
3113 std::mem::swap(&mut new_charset, &mut self.charset_encoding);
3114 new_charset.update(format, self)?;
3115 std::mem::swap(&mut new_charset, &mut self.charset_encoding); Ok(())
3117 }
3118
3119 pub fn visit_snainit<E: ExprEvaluationExt + Debug>(
3120 &mut self,
3121 fname: &E
3122 ) -> Result<(), AssemblerError> {
3123 let fname = self.build_fname(fname)?;
3124
3125 if !self.pass.is_first_pass() {
3126 return Ok(());
3127 }
3128
3129 if self.byte_written {
3130 return Err(AssemblerError::AssemblingError {
3131 msg: format!(
3132 "Some bytes has already been produced; you cannot import the snapshot {}.",
3133 fname
3134 )
3135 });
3136 }
3137 self.sna.sna = Snapshot::load(fname).map_err(|e| {
3138 AssemblerError::AssemblingError {
3139 msg: format!("Error while loading snapshot. {}", e)
3140 }
3141 })?;
3142
3143 self.sna.unwrap_memory_chunks();
3144
3145 Ok(())
3146 }
3147
3148 pub fn visit_snaset(
3149 &mut self,
3150 flag: &cpclib_sna::SnapshotFlag,
3151 value: &cpclib_sna::FlagValue
3152 ) -> Result<(), AssemblerError> {
3153 self.sna
3154 .set_value(*flag, value.as_u16().unwrap())
3155 .map_err(|e| e.into())
3156 }
3157
3158 pub fn visit_incbin(&mut self, data: &[u8]) -> Result<(), AssemblerError> {
3159 self.output_bytes(data)
3160 }
3161
3162 fn build_crunched_section_env(&mut self, span: Option<&Z80Span>) -> Self {
3163 let mut crunched_env = self.clone();
3164 crunched_env.crunched_section_state = CrunchedSectionState::new(span.cloned()).into();
3165 crunched_env.active_page_info_mut().logical_outputadr = 0;
3167 crunched_env.active_page_info_mut().startadr = None; crunched_env.active_page_info_mut().maxadr = 0;
3169 crunched_env.active_page_info_mut().output_limit = 0xFFFF; crunched_env.active_page_info_mut().protected_areas.clear(); crunched_env.output_address = 0;
3172
3173 crunched_env
3174 }
3175
3176 pub fn visit_crunched_section<'tokens, T: Visited + ListingElement + MayHaveSpan + Sync>(
3179 &mut self,
3180 kind: &CrunchType,
3181 lst: &mut [ProcessedToken<'tokens, T>],
3182 previous_bytes: &mut Option<Vec<u8>>,
3183 previous_crunched_bytes: &mut Option<Vec<u8>>,
3184 span: Option<&Z80Span>
3185 ) -> Result<(), AssemblerError>
3186 where
3187 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3188 ProcessedToken<'tokens, T>: FunctionBuilder,
3189 <<T as cpclib_tokens::ListingElement>::TestKind as cpclib_tokens::TestKindElement>::Expr:
3190 ExprEvaluationExt
3191 {
3192 let could_display_warning_message = self.active_page_info().output_limit != 0xFFFF
3204 || !self.active_page_info().protected_areas.is_empty();
3205
3206 let mut crunched_env = self.build_crunched_section_env(span);
3211
3212 if let Some(t) = self.output_trigger.as_mut() {
3213 t.enter_crunched_section()
3214 }
3215
3216 visit_processed_tokens(lst, &mut crunched_env).map_err(|e| {
3217 let e = AssemblerError::CrunchedSectionError { error: e.into() };
3218 match span {
3219 Some(span) => {
3220 AssemblerError::RelocatedError {
3221 error: e.into(),
3222 span: span.clone()
3223 }
3224 },
3225 None => e
3226 }
3227 })?;
3228
3229 if let Some(t) = self.output_trigger.as_mut() {
3230 t.leave_crunched_section()
3231 }
3232
3233 let bytes = crunched_env.produced_bytes();
3235
3236 let must_crunch = previous_bytes
3237 .as_ref()
3238 .map(|b| b.as_slice() != bytes.as_slice())
3239 .unwrap_or(true);
3240 if must_crunch {
3241 let crunched: Vec<u8> = if bytes.is_empty() {
3242 Vec::new()
3243 }
3244 else {
3245 kind.crunch(&bytes).map_err(|e| {
3246 match span {
3247 Some(span) => {
3248 AssemblerError::RelocatedError {
3249 error: e.into(),
3250 span: span.clone()
3251 }
3252 },
3253 None => e
3254 }
3255 })?
3256 };
3257 previous_crunched_bytes.replace(crunched);
3258 previous_bytes.replace(bytes);
3259 }
3260
3261 let _bytes = previous_bytes.as_ref().unwrap();
3262 let crunched = previous_crunched_bytes.as_ref().unwrap();
3263
3264 self.visit_incbin(crunched).map_err(|e| {
3266 match span {
3267 Some(span) => {
3268 AssemblerError::RelocatedError {
3269 error: e.into(),
3270 span: span.clone()
3271 }
3272 },
3273 None => e
3274 }
3275 })?;
3276
3277 std::mem::swap(self.symbols_mut(), crunched_env.symbols_mut());
3279 let can_skip_next_passes = *self.can_skip_next_passes.read().unwrap().deref()
3280 & *crunched_env.can_skip_next_passes.read().unwrap(); let request_additional_pass = *self.request_additional_pass.read().unwrap().deref()
3282 | *crunched_env.request_additional_pass.read().unwrap();
3283 *self.can_skip_next_passes.write().unwrap() = can_skip_next_passes;
3284 *self.request_additional_pass.write().unwrap() = request_additional_pass;
3285
3286 self.macro_seed = crunched_env.macro_seed;
3287
3288 if could_display_warning_message {
3292 self.add_warning(
3293 AssemblerWarning::AssemblingError{
3294 msg: "Memory protection systems are disabled in crunched section. If you want to keep them, explicitely use LIMIT or PROTECT directives in the crunched section.".to_owned()
3295 }
3296 );
3297 }
3298
3299 Ok(())
3300 }
3301}
3302
3303impl Env {
3304 fn assemble_nop<E: ExprEvaluationExt>(
3305 &mut self,
3306 kind: Mnemonic,
3307 count: Option<&E>
3308 ) -> Result<Bytes, AssemblerError> {
3309 let count = match count {
3310 Some(count) => self.resolve_expr_must_never_fail(count)?.int()?,
3311 None => 1
3312 };
3313 let mut bytes = Bytes::new();
3314 for _i in 0..count {
3315 match kind {
3316 Mnemonic::Nop => {
3317 bytes.push(0);
3318 },
3319 Mnemonic::Nop2 => {
3320 bytes.push(0xED);
3321 bytes.push(0xFF);
3322 },
3323 _ => unreachable!()
3324 }
3325 }
3326 Ok(bytes)
3327 }
3328}
3329impl Env {
3348 pub fn new(options: EnvOptions) -> Self {
3349 let mut env = Self {
3350 lookup_directory_stack: Vec::with_capacity(3),
3351 pass: AssemblingPass::Uninitialized,
3352 options: EnvOptions::default(),
3353 stable_counters: StableTickerCounters::default(),
3354 ga_mmr: 0xC0, macro_seed: 0,
3357 charset_encoding: CharsetEncoding::new(),
3358 sna: SnaAssembler::default(),
3359 sna_version: cpclib_sna::SnapshotVersion::V3,
3360
3361 cpr: None,
3362
3363 symbols: SymbolsTableCaseDependent::default(),
3364 run_options: None,
3365 byte_written: false,
3366 output_trigger: None,
3367 symbols_output: Default::default(),
3368
3369 crunched_section_state: None,
3370
3371 warnings: Vec::new(),
3372 nested_rorg: 0,
3373
3374 sections: HashMap::<String, Arc<RwLock<Section>>>::default(),
3375 current_section: None,
3376 output_address: 0,
3377 free_banks: DecoratedPages::default(),
3378
3379 real_nb_passes: 0,
3380 saved_files: None,
3381 can_skip_next_passes: true.into(),
3382 request_additional_pass: false.into(),
3383
3384 if_token_adr_to_used_decision: HashMap::default(),
3385 if_token_adr_to_unused_decision: HashMap::default(),
3386 requested_additional_pass: false,
3387
3388 functions: Default::default(),
3389 return_value: None,
3390
3391 current_pass_discarded_errors: HashSet::default(),
3392 previous_pass_discarded_errors: HashSet::default(),
3393
3394 included_paths: HashSet::default(),
3395
3396 extra_print_from_function: Vec::new().into(),
3397 extra_failed_assert_from_function: Vec::new().into(),
3398 map_counter: 0,
3399
3400 repeat_start: 1.into(),
3401 repeat_step: 1.into(),
3402
3403 assembling_control_current_output_commands: Vec::new()
3404 };
3405
3406 env.options = options;
3407
3408 if let Some(sna) = env.options.assemble_options().snapshot_model() {
3410 env.sna.sna = sna.clone();
3411 env.sna_version = env.sna.version();
3412 }
3413
3414 env.symbols = SymbolsTableCaseDependent::new(
3415 env.options().symbols().clone(),
3416 env.options().case_sensitive()
3417 );
3418 env.retrieve_options_symbols();
3419
3420 if let Some(builder) = &env.options().assemble_options().output_builder {
3421 env.output_trigger = ListingOutputTrigger {
3422 token: None,
3423 bytes: Vec::new(),
3424 builder: builder.clone(),
3425 start: 0,
3426 physical_address: MemoryPhysicalAddress::new(0, 0).into()
3427 }
3428 .into();
3429 }
3430 env
3431 }
3432
3433 pub fn pass(&self) -> &AssemblingPass {
3434 &self.pass
3435 }
3436}
3437
3438impl Env {
3440 pub fn visit_return<E: ExprEvaluationExt>(&mut self, e: &E) -> Result<(), AssemblerError> {
3441 debug_assert!(self.return_value.is_none());
3442 self.return_value = Some(self.resolve_expr_must_never_fail(e)?);
3443 Ok(())
3444 }
3445
3446 pub fn user_defined_function(&self, name: &str) -> Result<&Function, AssemblerError> {
3447 match self.functions.get(name) {
3448 Some(f) => Ok(f),
3449 None => Err(AssemblerError::FunctionUnknown(name.to_owned()))
3450 }
3451 }
3452
3453 pub fn any_function<'res>(
3454 &'res self,
3455 name: &'res str
3456 ) -> Result<&'res Function, AssemblerError> {
3457 match HardCodedFunction::by_name(name) {
3458 Some(f) => Ok(f),
3459 None => self.user_defined_function(name)
3460 }
3461 }
3462}
3463
3464pub fn visit_tokens_all_passes_with_options<'token, T>(
3467 tokens: &'token [T],
3468 options: EnvOptions
3469) -> Result<
3470 (Vec<ProcessedToken<'token, T>>, Env),
3471 (Option<Vec<ProcessedToken<'token, T>>>, Env, AssemblerError)
3472>
3473where
3474 T: Visited + ToSimpleToken + Debug + Sync + ListingElement + MayHaveSpan,
3475 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3476 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
3477 ExprEvaluationExt + ExprElement,
3478 ProcessedToken<'token, T>: FunctionBuilder
3479{
3480 let mut env = Env::new(options);
3481
3482 let mut tokens = match processed_token::build_processed_tokens_list(tokens, &mut env) {
3483 Ok(tokens) => tokens,
3484 Err(e) => return Err((None, env, e))
3485 };
3486 loop {
3487 env.start_new_pass();
3488 if env.pass.is_finished() {
3491 break;
3492 }
3493
3494 let res = processed_token::visit_processed_tokens(&mut tokens, &mut env);
3495 if let Err(e) = res {
3496 return Err((Some(tokens), env, e));
3497 }
3498 }
3499
3500 env.cleanup_warnings();
3501
3502 if let Some(trigger) = env.output_trigger.as_mut() {
3503 trigger.finish()
3504 }
3505
3506 Ok((tokens, env))
3507}
3508
3509#[deprecated(note = "use visit_tokens_one_pass")]
3511pub fn visit_tokens<T: Visited>(
3512 tokens: &[T],
3513 o: Arc<dyn EnvEventObserver>
3514) -> Result<Env, AssemblerError> {
3515 visit_tokens_one_pass(tokens, o)
3516}
3517
3518pub fn visit_tokens_one_pass<T: Visited>(
3520 tokens: &[T],
3521 o: Arc<dyn EnvEventObserver>
3522) -> Result<Env, AssemblerError> {
3523 let mut opt = EnvOptions::default();
3524 opt.observer = o;
3525 let mut env = Env::new(opt);
3526
3527 for token in tokens.iter() {
3528 token.visited(&mut env)?;
3529 }
3530
3531 Ok(env)
3532}
3533
3534macro_rules! visit_token_impl {
3535 ($token:ident, $env:ident, $span:ident, $cls:tt) => {{
3536 $env.update_dollar();
3537 match &$token {
3538 $cls::Abyte(d, l) => $env.visit_abyte(d, l.as_ref()),
3539 $cls::Align(boundary, fill) => $env.visit_align(boundary, fill.as_ref()),
3540 $cls::Assert(exp, txt) => {
3541 visit_assert(exp, txt.as_ref(), $env, $span)?;
3542 Ok(())
3543 },
3544 $cls::AssemblerControl(cmd) => $env.visit_assembler_control(cmd, $span),
3545 $cls::Assign { label, expr, op } => $env.visit_assign(label, expr, op.as_ref()),
3546
3547 $cls::Basic(variables, hidden_lines, code) => {
3548 $env.visit_basic(
3549 variables
3550 .as_ref()
3551 .map(|l| l.iter().map(|i| i).collect_vec()),
3552 hidden_lines.as_ref(),
3553 code
3554 )
3555 }, $cls::Bank(exp) => $env.visit_page_or_bank(exp.as_ref()),
3557 $cls::Bankset(v) => $env.visit_pageset(v),
3558 $cls::Breakpoint {
3559 address,
3560 r#type,
3561 access,
3562 run,
3563 mask,
3564 size,
3565 value,
3566 value_mask,
3567 condition,
3568 name,
3569 step
3570 } => {
3571 $env.visit_breakpoint(
3572 address.as_ref(),
3573 r#type.as_ref(),
3574 access.as_ref(),
3575 run.as_ref(),
3576 mask.as_ref(),
3577 size.as_ref(),
3578 value.as_ref(),
3579 value_mask.as_ref(),
3580 condition.as_ref(),
3581 name.as_ref(),
3582 step.as_ref(),
3583 $span
3584 )
3585 },
3586 $cls::BuildCpr => $env.visit_buildcpr(),
3587 $cls::BuildSna(v) => $env.visit_buildsna(v.as_ref()),
3588
3589 $cls::Charset(format) => $env.visit_charset(format),
3590
3591 $cls::Comment(_) => Ok(()), $cls::Defb(l) => $env.visit_db_or_dw_or_str(DbLikeKind::Defb, l.as_ref(), 0.into()),
3594 $cls::Defw(l) => $env.visit_db_or_dw_or_str(DbLikeKind::Defw, l.as_ref(), 0.into()),
3595 $cls::Defs(l) => visit_defs(l, $env),
3596
3597 $cls::End => visit_end($env),
3598 $cls::Export(labels) => $env.visit_export(labels.as_slice()),
3599 $cls::Equ { label, expr } => $env.visit_equ(&label, expr),
3600
3601 $cls::Fail(exp) => $env.visit_fail(exp.as_ref().map(|v| v.as_slice())),
3602 $cls::Field { label, expr, .. } => $env.visit_field(label, expr),
3603
3604 $cls::Label(label) => $env.visit_label(label),
3605 $cls::Limit(exp) => $env.visit_limit(exp),
3606 $cls::List => {
3607 $env.output_trigger.as_mut().map(|l| {
3608 l.on();
3609 });
3610 Ok(())
3611 },
3612
3613 $cls::Map(exp) => $env.visit_map(exp),
3614 $cls::MultiPush(regs) => $env.visit_multi_pushes(regs),
3615 $cls::MultiPop(regs) => $env.visit_multi_pops(regs),
3616
3617 $cls::Next {
3618 label,
3619 source,
3620 expr
3621 } => $env.visit_next_and_co(label, source, expr.as_ref(), false),
3622 $cls::NoExport(labels) => $env.visit_noexport(labels.as_slice()),
3623 $cls::NoList => {
3624 $env.output_trigger.as_mut().map(|l| {
3625 l.off();
3626 });
3627 Ok(())
3628 },
3629
3630 $cls::Org { val1, val2 } => $env.visit_org(val1, val2.as_ref()),
3631 $cls::OpCode(mnemonic, arg1, arg2, arg3) => {
3632 visit_opcode(*mnemonic, &arg1, &arg2, &arg3, $env)?;
3633 if !$env.stable_counters.is_empty() {
3635 let duration = $token.to_token().estimated_duration()?;
3636 $env.stable_counters.update_counters(duration);
3637 }
3638 Ok(())
3639 },
3640
3641 $cls::Pause => {
3642 $env.visit_pause($span);
3643 Ok(())
3644 },
3645 $cls::Protect(start, end) => $env.visit_protect(start, end),
3646 $cls::Print(exp) => {
3647 $env.visit_print(exp.as_ref(), $span);
3648 Ok(())
3649 },
3650
3651 $cls::Range(name, start, stop) => $env.visit_range(name, start, stop),
3652 $cls::Return(exp) => $env.visit_return(exp),
3653
3654 $cls::Rorg(_exp, _code) => panic!("Is delegated to ProcessedToken"),
3655 $cls::Run(address, gate_array) => $env.visit_run(address, gate_array.as_ref()),
3656
3657 $cls::SetN {
3658 label,
3659 source,
3660 expr
3661 } => $env.visit_next_and_co(label, source, expr.as_ref(), true),
3662 $cls::Save {
3663 filename,
3664 address,
3665 size,
3666 save_type,
3667 dsk_filename,
3668 side
3669 } => {
3670 $env.visit_save(
3671 filename,
3672 address.as_ref(),
3673 size.as_ref(),
3674 save_type.as_ref(),
3675 dsk_filename.as_ref(),
3676 side.as_ref()
3677 )
3678 },
3679 $cls::Section(name) => $env.visit_section(name),
3680 $cls::Skip(amount) => $env.visit_skip(amount),
3681 $cls::SnaInit(fname) => $env.visit_snainit(fname),
3682 $cls::SnaSet(flag, value) => $env.visit_snaset(flag, value),
3683 $cls::StableTicker(ticker) => visit_stableticker(ticker, $env),
3684 $cls::StartingIndex { start, step } => {
3685 $env.visit_starting_index(start.as_ref(), step.as_ref())
3686 },
3687 $cls::Str(l) => $env.visit_db_or_dw_or_str(DbLikeKind::Str, l.as_ref(), 0.into()),
3688 $cls::Struct(name, content) => {
3689 $env.visit_struct_definition(name, content.as_slice(), $span)
3690 },
3691
3692 $cls::Undef(label) => $env.visit_undef(label),
3693 $cls::WaitNops(count) => $env.visit_waitnops(count),
3694
3695 $cls::Include(..)
3696 | $cls::Incbin { .. }
3697 | $cls::If(..)
3698 | $cls::Repeat(..)
3699 | $cls::Macro { .. } => panic!("Should be handled by ProcessedToken"),
3700
3701 _ => {
3702 Err(AssemblerError::BugInAssembler {
3703 file: file!(),
3704 line: line!(),
3705 msg: format!("Directive not handled: {:?}", $token)
3706 })
3707 },
3708 }
3709 }};
3710}
3711
3712pub fn visit_located_token(
3715 outer_token: &LocatedToken,
3716 env: &mut Env
3717) -> Result<(), AssemblerError> {
3718 let nb_warnings = env.warnings.len();
3719
3720 let outer_token = unsafe { (outer_token as *const LocatedToken).as_ref().unwrap() };
3722
3723 let span = Some(outer_token.span());
3727
3728 if outer_token.is_warning() {
3730 let warning = AssemblerWarning::AlreadyRenderedError(outer_token.warning_message().into());
3731 let warning = warning.locate(outer_token.span().clone());
3732 env.add_warning(warning);
3733 }
3734
3735 let token = outer_token.deref();
3737
3738 visit_token_impl!(token, env, span, LocatedTokenInner)
3739 .map_err(|e| e.locate(span.unwrap().clone()))?;
3740
3741 let span = outer_token.span();
3742
3743 let nb_additional_warnings = env.warnings.len() - nb_warnings;
3745 for i in 0..nb_additional_warnings {
3746 let warning = &mut env.warnings[i + nb_warnings];
3747 *warning = warning.clone().locate_warning(span.clone());
3748
3749 }
3757
3758 env.move_delayed_commands_of_functions();
3759
3760 Ok(())
3761}
3762
3763fn visit_token(token: &Token, env: &mut Env) -> Result<(), AssemblerError> {
3765 let span = None;
3766 let _res = visit_token_impl!(token, env, span, Token);
3767
3768 env.move_delayed_commands_of_functions();
3769 Ok(())
3770}
3771
3772fn visit_assert<E: ExprEvaluationExt + ExprElement>(
3775 exp: &E,
3776 txt: Option<&Vec<FormattedExpr>>,
3777 env: &mut Env,
3778 span: Option<&Z80Span>
3779) -> Result<bool, AssemblerError> {
3780 if let Some(commands) = env.assembling_control_current_output_commands.last_mut() {
3781 commands.store_assert(exp.to_expr().into_owned(), txt.cloned(), span.cloned());
3782 }
3783
3784 let res = match env.resolve_expr_must_never_fail(exp) {
3785 Err(e) => Err(e),
3786
3787 Ok(value) => {
3788 if !value.bool()? {
3789 Err(AssemblerError::AssertionFailed {
3790 msg: (if txt.is_some() {
3792 env.prepropress_string_formatted_expression(txt.unwrap())?.to_string()
3793 }
3794 else {
3795 "".to_owned()
3796 })
3797 ,
3798 test: exp.to_string(),
3799 guidance: env.to_assert_string(exp)
3800 })
3801 }
3802 else {
3803 Ok(())
3804 }
3805 }
3806 };
3807
3808 if let Err(assert_error) = res {
3809 let assert_error = if let Some(span) = span {
3810 assert_error.locate(span.clone())
3811 }
3812 else {
3813 assert_error
3814 };
3815 env.active_page_info_mut()
3816 .add_failed_assert_command(assert_error.into());
3817 Ok(false)
3818 }
3819 else {
3820 Ok(true)
3821 }
3822}
3823
3824impl Env {
3825 pub fn visit_while<'token, E, T>(
3826 &mut self,
3827 cond: &E,
3828 code: &mut [ProcessedToken<'token, T>],
3829 span: Option<&Z80Span>
3830 ) -> Result<(), AssemblerError>
3831 where
3832 T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
3833 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3834 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
3835 ExprEvaluationExt,
3836 ProcessedToken<'token, T>: FunctionBuilder
3837 {
3838 while self.resolve_expr_must_never_fail(cond)?.bool()? {
3839 visit_processed_tokens(code, self).map_err(|e| {
3841 AssemblerError::WhileIssue {
3842 error: Box::new(e),
3843 span: span.cloned()
3844 }
3845 })?;
3846 }
3847
3848 Ok(())
3849 }
3850
3851 pub fn visit_iterate<
3854 'token,
3855 E: ExprEvaluationExt,
3856 T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync
3857 >(
3858 &mut self,
3859 counter_name: &str,
3860 values: either::Either<&Vec<E>, &E>,
3861 code: &mut [ProcessedToken<'token, T>],
3862 span: Option<&Z80Span>
3863 ) -> Result<(), AssemblerError>
3864 where
3865 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3866 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
3867 ExprEvaluationExt,
3868 ProcessedToken<'token, T>: FunctionBuilder
3869 {
3870 let counter_name = format!("{{{}}}", counter_name);
3871 let counter_name = counter_name.as_str();
3872 if self.symbols().contains_symbol(counter_name)? {
3873 return Err(AssemblerError::RepeatIssue {
3874 error: AssemblerError::ExpressionError(ExpressionError::OwnError(Box::new(
3875 AssemblerError::AssemblingError {
3876 msg: format!("Counter {} already exists", counter_name)
3877 }
3878 )))
3879 .into(),
3880 span: span.cloned(),
3881 repetition: 0
3882 });
3883 }
3884
3885 match values {
3888 either::Either::Left(values) => {
3889 for (i, value) in values.iter().enumerate() {
3890 let counter_value = self.resolve_expr_must_never_fail(value).map_err(|e| {
3891 AssemblerError::RepeatIssue {
3892 error: Box::new(e),
3893 span: span.cloned(),
3894 repetition: i as _
3895 }
3896 })?;
3897 self.inner_visit_repeat(
3898 Some(counter_name),
3899 Some(counter_value),
3900 i as _,
3901 code,
3902 span
3903 )?;
3904 }
3905 },
3906 either::Either::Right(values) => {
3907 match self.resolve_expr_must_never_fail(values)? {
3908 ExprResult::List(values) => {
3909 for (i, counter_value) in values.into_iter().enumerate() {
3910 self.inner_visit_repeat(
3911 Some(counter_name),
3912 Some(counter_value),
3913 i as _,
3914 code,
3915 span
3916 )?;
3917 }
3918 },
3919 _ => {
3920 return Err(AssemblerError::AssemblingError {
3921 msg: format!("REPEAT issue: {} is not a list", values)
3922 });
3923 }
3924 }
3925 },
3926 }
3927
3928 self.symbols_mut().remove_symbol(counter_name)?;
3932
3933 Ok(())
3934 }
3935
3936 pub fn visit_rorg<'token, T, E>(
3937 &mut self,
3938 address: &E,
3939 code: &mut [ProcessedToken<'token, T>],
3940 span: Option<&Z80Span>
3941 ) -> Result<(), AssemblerError>
3942 where
3943 E: ExprEvaluationExt,
3944 T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
3945 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3946 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
3947 ExprEvaluationExt,
3948 ProcessedToken<'token, T>: FunctionBuilder
3949 {
3950 let address = self
3952 .resolve_expr_must_never_fail(address)
3953 .map_err(|error| {
3954 match span {
3955 Some(span) => {
3956 AssemblerError::RelocatedError {
3957 error: Box::new(error),
3958 span: span.clone()
3959 }
3960 },
3961 None => error
3962 }
3963 })?
3964 .int()?;
3965
3966 {
3968 let page_info = self.active_page_info_mut();
3969 page_info.logical_codeadr = address as _;
3970 }
3971
3972 self.update_dollar();
3973 let value = self.active_page_info_mut().logical_codeadr;
3974
3975 if let Some(o) = self.output_trigger.as_mut() {
3976 o.replace_code_address(&value.into())
3977 }
3978
3979 self.nested_rorg += 1; visit_processed_tokens(code, self)?;
3982 self.nested_rorg -= 1;
3983
3984 let page_info = self.active_page_info_mut();
3986 page_info.logical_codeadr = page_info.logical_outputadr;
3987
3988 Ok(())
3989 }
3990
3991 pub fn visit_confined<'token, E: ExprEvaluationExt, T>(
3992 &mut self,
3993 lst: &mut [ProcessedToken<'token, T>],
3994 span: Option<&Z80Span>
3995 ) -> Result<(), AssemblerError>
3996 where
3997 T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
3998 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
3999 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
4000 ExprEvaluationExt,
4001 ProcessedToken<'token, T>: FunctionBuilder
4002 {
4003 let mut confined_env = self.clone();
4006 confined_env.active_page_info_mut().logical_outputadr = 0;
4007 confined_env.active_page_info_mut().startadr = None; confined_env.active_page_info_mut().maxadr = 0;
4009 confined_env.active_page_info_mut().output_limit = 0xFFFF; confined_env.active_page_info_mut().protected_areas.clear(); confined_env.output_address = 0;
4012 visit_processed_tokens(lst, &mut confined_env).map_err(|e| {
4014 panic!("{:?}", e);
4015 match span {
4016 Some(span) => e.locate(span.clone()),
4017 None => e
4018 }
4019 })?;
4020
4021 let bytes = confined_env.produced_bytes();
4023 let bytes_len = bytes.len() as u16;
4024
4025 if bytes_len > 256 {
4026 let e = AssemblerError::AssemblingError {
4027 msg: format!(
4028 "CONFINED error: content uses {} bytes instead of a maximum of 256.",
4029 bytes.len()
4030 )
4031 };
4032 match span {
4033 Some(span) => return Err(e.locate(span.clone())),
4034 None => return Err(e)
4035 }
4036 }
4037
4038 if ((self.logical_code_address().wrapping_add(bytes_len)) & 0xFF00)
4040 != self.logical_code_address() & 0xFF00
4041 {
4042 while (self.logical_code_address() & 0x00FF) != 0x0000 {
4043 self.output_byte(0)?;
4044 self.update_dollar();
4045 }
4046 }
4047
4048 visit_processed_tokens(lst, self)
4049 }
4050
4051 pub fn visit_for<'token, E: ExprEvaluationExt, T>(
4053 &mut self,
4054 label: &str,
4055 start: &E,
4056 stop: &E,
4057 step: Option<&E>,
4058 code: &mut [ProcessedToken<'token, T>],
4059 span: Option<&Z80Span>
4060 ) -> Result<(), AssemblerError>
4061 where
4062 T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
4063 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
4064 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
4065 ExprEvaluationExt,
4066 ProcessedToken<'token, T>: FunctionBuilder
4067 {
4068 let counter_name = format!("{{{}}}", label);
4069 if self.symbols().contains_symbol(&counter_name)? {
4070 return Err(AssemblerError::ForIssue {
4071 error: AssemblerError::ExpressionError(ExpressionError::OwnError(Box::new(
4072 AssemblerError::AssemblingError {
4073 msg: format!("Counter {} already exists", &counter_name)
4074 }
4075 )))
4076 .into(),
4077 span: span.cloned()
4078 });
4079 }
4080
4081 let mut counter_value = self.resolve_expr_must_never_fail(start)?;
4082 let stop = self.resolve_expr_must_never_fail(stop)?;
4083 let step = match step {
4084 Some(step) => self.resolve_expr_must_never_fail(step)?,
4085 None => 1i32.into()
4086 };
4087
4088 let zero = ExprResult::from(0i32);
4089
4090 if step == zero {
4091 return Err(AssemblerError::ForIssue {
4092 error: AssemblerError::ExpressionError(ExpressionError::OwnError(Box::new(
4093 AssemblerError::AssemblingError {
4094 msg: "Infinite loop".to_string()
4095 }
4096 )))
4097 .into(),
4098 span: span.cloned()
4099 });
4100 }
4101
4102 if step < zero {
4103 return Err(AssemblerError::ForIssue {
4104 error: AssemblerError::ExpressionError(ExpressionError::OwnError(Box::new(
4105 AssemblerError::AssemblingError {
4106 msg: "Negative step is not yet handled".to_string()
4107 }
4108 )))
4109 .into(),
4110 span: span.cloned()
4111 });
4112 }
4113
4114 let mut i = 1;
4115 while counter_value <= stop {
4116 self.inner_visit_repeat(
4117 Some(counter_name.as_str()),
4118 Some(counter_value.clone()),
4119 i as _,
4120 code,
4121 span
4122 )?;
4123 counter_value = (counter_value + &step)?;
4124 i += 1;
4125 }
4126
4127 self.symbols_mut().remove_symbol(counter_name)?;
4128
4129 Ok(())
4130 }
4131
4132 pub fn visit_repeat_until<'token, E, T>(
4134 &mut self,
4135 cond: &E,
4136 code: &mut [ProcessedToken<'token, T>],
4137 span: Option<&Z80Span>
4138 ) -> Result<(), AssemblerError>
4139 where
4140 E: ExprEvaluationExt,
4141 T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
4142 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
4143 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
4144 ExprEvaluationExt,
4145 ProcessedToken<'token, T>: FunctionBuilder
4146 {
4147 let mut i = 0;
4148 loop {
4149 i += 1;
4150 self.inner_visit_repeat(None, None, i as _, code, span)?;
4151 let res = self.resolve_expr_must_never_fail(cond)?;
4152 if res.bool()? {
4153 break;
4154 }
4155 }
4156
4157 Ok(())
4158 }
4159
4160 pub fn visit_starting_index<E>(
4161 &mut self,
4162 start: Option<&E>,
4163 step: Option<&E>
4164 ) -> Result<(), AssemblerError>
4165 where
4166 E: ExprEvaluationExt
4167 {
4168 let start_value = start
4169 .map(|start| self.resolve_expr_must_never_fail(start))
4170 .unwrap_or(Ok(ExprResult::from(1)))?;
4171 let step_value = step
4172 .map(|step| self.resolve_expr_must_never_fail(step))
4173 .unwrap_or(Ok(ExprResult::from(1)))?;
4174
4175 self.repeat_start = start_value;
4176 self.repeat_step = step_value;
4177 Ok(())
4178 }
4179
4180 pub fn visit_repeat_token<'token, T, E>(
4182 &mut self,
4183 opcode: &mut ProcessedToken<'token, T>,
4184 count: &E
4185 ) -> Result<(), AssemblerError>
4186 where
4187 E: ExprEvaluationExt,
4188 T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
4189 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
4190 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
4191 ExprEvaluationExt,
4192 ProcessedToken<'token, T>: FunctionBuilder
4193 {
4194 let repeat = self.resolve_expr_must_never_fail(count)?;
4195 let repeat = repeat.int()?;
4196 for _ in 0..repeat {
4197 opcode.visited(self)?;
4198 }
4199 Ok(())
4200 }
4201
4202 pub fn visit_repeat<'token, T, E>(
4204 &mut self,
4205 count: &E,
4206 code: &mut [ProcessedToken<'token, T>],
4207 counter_name: Option<&str>,
4208 counter_start: Option<&E>,
4209 counter_step: Option<&E>,
4210 span: Option<&Z80Span>
4211 ) -> Result<(), AssemblerError>
4212 where
4213 E: ExprEvaluationExt,
4214 T: ListingElement<Expr = E> + Visited + MayHaveSpan + Sync,
4215 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
4216 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
4217 ExprEvaluationExt,
4218 ProcessedToken<'token, T>: FunctionBuilder
4219 {
4220 let count = self.resolve_expr_must_never_fail(count)?.int()?;
4222
4223 let counter_name = counter_name
4225 .as_ref()
4226 .map(|counter| format!("{{{}}}", counter));
4227 let counter_name = counter_name.as_deref();
4228 if let Some(counter_name) = counter_name {
4229 if self.symbols().contains_symbol(counter_name)? {
4230 return Err(AssemblerError::RepeatIssue {
4231 error: AssemblerError::ExpressionError(ExpressionError::OwnError(Box::new(
4232 AssemblerError::AssemblingError {
4233 msg: format!("Counter {} already exists", counter_name)
4234 }
4235 )))
4236 .into(),
4237 span: span.cloned(),
4238 repetition: 0
4239 });
4240 }
4241 }
4242
4243 let mut counter_value = counter_start
4245 .map(|start| self.resolve_expr_must_never_fail(start))
4246 .unwrap_or(Ok(self.repeat_start.clone()))?; let step_value = counter_step
4248 .map(|step| self.resolve_expr_must_never_fail(step))
4249 .unwrap_or(Ok(self.repeat_step.clone()))?; for i in 0..count {
4252 self.inner_visit_repeat(
4253 counter_name,
4254 Some(counter_value.clone()),
4255 i as _,
4256 code,
4257 span
4258 )?;
4259 counter_value += step_value.clone();
4261 }
4262
4263 if let Some(counter_name) = counter_name {
4264 self.symbols_mut().remove_symbol(counter_name)?;
4265 }
4266 Ok(())
4267 }
4268
4269 fn inner_visit_repeat<'token, T: ListingElement + Visited + MayHaveSpan + Sync>(
4271 &mut self,
4272 counter_name: Option<&str>,
4273 counter_value: Option<ExprResult>,
4274 iteration: i32,
4275 code: &mut [ProcessedToken<'token, T>],
4276 span: Option<&Z80Span>
4277 ) -> Result<(), AssemblerError>
4278 where
4279 <T as cpclib_tokens::ListingElement>::Expr: ExprEvaluationExt + ExprElement,
4280 <<T as cpclib_tokens::ListingElement>::TestKind as TestKindElement>::Expr:
4281 ExprEvaluationExt,
4282 ProcessedToken<'token, T>: FunctionBuilder
4283 {
4284 {
4286 self.macro_seed += 1;
4287 let seed = self.macro_seed;
4288 self.symbols_mut().push_seed(seed);
4289 }
4290
4291 if let Some(counter_name) = counter_name {
4293 self.symbols_mut()
4294 .set_symbol_to_value(counter_name, counter_value.clone().unwrap())?;
4295
4296 if self.pass.is_listing_pass() {
4297 if let Some(trigger) = self.output_trigger.as_mut() {
4298 trigger.repeat_iteration(counter_name, counter_value.as_ref())
4299 }
4300 }
4301 }
4302 else if self.pass.is_listing_pass() {
4303 if let Some(trigger) = self.output_trigger.as_mut() {
4304 trigger.repeat_iteration("<new iteration>", counter_value.as_ref())
4305 }
4306 }
4307
4308 if let Some(counter_value) = &counter_value {
4309 self.symbols_mut().push_counter_value(counter_value.clone());
4310 }
4311
4312 visit_processed_tokens(code, self).map_err(|e| {
4314 let e = if let AssemblerError::RelocatedError {
4315 error: box AssemblerError::UnknownSymbol { closest: _, symbol },
4316 span
4317 } = &e
4318 {
4319 if let Some(counter_name) = counter_name {
4320 if counter_name == &format!("{{{}}}", symbol) {
4321 AssemblerError::RelocatedError {
4322 error: Box::new(AssemblerError::UnknownSymbol {
4323 closest: Some(counter_name.into()),
4324 symbol: symbol.clone()
4325 }),
4326 span: span.clone()
4327 }
4328 }
4329 else {
4330 e
4331 }
4332 }
4333 else {
4334 e
4335 }
4336 }
4337 else {
4338 e
4339 };
4340
4341 AssemblerError::RepeatIssue {
4342 error: Box::new(e),
4343 span: span.cloned(),
4344 repetition: iteration as _
4345 }
4346 })?;
4347
4348 self.symbols_mut().pop_seed();
4350 if let Some(counter_value) = &counter_value {
4351 self.symbols_mut().pop_counter_value();
4352 }
4353
4354 Ok(())
4355 }
4356
4357 fn to_assert_string<E: ExprEvaluationExt + ExprElement>(&mut self, exp: &E) -> String {
4360 let mut format = |oper, left, right| {
4361 format!(
4362 "0x{:x} {} 0x{:x}",
4363 self.resolve_expr_must_never_fail(left).unwrap(),
4364 oper,
4365 self.resolve_expr_must_never_fail(right).unwrap(),
4366 )
4367 };
4368
4369 if exp.is_binary_operation() {
4370 let code = match exp.binary_operation() {
4371 BinaryOperation::Equal => Some("=="),
4372 BinaryOperation::GreaterOrEqual => Some(">="),
4373 BinaryOperation::StrictlyGreater => Some(">"),
4374 BinaryOperation::StrictlyLower => Some("<"),
4375 BinaryOperation::LowerOrEqual => Some("<="),
4376 _ => None
4377 };
4378
4379 match code {
4380 Some(code) => {
4381 let left = exp.arg1();
4382 let right = exp.arg2();
4383 format(code, left, right)
4384 },
4385
4386 None => {
4387 let d = self.resolve_expr_must_never_fail(exp).unwrap();
4388 format!("0x{:x}", d)
4389 }
4390 }
4391 }
4392 else {
4393 let d = self.resolve_expr_must_never_fail(exp).unwrap();
4394 format!("0x{:x}", d)
4395 }
4396 }
4397
4398 fn visit_run<E: ExprEvaluationExt>(
4399 &mut self,
4400 address: &E,
4401 ga: Option<&E>
4402 ) -> Result<(), AssemblerError> {
4403 let address = self.resolve_expr_may_fail_in_first_pass(address)?.int()?;
4404
4405 if let Some(o) = self.output_trigger.as_mut() {
4406 o.replace_code_address(&address.into())
4407 }
4408
4409 if self.run_options.is_some() {
4410 return Err(AssemblerError::RunAlreadySpecified);
4411 }
4412 self.sna
4413 .set_value(cpclib_sna::SnapshotFlag::Z80_PC, address as _)?;
4414
4415 match ga {
4416 None => {
4417 self.run_options = Some((address as _, None));
4418 },
4419 Some(ga_expr) => {
4420 let ga_expr = self.resolve_expr_may_fail_in_first_pass(ga_expr)?.int()?;
4421 self.sna.set_value(SnapshotFlag::GA_RAMCFG, address as _)?;
4422 self.run_options = Some((address as _, Some(ga_expr as _)));
4423 }
4424 }
4425 Ok(())
4426 }
4427}
4428
4429impl Env {
4431 pub fn inc_macro_seed(&mut self) {
4432 self.macro_seed += 1;
4433 }
4434
4435 pub fn macro_seed(&self) -> usize {
4436 self.macro_seed
4437 }
4438}
4439
4440impl Env {
4442 fn merge_overriding_warnings(&mut self) {
4443 let mut current_warning_idx = 1; let mut previous_warning_idx = 0; while current_warning_idx < self.warnings.len() {
4448 let (new_size, new_span) = match (
4450 &self.warnings[previous_warning_idx],
4451 &self.warnings[current_warning_idx]
4452 ) {
4453 (
4455 AssemblerWarning::OverrideMemory(prev_addr, prev_size),
4456 AssemblerWarning::OverrideMemory(curr_addr, curr_size)
4457 ) => {
4458 if (prev_addr.offset_in_cpc() + *prev_size as u32) == curr_addr.offset_in_cpc()
4459 {
4460 (Some(*prev_size + *curr_size), None)
4461 }
4462 else {
4463 (None, None)
4464 }
4465 },
4466
4467 (
4468 AssemblerError::RelocatedWarning {
4469 warning: box AssemblerWarning::OverrideMemory(prev_addr, prev_size),
4470 span: prev_span
4471 },
4472 AssemblerError::RelocatedWarning {
4473 warning: box AssemblerWarning::OverrideMemory(curr_addr, curr_size),
4474 span: curr_span
4475 }
4476 ) => {
4477 if (prev_addr.offset_in_cpc() + *prev_size as u32 == curr_addr.offset_in_cpc())
4478 && std::ptr::eq(
4479 prev_span.complete_source().as_ptr(),
4480 curr_span.complete_source().as_ptr()
4481 )
4482 {
4483 let new_size = *prev_size + *curr_size;
4484
4485 let start_str = prev_span.as_str();
4486 let end_str = curr_span.as_str();
4487 let start_str = start_str.as_bytes();
4488 let end_str = end_str.as_bytes();
4489
4490 let start_ptr = &start_str[0] as *const u8;
4491 let end_last_ptr = &end_str[end_str.len() - 1] as *const u8;
4492 assert!(end_last_ptr > start_ptr);
4493 let txt = unsafe {
4494 let slice = std::slice::from_raw_parts(
4495 start_ptr,
4496 end_last_ptr.offset_from(start_ptr) as _
4497 );
4498 std::str::from_utf8(slice).unwrap()
4499 };
4500
4501 let new_span = Z80Span::from(prev_span.0.update_slice(txt.as_bytes()));
4502
4503 (Some(new_size), Some(new_span))
4504 }
4505 else {
4506 (None, None)
4507 }
4508 },
4509
4510 _ => {
4511 (None, None)
4513 }
4514 };
4515
4516 if let Some(new_size) = new_size {
4517 if let Some(new_span) = new_span {
4518 if let AssemblerError::RelocatedWarning {
4519 warning: box AssemblerWarning::OverrideMemory(_prev_addr, prev_size),
4520 span
4521 } = &mut self.warnings[previous_warning_idx]
4522 {
4523 *prev_size = new_size;
4524 *span = new_span;
4525 }
4526 }
4527 else if let AssemblerWarning::OverrideMemory(_prev_addr, prev_size) =
4528 &mut self.warnings[previous_warning_idx]
4529 {
4530 *prev_size = new_size;
4531 }
4532 }
4533 else {
4534 previous_warning_idx += 1;
4535 if previous_warning_idx != current_warning_idx {
4536 self.warnings
4537 .swap(previous_warning_idx, current_warning_idx);
4538 }
4539 }
4540
4541 current_warning_idx += 1;
4542 }
4543 self.warnings.truncate(previous_warning_idx + 1);
4545 }
4546
4547 fn render_warnings(&mut self) {
4548 self.warnings.iter_mut().for_each(|w| {
4550 if let AssemblerError::AssemblingError { .. } = w {
4551 }
4553 else {
4554 *w = AssemblerWarning::AssemblingError {
4555 msg: (*w).to_string()
4556 }
4557 }
4558 });
4559 }
4560
4561 pub fn cleanup_warnings(&mut self) {
4562 if !self.options().assemble_options().enable_warnings {
4563 debug_assert!(self.warnings.is_empty());
4564 return;
4565 }
4566
4567 self.merge_overriding_warnings();
4568 self.render_warnings();
4569 }
4570}
4571
4572impl Env {
4573 fn visit_equ<E: ExprEvaluationExt + ExprElement + Debug, S: SourceString + MayHaveSpan>(
4574 &mut self,
4575 label_span: &S,
4576 exp: &E
4577 ) -> Result<(), AssemblerError> {
4578 if self.symbols().contains_symbol(label_span.as_str())? && self.pass.is_first_pass() {
4579 Err(AssemblerError::AlreadyDefinedSymbol {
4580 symbol: label_span.as_str().into(),
4581 kind: self.symbols().kind(label_span.as_str())?.into(),
4582 here: label_span.possible_span().map(|s| s.into())
4583 })
4584 }
4585 else {
4586 let label = self.handle_global_and_local_labels(label_span.as_str())?;
4587
4588 if label.starts_with(".") {
4589 let warning = AssemblerError::AssemblingError {
4590 msg: format!(
4591 "{} is not a local label. A better name without the dot would be better",
4592 &label
4593 )
4594 };
4595 let warning = AssemblerWarning::AssemblingError {
4596 msg: warning.to_string()
4597 };
4598 self.add_warning(warning);
4599 }
4600
4601 let value = self.resolve_expr_may_fail_in_first_pass(exp)?;
4606 if let Some(o) = self.output_trigger.as_mut() {
4607 o.replace_code_address(&value)
4608 }
4609 self.add_symbol_to_symbol_table(
4610 label,
4611 value,
4612 label_span.possible_span().map(|s| s.into())
4613 )
4614 }
4615 }
4616
4617 fn visit_field<
4618 E: ExprEvaluationExt + ExprElement + Debug + MayHaveSpan,
4619 S: SourceString + MayHaveSpan
4620 >(
4621 &mut self,
4622 label_span: S,
4623 exp: &E
4624 ) -> Result<(), AssemblerError> {
4625 if self.symbols().contains_symbol(label_span.as_str())? && self.pass.is_first_pass() {
4626 Err(AssemblerError::AlreadyDefinedSymbol {
4627 symbol: label_span.as_str().into(),
4628 kind: self.symbols().kind(label_span.as_str())?.into(),
4629 here: None
4630 })
4631 }
4632 else {
4633 let delta = self.resolve_expr_may_fail_in_first_pass(exp)?.int()?;
4634 if delta < 0 {
4635 let mut e = AssemblerError::AlreadyRenderedError(format!(
4636 "FIELD argument must be positive ({delta} is a wrong value)."
4637 ));
4638 if let Some(span) = exp.possible_span() {
4639 e = e.locate(span.clone());
4640 }
4641 return Err(e);
4642 }
4643
4644 let label = self.handle_global_and_local_labels(label_span.as_str())?;
4645 if !label.starts_with('.') {
4646 self.symbols_mut().set_current_label(label)?;
4647 }
4648
4649 let value: ExprResult = self.map_counter.into();
4650 if let Some(o) = self.output_trigger.as_mut() {
4651 o.replace_code_address(&value)
4652 }
4653 self.add_symbol_to_symbol_table(
4654 label,
4655 value,
4656 label_span.possible_span().map(|l| l.into())
4657 )?;
4658
4659 self.map_counter = self.map_counter.wrapping_add(delta);
4660
4661 Ok(())
4662 }
4663 }
4664
4665 fn visit_assign<'e, E: ExprEvaluationExt + ExprElement + Clone, S: AsRef<str>>(
4666 &mut self,
4667 label: S,
4668 exp: &E,
4669 op: Option<&BinaryOperation>
4670 ) -> Result<(), AssemblerError> {
4671 let label = label.as_ref();
4672 let value = if let Some(op) = op {
4673 let new_exp = Expr::BinaryOperation(
4674 *op,
4675 Box::new(Expr::Label(label.into())),
4676 Box::new(exp.to_expr().into_owned())
4677 );
4678 self.resolve_expr_must_never_fail(&new_exp)?
4679 }
4680 else {
4681 self.resolve_expr_may_fail_in_first_pass(exp)?
4682 };
4683
4684 if let Some(o) = self.output_trigger.as_mut() {
4685 o.replace_code_address(&value)
4686 }
4687
4688 let label = self.handle_global_and_local_labels(label)?;
4689 self.symbols_mut().assign_symbol_to_value(label, value)?;
4694 Ok(())
4695 }
4696}
4697
4698fn visit_defs<E: ExprEvaluationExt>(
4699 l: &[(E, Option<E>)],
4700 env: &mut Env
4701) -> Result<(), AssemblerError> {
4702 for (e, f) in l.iter() {
4703 let bytes = assemble_defs_item(e, f.as_ref(), env)?;
4704 env.output_bytes(&bytes)?;
4705 }
4706 Ok(())
4707}
4708
4709fn visit_end(_env: &mut Env) -> Result<(), AssemblerError> {
4710 eprintln!("END directive is not implemented");
4711 Ok(())
4712}
4713
4714pub enum DbLikeKind {
4715 Defb,
4716 Defw,
4717 Str
4718}
4719
4720impl From<&Token> for DbLikeKind {
4721 fn from(token: &Token) -> Self {
4722 match token {
4723 Token::Defb(..) => Self::Defb,
4724 Token::Defw(..) => Self::Defw,
4725 Token::Str(..) => Self::Str,
4726 _ => unreachable!()
4727 }
4728 }
4729}
4730
4731impl DbLikeKind {
4732 fn mask(&self) -> u16 {
4733 match self {
4734 DbLikeKind::Defb => 0xFF,
4735 DbLikeKind::Defw => 0xFFFF,
4736 DbLikeKind::Str => 0xFF
4737 }
4738 }
4739}
4740
4741impl Env {
4742 pub fn visit_abyte<
4743 E1: ExprEvaluationExt + ExprElement + Debug,
4744 E2: ExprEvaluationExt + ExprElement + Debug
4745 >(
4746 &mut self,
4747 delta: &E1,
4748 exprs: &[E2]
4749 ) -> Result<(), AssemblerError> {
4750 let delta = self.resolve_expr_may_fail_in_first_pass(delta)?;
4751 self.visit_db_or_dw_or_str(DbLikeKind::Defb, exprs, delta)
4752 }
4753
4754 pub fn visit_db_or_dw_or_str<E: ExprEvaluationExt + ExprElement + Debug>(
4756 &mut self,
4757 kind: DbLikeKind,
4758 exprs: &[E],
4759 delta: ExprResult
4760 ) -> Result<(), AssemblerError> {
4761 let env = self;
4762
4763 let delta = delta.int()?;
4764
4765 let mask = kind.mask();
4766
4767 let output = |env: &mut Env, val: i32, mask: u16| -> Result<(), AssemblerError> {
4768 let val = val + delta;
4769
4770 if mask == 0xFF {
4771 env.output_byte(val as u8)?;
4772 }
4773 else {
4774 let high = ((val & 0xFF00) >> 8) as u8;
4775 let low = (val & 0xFF) as u8;
4776 env.output_byte(low)?;
4777 env.output_byte(high)?;
4778 }
4779 Ok(())
4780 };
4781
4782 let output_expr_result = |env: &mut Env, expr: ExprResult, mask: u16| {
4783 match &expr {
4784 ExprResult::Float(_) | ExprResult::Value(_) | ExprResult::Bool(_) => {
4785 output(env, expr.int()?, mask)
4786 },
4787 ExprResult::Char(c) => {
4788 let c = env.charset_encoding.transform_char(*c as char);
4790 output(env, expr.int()?, mask)
4791 },
4792 ExprResult::String(s) => {
4793 let bytes = env.charset_encoding.transform_string(s);
4794
4795 for c in bytes {
4796 output(env, c as _, mask)?;
4797 }
4798 Ok(())
4799 },
4800 ExprResult::List(l) => {
4801 for c in l {
4802 output(env, c.int()?, mask)?;
4803 }
4804 Ok(())
4805 },
4806 ExprResult::Matrix { .. } => {
4807 for row in expr.matrix_rows() {
4808 for c in row.list_content() {
4809 output(env, c.int()?, mask)?;
4810 }
4811 }
4812 Ok(())
4813 }
4814 }
4815 };
4816
4817 let backup_address = env.logical_output_address();
4818 for exp in exprs.iter() {
4819 if exp.is_string() {
4820 let s = exp.string();
4821 let bytes = env.charset_encoding.transform_string(s);
4822 for b in &bytes {
4823 output(env, *b as _, mask)?
4824 }
4825 env.update_dollar();
4826 }
4827 else if exp.is_char() {
4828 let c = exp.char();
4829 let b = env.charset_encoding.transform_char(c);
4830 output(env, b as _, mask)?;
4831 env.update_dollar();
4832 }
4833 else {
4834 let val = env.resolve_expr_may_fail_in_first_pass(exp)?;
4835 output_expr_result(env, val, mask)?;
4836 env.update_dollar();
4837 }
4838 }
4839
4840 if matches!(kind, DbLikeKind::Str) && backup_address < env.logical_output_address() {
4842 let last_address = env.logical_output_address() - 1;
4843 let last_address = env.logical_to_physical_address(last_address as _);
4844 let last_value = env.peek(&last_address);
4845 env.poke(last_value | 0x80, &last_address);
4846 }
4847
4848 Ok(())
4849 }
4850}
4851
4852impl Env {
4853 fn move_delayed_commands_of_functions(&mut self) {
4855 {
4856 let prints = self.extra_print_from_function.read().unwrap().clone();
4857 for print in prints.into_iter() {
4858 self.active_page_info_mut()
4859 .add_print_or_pause_command(print);
4860 }
4861 self.extra_print_from_function.write().unwrap().clear();
4862 }
4863
4864 {
4865 let asserts = self
4866 .extra_failed_assert_from_function
4867 .read()
4868 .unwrap()
4869 .clone();
4870 for assert in asserts.into_iter() {
4871 self.active_page_info_mut()
4872 .add_failed_assert_command(assert);
4873 }
4874 self.extra_failed_assert_from_function
4875 .write()
4876 .unwrap()
4877 .clear();
4878 }
4879 }
4880}
4881
4882#[allow(missing_docs)]
4883impl Env {
4884 pub fn visit_basic<S: SourceString, S2: SourceString, E: ExprEvaluationExt>(
4885 &mut self,
4886 variables: Option<Vec<S>>,
4887 hidden_lines: Option<&Vec<E>>,
4888 code: S2
4889 ) -> Result<(), AssemblerError> {
4890 let bytes = self.assemble_basic(variables, hidden_lines, code)?;
4891
4892 if self.start_address().is_none() {
4895 self.active_page_info_mut().logical_outputadr = 0x170;
4896 self.active_page_info_mut().logical_codeadr = self.logical_output_address();
4897 self.active_page_info_mut().startadr = Some(self.logical_output_address());
4898 self.output_address = 0x170;
4899 }
4900
4901 self.output_bytes(&bytes)
4902 }
4903
4904 pub fn assemble_basic<S: SourceString, S2: SourceString, E: ExprEvaluationExt>(
4905 &mut self,
4906 variables: Option<Vec<S>>,
4907 hidden_lines: Option<&Vec<E>>,
4908 code: S2
4909 ) -> Result<Vec<u8>, AssemblerError> {
4910 let hidden_lines = hidden_lines.map(|h| {
4911 h.iter()
4912 .map(|e| self.resolve_expr_must_never_fail(e))
4913 .collect::<Result<Vec<_>, AssemblerError>>()
4914 });
4915 if let Some(Err(e)) = hidden_lines {
4916 return Err(e);
4917 }
4918
4919 let hidden_lines = hidden_lines.map(|r| {
4920 r.unwrap()
4921 .into_iter()
4922 .map(|e| e.int())
4923 .collect::<Result<Vec<_>, ExpressionTypeError>>()
4924 });
4925 if let Some(Err(e)) = hidden_lines {
4926 return Err(e.into());
4927 }
4928
4929 let hidden_lines =
4930 hidden_lines.map(|r| r.unwrap().into_iter().map(|e| e as u16).collect_vec());
4931
4932 let basic_src = {
4935 let mut basic = code.as_str().to_owned();
4936 match variables {
4937 None => {},
4938 Some(arguments) => {
4939 for argument in arguments {
4940 let key = format!("{{{}}}", argument.as_str());
4941 let value = format!(
4942 "&{:X}",
4943 self.resolve_expr_may_fail_in_first_pass(&Expr::from(
4944 argument.as_str()
4945 ))?
4946 );
4947 basic = basic.replace(&key, &value);
4948 }
4949 },
4950 }
4951 basic
4952 };
4953
4954 let mut basic = BasicProgram::parse(basic_src)?;
4956 if let Some(hidden_lines) = hidden_lines {
4957 basic.hide_lines(&hidden_lines)?;
4958 }
4959 Ok(basic.as_bytes())
4960 }
4961}
4962
4963pub fn visit_repeat(rept: &Token, env: &mut Env) -> Result<(), AssemblerError> {
4966 let tokens = rept.unroll(env).unwrap()?;
4967
4968 for token in &tokens {
4969 visit_token(token, env)?;
4970 }
4971
4972 Ok(())
4973}
4974
4975#[allow(clippy::cast_possible_wrap)]
4979pub fn visit_stableticker<S: AsRef<str>>(
4980 ticker: &StableTickerAction<S>,
4981 env: &mut Env
4982) -> Result<(), AssemblerError> {
4983 match ticker {
4984 StableTickerAction::Start(name) => {
4985 env.stable_counters.add_counter(name)?;
4986 Ok(())
4987 },
4988 StableTickerAction::Stop(stop) => {
4989 if let Some((label, count)) = stop
4990 .as_ref()
4991 .map(|stop| env.stable_counters.release_counter(stop.as_ref()))
4992 .unwrap_or_else(|| env.stable_counters.release_last_counter())
4993 {
4994 if !env.pass.is_listing_pass() && env.symbols().contains_symbol(&label)? {
4995 env.add_warning(AssemblerWarning::AlreadyRenderedError(format!(
4996 "Symbol {label} has been overwritten"
4997 )));
4998 }
4999
5000 env.symbols_mut()
5002 .set_symbol_to_value(label, Value::from(count))?;
5003 Ok(())
5004 }
5005 else {
5006 Err(AssemblerError::NoActiveCounter)
5007 }
5008 }
5009 }
5010}
5011
5012pub fn assemble_defs_item<E: ExprEvaluationExt>(
5014 expr: &E,
5015 fill: Option<&E>,
5016 env: &mut Env
5017) -> Result<Bytes, AssemblerError> {
5018 let count = match env.resolve_expr_must_never_fail(expr) {
5019 Ok(amount) => amount.int()?,
5020 Err(e) => {
5021 env.add_error_discardable_one_pass(e)?;
5022 *env.request_additional_pass.write().unwrap() = true; 0
5024 }
5025 };
5026
5027 if count < 0 {
5028 return Err(AssemblerError::AssemblingError {
5029 msg: format!("{count} is an invalid value")
5030 });
5031 }
5032
5033 let value = if fill.is_none() {
5034 0
5035 }
5036 else {
5037 let value = env
5038 .resolve_expr_may_fail_in_first_pass(fill.unwrap())?
5039 .int()?;
5040 (value & 0xFF) as u8
5041 };
5042
5043 let mut bytes = Bytes::with_capacity(count as usize);
5044 bytes.resize_with(count as _, || value);
5045
5046 Ok(bytes)
5047}
5048
5049pub fn assemble_align(
5051 expr: &Expr,
5052 fill: Option<&Expr>,
5053 env: &mut Env
5054) -> Result<Bytes, AssemblerError> {
5055 let expression = env.resolve_expr_must_never_fail(expr)?.int()? as u16;
5056 let current = env.symbols().current_address()?;
5057 let value = if fill.is_none() {
5058 0
5059 }
5060 else {
5061 let value = env
5062 .resolve_expr_may_fail_in_first_pass(fill.unwrap())?
5063 .int()?;
5064 (value & 0xFF) as u8
5065 };
5066
5067 let mut until = current;
5069 while until % expression != 0 {
5070 until += 1;
5071 }
5072
5073 let hole = (until - current) as usize;
5075 let mut bytes = Bytes::with_capacity(hole);
5076 for _i in 0..hole {
5077 bytes.push(value);
5078 }
5079
5080 Ok(bytes)
5082}
5083
5084pub(crate) fn visit_opcode<D: DataAccessElem>(
5086 mnemonic: Mnemonic,
5087 arg1: &Option<D>,
5088 arg2: &Option<D>,
5089 arg3: &Option<Register8>,
5090 env: &mut Env
5091) -> Result<(), AssemblerError>
5092where
5093 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5094{
5095 let bytes = assemble_opcode(mnemonic, arg1, arg2, arg3, env)?;
5097 for b in bytes.iter() {
5098 env.output_byte(*b)?;
5099 }
5100
5101 Ok(())
5102}
5103
5104pub fn assemble_opcode<D: DataAccessElem>(
5108 mnemonic: Mnemonic,
5109 arg1: &Option<D>,
5110 arg2: &Option<D>,
5111 arg3: &Option<Register8>,
5112 env: &mut Env
5113) -> Result<Bytes, AssemblerError>
5114where
5115 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5116{
5117 match mnemonic {
5118 Mnemonic::And | Mnemonic::Or | Mnemonic::Xor => {
5119 assemble_logical_operator(mnemonic, arg1.as_ref().unwrap(), env)
5120 },
5121 Mnemonic::Add | Mnemonic::Adc => {
5122 assemble_add_or_adc(mnemonic, arg1.as_ref(), arg2.as_ref().unwrap(), env)
5123 },
5124 Mnemonic::Cp => env.assemble_cp(arg1.as_ref().unwrap()),
5125 Mnemonic::ExMemSp => assemble_ex_memsp(arg1.as_ref().unwrap()),
5126 Mnemonic::Dec | Mnemonic::Inc => assemble_inc_dec(mnemonic, arg1.as_ref().unwrap(), env),
5127 Mnemonic::Djnz => assemble_djnz(arg1.as_ref().unwrap(), env),
5128 Mnemonic::In => assemble_in(arg1.as_ref().unwrap(), arg2.as_ref().unwrap(), env),
5129 Mnemonic::Ld => assemble_ld(arg1.as_ref().unwrap(), arg2.as_ref().unwrap(), env),
5130 Mnemonic::Ldi
5131 | Mnemonic::Ldd
5132 | Mnemonic::Ldir
5133 | Mnemonic::Lddr
5134 | Mnemonic::Outi
5135 | Mnemonic::Outd
5136 | Mnemonic::Ei
5137 | Mnemonic::Di
5138 | Mnemonic::ExAf
5139 | Mnemonic::ExHlDe
5140 | Mnemonic::Exx
5141 | Mnemonic::Halt
5142 | Mnemonic::Ind
5143 | Mnemonic::Indr
5144 | Mnemonic::Ini
5145 | Mnemonic::Inir
5146 | Mnemonic::Rla
5147 | Mnemonic::Rlca
5148 | Mnemonic::Rrca
5149 | Mnemonic::Rra
5150 | Mnemonic::Reti
5151 | Mnemonic::Retn
5152 | Mnemonic::Scf
5153 | Mnemonic::Ccf
5154 | Mnemonic::Cpd
5155 | Mnemonic::Cpdr
5156 | Mnemonic::Cpi
5157 | Mnemonic::Cpir
5158 | Mnemonic::Cpl
5159 | Mnemonic::Daa
5160 | Mnemonic::Neg
5161 | Mnemonic::Otdr
5162 | Mnemonic::Otir
5163 | Mnemonic::Rld
5164 | Mnemonic::Rrd => assemble_no_arg(mnemonic),
5165 Mnemonic::Out => assemble_out(arg1.as_ref().unwrap(), arg2.as_ref().unwrap(), env),
5166 Mnemonic::Jr | Mnemonic::Jp | Mnemonic::Call => {
5167 assemble_call_jr_or_jp(mnemonic, arg1.as_ref(), arg2.as_ref().unwrap(), env)
5168 },
5169 Mnemonic::Pop => assemble_pop(arg1.as_ref().unwrap()),
5170 Mnemonic::Push => assemble_push(arg1.as_ref().unwrap()),
5171 Mnemonic::Bit | Mnemonic::Res | Mnemonic::Set => {
5172 assemble_bit_res_or_set(
5173 mnemonic,
5174 arg1.as_ref().unwrap(),
5175 arg2.as_ref().unwrap(),
5176 arg3.as_ref(),
5177 env
5178 )
5179 },
5180 Mnemonic::Ret => assemble_ret(arg1.as_ref()),
5181 Mnemonic::Rst => {
5182 if let Some(arg2) = arg2.as_ref() {
5183 assemble_rst_fake(arg1.as_ref().unwrap(), arg2, env)
5184 }
5185 else {
5186 assemble_rst(arg1.as_ref().unwrap(), env)
5188 }
5189 },
5190 Mnemonic::Im => assemble_im(arg1.as_ref().unwrap(), env),
5191 Mnemonic::Nop => {
5192 env.assemble_nop(
5193 Mnemonic::Nop,
5194 arg1.as_ref().map(|v| v.get_expression().unwrap())
5195 )
5196 },
5197 Mnemonic::Nop2 => env.assemble_nop::<Expr>(Mnemonic::Nop2, None),
5198
5199 Mnemonic::Sub => env.assemble_sub(arg1.as_ref().unwrap()),
5200 Mnemonic::Sbc => env.assemble_sbc(arg1.as_ref(), arg2.as_ref().unwrap()),
5201 Mnemonic::Sla
5202 | Mnemonic::Sra
5203 | Mnemonic::Srl
5204 | Mnemonic::Sl1
5205 | Mnemonic::Rl
5206 | Mnemonic::Rr
5207 | Mnemonic::Rlc
5208 | Mnemonic::Rrc => env.assemble_shift(mnemonic, arg1.as_ref().unwrap(), arg2.as_ref())
5209 }
5210}
5211
5212fn assemble_no_arg(mnemonic: Mnemonic) -> Result<Bytes, AssemblerError> {
5213 let bytes: &[u8] = match mnemonic {
5214 Mnemonic::Ldi => &[0xED, 0xA0],
5215 Mnemonic::Ldd => &[0xED, 0xA8],
5216 Mnemonic::Lddr => &[0xED, 0xB8],
5217 Mnemonic::Ldir => &[0xED, 0xB0],
5218 Mnemonic::Di => &[0xF3],
5219 Mnemonic::ExAf => &[0x08],
5220 Mnemonic::ExHlDe => &[0xEB],
5221 Mnemonic::Exx => &[0xD9],
5222 Mnemonic::Ei => &[0xFB],
5223 Mnemonic::Halt => &[0x76],
5224 Mnemonic::Ind => &[0xED, 0xAA],
5225 Mnemonic::Indr => &[0xED, 0xBA],
5226 Mnemonic::Ini => &[0xED, 0xA2],
5227 Mnemonic::Inir => &[0xED, 0xB2],
5228 Mnemonic::Outd => &[0xED, 0xAB],
5229 Mnemonic::Outi => &[0xED, 0xA3],
5230 Mnemonic::Rla => &[0x17],
5231 Mnemonic::Rlca => &[0x07],
5232 Mnemonic::Rrca => &[0x0F],
5233 Mnemonic::Rra => &[0x1F],
5234 Mnemonic::Reti => &[0xED, 0x4D],
5235 Mnemonic::Retn => &[0xED, 0x45],
5236 Mnemonic::Scf => &[0x37],
5237 Mnemonic::Ccf => &[0x3F],
5238 Mnemonic::Cpd => &[0xED, 0xA9],
5240 Mnemonic::Cpdr => &[0xED, 0xB9],
5241 Mnemonic::Cpi => &[0xED, 0xA1],
5242 Mnemonic::Cpir => &[0xED, 0xB1],
5243 Mnemonic::Cpl => &[0x2F],
5244 Mnemonic::Daa => &[0x27],
5245 Mnemonic::Neg => &[0xED, 0x44],
5246 Mnemonic::Otdr => &[0xED, 0xBB],
5247 Mnemonic::Otir => &[0xED, 0xB3],
5248 Mnemonic::Rld => &[0xED, 0x6F],
5249 Mnemonic::Rrd => &[0xED, 0x67],
5250 _ => {
5251 return Err(AssemblerError::BugInAssembler {
5252 file: file!(),
5253 line: line!(),
5254 msg: format!("{} not treated", mnemonic)
5255 });
5256 }
5257 };
5258
5259 Ok(Bytes::from_slice(bytes))
5260}
5261
5262fn assemble_inc_dec<D: DataAccessElem>(
5263 mne: Mnemonic,
5264 arg1: &D,
5265 env: &mut Env
5266) -> Result<Bytes, AssemblerError>
5267where
5268 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5269{
5270 let mut bytes = Bytes::new();
5271
5272 let is_inc = match mne {
5273 Mnemonic::Inc => true,
5274 Mnemonic::Dec => false,
5275 _ => panic!("Impossible case")
5276 };
5277
5278 if arg1.is_register16() {
5279 let reg = arg1.get_register16().unwrap();
5280 {
5281 let base = if is_inc { 0b0000_0011 } else { 0b0000_1011 };
5282 let byte = base | (register16_to_code_with_sp(reg) << 4);
5283 bytes.push(byte);
5284 }
5285 }
5286 else if arg1.is_indexregister16() {
5287 let reg = arg1.get_indexregister16().unwrap();
5288 {
5289 bytes.push(indexed_register16_to_code(reg));
5290 bytes.push(if is_inc { 0x23 } else { 0x2B });
5291 }
5292 }
5293 else if arg1.is_register8() {
5294 let reg = arg1.get_register8().unwrap();
5295 {
5296 bytes.push(
5297 if is_inc { 0b0000_0100 } else { 0b0000_0101 } | (register8_to_code(reg) << 3)
5298 );
5299 }
5300 }
5301 else if arg1.is_indexregister8() {
5302 let reg = arg1.get_indexregister8().unwrap();
5303 {
5304 bytes.push(indexed_register16_to_code(reg.complete()));
5305 bytes.push(
5306 if is_inc { 0b0000_0100 } else { 0b0000_0101 } | (indexregister8_to_code(reg) << 3)
5307 );
5308 }
5309 }
5310 else if arg1.is_address_in_register16() && arg1.get_register16().unwrap() == Register16::Hl {
5311 {
5312 bytes.push(if is_inc { 0x34 } else { 0x35 });
5313 }
5314 }
5315 else if arg1.is_indexregister_with_index() {
5316 let reg = arg1.get_indexregister16().unwrap();
5317 let idx = arg1.get_index().unwrap();
5318 {
5319 let res = env.resolve_index_may_fail_in_first_pass(idx)?;
5320 let val = (res.int()? & 0xFF) as u8;
5321
5322 bytes.push(indexed_register16_to_code(reg));
5323 bytes.push(if is_inc { 0x34 } else { 0x35 });
5324 bytes.push(val);
5325 }
5326 }
5327 else {
5328 return Err(AssemblerError::BugInAssembler {
5329 file: file!(),
5330 line: line!(),
5331 msg: format!(
5332 "{}: not implemented for {:?}",
5333 mne.to_string().to_owned(),
5334 arg1
5335 )
5336 });
5337 }
5338 Ok(bytes)
5339}
5340
5341pub fn absolute_to_relative<T: AsRef<SymbolsTable>>(
5343 address: i32,
5344 opcode_delta: i32,
5345 sym: T
5346) -> Result<u8, AssemblerError> {
5347 match sym.as_ref().current_address() {
5348 Err(_msg) => Err(AssemblerError::UnknownAssemblingAddress),
5349 Ok(root) => {
5350 let delta = (address - i32::from(root)) - opcode_delta;
5351 if !(-128..=127).contains(&delta) {
5352 Err(AssemblerError::InvalidArgument {
5353 msg: format!(
5354 "Address 0x{:x} relative to 0x{:x} is too far {}",
5355 address, root, delta
5356 )
5357 })
5358 }
5359 else {
5360 let res = (delta & 0xFF) as u8;
5361 Ok(res)
5362 }
5363 }
5364 }
5365}
5366
5367fn assemble_ret<D: DataAccessElem>(arg1: Option<&D>) -> Result<Bytes, AssemblerError> {
5368 let mut bytes = Bytes::new();
5369
5370 if let Some(arg1) = arg1 {
5371 if let Some(test) = arg1.get_flag_test() {
5372 let flag = flag_test_to_code(test);
5373 bytes.push(0b1100_0000 | (flag << 3));
5374 }
5375 else {
5376 return Err(AssemblerError::InvalidArgument {
5377 msg: "RET: wrong argument for ret".to_string()
5378 });
5379 }
5380 }
5381 else {
5382 bytes.push(0xC9);
5383 }
5384
5385 Ok(bytes)
5386}
5387
5388fn assemble_rst_fake<D: DataAccessElem>(
5389 arg1: &D,
5390 arg2: &D,
5391 env: &mut Env
5392) -> Result<Bytes, AssemblerError>
5393where
5394 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5395{
5396 let val = env
5397 .resolve_expr_may_fail_in_first_pass(arg2.get_expression().unwrap())?
5398 .int()?;
5399
5400 let _p = match val {
5401 0x38 | 7 | 38 => 0b111,
5402 _ => {
5403 return Err(AssemblerError::InvalidArgument {
5404 msg: format!(
5405 "Conditionnal RST cannot take {} as argument. Expected values are 0x38|7|38.",
5406 val
5407 )
5408 });
5409 }
5410 };
5411
5412 let flag = arg1.get_flag_test().unwrap();
5413 if flag != FlagTest::NZ && flag != FlagTest::Z && flag != FlagTest::NC && flag != FlagTest::C {
5414 return Err(AssemblerError::InvalidArgument {
5415 msg: format!(
5416 "Conditionnal RST cannot take {} as flag. Expected values are C|NC|Z|NZ.",
5417 flag
5418 )
5419 });
5420 }
5421
5422 assemble_opcode(
5423 Mnemonic::Jr,
5424 &Some(DataAccess::from(flag)),
5425 &Some(DataAccess::from(
5426 Expr::Label("$".into()).add(Expr::Value(1))
5427 )),
5428 &None,
5429 env
5430 )
5431}
5432
5433fn assemble_rst<D: DataAccessElem>(arg1: &D, env: &mut Env) -> Result<Bytes, AssemblerError>
5434where <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement {
5435 let mut bytes = Bytes::new();
5436 let val = env
5437 .resolve_expr_may_fail_in_first_pass(arg1.get_expression().unwrap())?
5438 .int()?;
5439
5440 let p = match val {
5441 0x00 => 0b000,
5442 0x08 | 1 => 0b001,
5443 0x10 | 2 | 10 => 0b010,
5444 0x18 | 3 | 18 => 0b011,
5445 0x20 | 4 | 20 => 0b100,
5446 0x28 | 5 | 28 => 0b101,
5447 0x30 | 6 | 30 => 0b110,
5448 0x38 | 7 | 38 => 0b111,
5449 _ => {
5450 return Err(AssemblerError::InvalidArgument {
5451 msg: format!(
5452 "RST cannot take {} as argument. Expected values are 0x00, 0x08|1, 0x10|2|10, 0x18|3|18, 0x20|4|20, 0x28|5|28, 0x30|6|30, 0x38|7|38.",
5453 val
5454 )
5455 });
5456 }
5457 };
5458
5459 bytes.push(0b11000111 | (p << 3));
5460 Ok(bytes)
5461}
5462
5463fn assemble_im<D: DataAccessElem>(arg1: &D, env: &mut Env) -> Result<Bytes, AssemblerError>
5464where <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement {
5465 let mut bytes = Bytes::new();
5466 let val = env
5467 .resolve_expr_may_fail_in_first_pass(arg1.get_expression().unwrap())?
5468 .int()?;
5469
5470 let code = match val {
5471 0x00 => 0x46,
5472 0x01 => 0x56,
5473 0x02 => 0x5E,
5474 _ => {
5475 return Err(AssemblerError::InvalidArgument {
5476 msg: format!("IM cannot take {} as argument.", val)
5477 });
5478 }
5479 };
5480
5481 bytes.push(0xED);
5482 bytes.push(code);
5483 Ok(bytes)
5484}
5485
5486pub fn assemble_call_jr_or_jp<D: DataAccessElem>(
5489 mne: Mnemonic,
5490 arg1: Option<&D>,
5491 arg2: &D,
5492 env: &mut Env
5493) -> Result<Bytes, AssemblerError>
5494where
5495 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5496{
5497 let mut bytes = Bytes::new();
5498
5499 let is_jr = match mne {
5500 Mnemonic::Jr => true,
5501 Mnemonic::Jp | Mnemonic::Call => false,
5502 _ => unreachable!()
5503 };
5504
5505 let is_call = match mne {
5506 Mnemonic::Call => true,
5507 Mnemonic::Jp | Mnemonic::Jr => false,
5508 _ => unreachable!()
5509 };
5510
5511 let is_jp = !(is_call || is_jr);
5512
5513 let flag_code = if let Some(arg1) = arg1 {
5516 match arg1.get_flag_test() {
5517 Some(test) => Some(flag_test_to_code(test)),
5518 _ => {
5519 return Err(AssemblerError::InvalidArgument {
5520 msg: format!(
5521 "{}: wrong flag argument",
5522 mne.to_string().to_ascii_uppercase()
5523 )
5524 });
5525 }
5526 }
5527 }
5528 else {
5529 None
5530 };
5531
5532 if arg2.is_expression() {
5534 let e = arg2.get_expression().unwrap();
5535 let address = env.resolve_expr_may_fail_in_first_pass(e)?.int()?;
5536 if is_jr {
5537 let relative = if e.is_relative() {
5538 address as u8
5539 }
5540 else {
5541 env.absolute_to_relative_may_fail_in_first_pass(address, 2)?
5542 };
5543 if flag_code.is_some() {
5544 add_byte(&mut bytes, 0b0010_0000 | (flag_code.unwrap() << 3));
5546 }
5547 else {
5548 add_byte(&mut bytes, 0b0001_1000);
5550 }
5551 add_byte(&mut bytes, relative);
5552 }
5553 else if is_call {
5554 match flag_code {
5555 Some(flag) => add_byte(&mut bytes, 0b1100_0100 | (flag << 3)),
5556 None => add_byte(&mut bytes, 0xCD)
5557 }
5558 add_word(&mut bytes, address as u16);
5559 }
5560 else {
5561 if flag_code.is_some() {
5562 add_byte(&mut bytes, 0b1100_0010 | (flag_code.unwrap() << 3))
5564 }
5565 else {
5566 add_byte(&mut bytes, 0xC3);
5568 }
5569 add_word(&mut bytes, address as u16);
5570 }
5571 }
5572 else if arg2.is_address_in_register16() {
5573 assert_eq!(arg2.get_register16(), Some(Register16::Hl));
5574 assert!(is_jp);
5575 add_byte(&mut bytes, 0xE9);
5576 }
5577 else if arg2.is_address_in_indexregister16() {
5578 assert!(is_jp);
5579 let reg = arg2.get_indexregister16().unwrap();
5580 add_byte(&mut bytes, indexed_register16_to_code(reg));
5581 add_byte(&mut bytes, 0xE9);
5582 }
5583 else {
5584 return Err(AssemblerError::BugInAssembler {
5585 file: file!(),
5586 line: line!(),
5587 msg: format!("{}: parameter {:?} not treated", mne, arg2)
5588 });
5589 }
5590
5591 Ok(bytes)
5592}
5593
5594fn assemble_djnz<D: DataAccessElem>(arg1: &D, env: &mut Env) -> Result<Bytes, AssemblerError>
5595where <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement {
5596 if let Some(expr) = arg1.get_expression() {
5597 let mut bytes = Bytes::new();
5598 let address = env.resolve_expr_may_fail_in_first_pass(expr)?.int()?;
5599 let relative = if expr.is_relative() {
5600 address as u8
5601 }
5602 else {
5603 env.absolute_to_relative_may_fail_in_first_pass(address, 1 + 1)?
5604 };
5605 bytes.push(0x10);
5606 bytes.push(relative);
5607
5608 Ok(bytes)
5609 }
5610 else {
5611 unreachable!()
5612 }
5613}
5614
5615#[allow(missing_docs)]
5616impl Env {
5617 pub fn assemble_cp<D: DataAccessElem>(&mut self, arg: &D) -> Result<Bytes, AssemblerError>
5618 where <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement {
5619 let mut bytes = Bytes::new();
5620
5621 if arg.is_register8() {
5622 let reg = arg.get_register8().unwrap();
5623 {
5624 add_byte(&mut bytes, 0b1011_1000 + register8_to_code(reg));
5625 }
5626 }
5627 else if arg.is_indexregister8() {
5628 let reg = arg.get_indexregister8().unwrap();
5629 {
5630 add_byte(&mut bytes, indexed_register16_to_code(reg.complete()));
5631 add_byte(&mut bytes, 0b1011_1000 + indexregister8_to_code(reg));
5632 }
5633 }
5634 else if arg.is_expression() {
5635 let exp = arg.get_expression().unwrap();
5636 {
5637 add_byte(&mut bytes, 0xFE);
5638 add_byte(
5639 &mut bytes,
5640 self.resolve_expr_may_fail_in_first_pass(exp)?.int()? as _
5641 );
5642 }
5643 }
5644 else if arg.is_address_in_register16() && arg.get_register16().unwrap() == Register16::Hl
5645 {
5646 {
5647 add_byte(&mut bytes, 0xBE);
5648 }
5649 }
5650 else if arg.is_indexregister_with_index() {
5651 let reg = arg.get_indexregister16().unwrap();
5652 let idx = arg.get_index().unwrap();
5653 {
5654 add_byte(&mut bytes, indexed_register16_to_code(reg));
5655 add_byte(&mut bytes, 0xBE);
5656 add_byte(
5657 &mut bytes,
5658 self.resolve_index_may_fail_in_first_pass(idx)?.int()? as _
5659 );
5660 }
5661 }
5662 else {
5663 unreachable!()
5664 }
5665
5666 Ok(bytes)
5667 }
5668
5669 pub fn assemble_sub<D: DataAccessElem>(&mut self, arg: &D) -> Result<Bytes, AssemblerError>
5670 where <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement {
5671 let mut bytes = Bytes::new();
5672
5673 if arg.is_expression() {
5674 let exp = arg.get_expression().unwrap();
5675 {
5676 let val = (self.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
5677 bytes.push(0xD6);
5678 bytes.push(val);
5679 }
5680 }
5681 else if arg.is_register8() {
5682 let reg = arg.get_register8().unwrap();
5683 {
5684 bytes.push(0b10010000 + (register8_to_code(reg)));
5685 }
5686 }
5687 else if arg.is_indexregister8() {
5688 let reg = arg.get_indexregister8().unwrap();
5689 {
5690 bytes.push(indexed_register16_to_code(reg.complete()));
5691 bytes.push(0b10010000 + (indexregister8_to_code(reg)));
5692 }
5693 }
5694 else if arg.is_address_in_register16() {
5695 assert_eq!(arg.get_register16().unwrap(), Register16::Hl);
5696 {
5697 bytes.push(0x96);
5698 }
5699 }
5700 else if arg.is_indexregister_with_index() {
5701 let reg = arg.get_indexregister16().unwrap();
5702 let idx = arg.get_index().unwrap();
5703
5704 {
5705 let val = (self.resolve_index_may_fail_in_first_pass(idx)?.int()? & 0xFF) as u8;
5706
5707 bytes.push(indexed_register16_to_code(reg));
5708 bytes.push(0x96);
5709 bytes.push(val);
5710 }
5711 }
5712 else {
5713 unreachable!();
5714 }
5715
5716 Ok(bytes)
5717 }
5718
5719 pub fn assemble_sbc<D: DataAccessElem>(
5720 &mut self,
5721 arg1: Option<&D>,
5722 arg2: &D
5723 ) -> Result<Bytes, AssemblerError>
5724 where
5725 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5726 {
5727 let mut bytes = Bytes::new();
5728
5729 if arg1.as_ref().map(|arg| arg.is_register_a()).unwrap_or(true) {
5730 if arg2.is_register8() {
5731 let reg = arg2.get_register8().unwrap();
5732 {
5733 bytes.push(0b10011000 + register8_to_code(reg));
5734 }
5735 }
5736 else if arg2.is_indexregister8() {
5737 let reg = arg2.get_indexregister8().unwrap();
5738 {
5739 bytes.push(indexed_register16_to_code(reg.complete()));
5740 bytes.push(0b10011000 + indexregister8_to_code(reg));
5741 }
5742 }
5743 else if arg2.is_expression() {
5744 let exp = arg2.get_expression().unwrap();
5745 {
5746 let val = self.resolve_expr_may_fail_in_first_pass(exp)?.int()? as u8;
5747 bytes.push(0xDE);
5748 bytes.push(val);
5749 }
5750 }
5751 else if arg2.is_address_in_register16() {
5752 assert_eq!(arg2.get_register16().unwrap(), Register16::Hl);
5753 {
5754 bytes.push(0x9E);
5755 }
5756 }
5757 else if arg2.is_indexregister_with_index() {
5758 let reg = arg2.get_indexregister16().unwrap();
5759 let idx = arg2.get_index().unwrap();
5760 {
5761 bytes.push(indexed_register16_to_code(reg));
5762 bytes.push(0x9E);
5763 let val = self.resolve_index_may_fail_in_first_pass(idx)?.int()? as u8;
5764 bytes.push(val);
5765 }
5766 }
5767 else {
5768 unreachable!()
5769 }
5770 }
5771 else {
5772 assert!(arg1.unwrap().is_register_hl());
5773 assert!(arg2.is_register16());
5774 let reg = arg2.get_register16().unwrap();
5775 bytes.push(0xED);
5776 bytes.push(0b0100_0010 | (register16_to_code_with_sp(reg) << 4));
5777 }
5778
5779 Ok(bytes)
5780 }
5781
5782 pub fn assemble_shift<D: DataAccessElem>(
5783 &mut self,
5784 mne: Mnemonic,
5785 target: &D,
5786 hidden: Option<&D>
5787 ) -> Result<Bytes, AssemblerError>
5788 where
5789 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5790 {
5791 let mut bytes = Bytes::new();
5792
5793 if target.is_register8() {
5794 let reg = target.get_register8().unwrap();
5795 add_byte(&mut bytes, 0xCB);
5796 let byte = if mne.is_sla() {
5797 0b0010_0000
5798 }
5799 else if mne.is_sra() {
5800 0b0010_1000
5801 }
5802 else if mne.is_srl() {
5803 0b0011_1000
5804 }
5805 else if mne.is_rlc() {
5806 0b0000_0000
5807 }
5808 else if mne.is_rrc() {
5809 0b0000_1000
5810 }
5811 else if mne.is_rl() {
5812 0b0001_0000
5813 }
5814 else if mne.is_rr() {
5815 0b0001_1000
5816 }
5817 else if mne.is_sl1() {
5818 0b0011_0000
5819 }
5820 else {
5821 unreachable!()
5822 } + register8_to_code(reg);
5823 add_byte(&mut bytes, byte);
5824 }
5825 else if target.is_register16() {
5826 let reg16 = target.get_register16().unwrap();
5828 let opcodes: &[(Mnemonic, Option<Register8>)] = match mne {
5829 Mnemonic::Srl => &[(Mnemonic::Srl, reg16.high()), (Mnemonic::Rr, reg16.low())],
5830 Mnemonic::Sra => &[(Mnemonic::Sra, reg16.high()), (Mnemonic::Rr, reg16.low())],
5831 Mnemonic::Sl1 => &[(Mnemonic::Sl1, reg16.low()), (Mnemonic::Rl, reg16.high())],
5832 Mnemonic::Sla => &[(Mnemonic::Sla, reg16.low()), (Mnemonic::Rl, reg16.high())],
5833 Mnemonic::Rr => &[(Mnemonic::Rr, reg16.high()), (Mnemonic::Rr, reg16.low())],
5834 Mnemonic::Rl => &[(Mnemonic::Rl, reg16.low()), (Mnemonic::Rl, reg16.high())],
5835 Mnemonic::Rlc => {
5836 &[
5837 (Mnemonic::Sla, reg16.high()),
5838 (Mnemonic::Rl, reg16.low()),
5839 (Mnemonic::Rr, reg16.high()),
5840 (Mnemonic::Rlc, reg16.high())
5841 ]
5842 },
5843 Mnemonic::Rrc => {
5844 &[
5845 (Mnemonic::Srl, reg16.high()),
5846 (Mnemonic::Rr, reg16.low()),
5847 (Mnemonic::Rl, reg16.high()),
5848 (Mnemonic::Rrc, reg16.high())
5849 ]
5850 },
5851
5852 _ => unreachable!()
5853 };
5854
5855 for instruction in opcodes
5856 .iter()
5857 .map(|op| Token::OpCode(op.0, Some(op.1.unwrap().into()), None, None))
5858 {
5859 instruction.visited(self)?;
5860 }
5861 }
5862 else {
5863 assert!(target.is_address_in_register16() || target.is_indexregister_with_index());
5864
5865 if target.is_indexregister_with_index() {
5867 let reg = target.get_indexregister16().unwrap();
5868 let idx = target.get_index().unwrap();
5869
5870 {
5871 let val = self.resolve_index_may_fail_in_first_pass(idx)?.int()? as u8;
5872 bytes.push(indexed_register16_to_code(reg));
5873 add_byte(&mut bytes, 0xCB);
5874 bytes.push(val);
5875 }
5876 }
5877 else if target.is_address_in_register16() {
5878 assert_eq!(target.get_register16().unwrap(), Register16::Hl);
5879 {
5880 add_byte(&mut bytes, 0xCB);
5881 }
5882 }
5883 else {
5884 return Err(AssemblerError::InvalidArgument {
5885 msg: format!("{} cannot take {} as argument", mne, target)
5886 });
5887 };
5888
5889 let mut byte: u8 = if mne.is_sla() {
5891 0x26
5892 }
5893 else if mne.is_sra() {
5894 0x2E
5895 }
5896 else if mne.is_srl() {
5897 0x3E
5898 }
5899 else if mne.is_rlc() {
5900 0x06
5901 }
5902 else if mne.is_rrc() {
5903 0x0E
5904 }
5905 else if mne.is_rl() {
5906 0x16
5907 }
5908 else if mne.is_rr() {
5909 0x1E
5910 }
5911 else if mne.is_sl1() {
5912 0x36
5913 }
5914 else {
5915 unreachable!()
5916 };
5917
5918 if hidden.is_some() {
5919 let delta: i8 = match hidden.unwrap().get_register8().unwrap() {
5920 Register8::A => 1,
5921 Register8::L => -1,
5922 Register8::H => -2,
5923 Register8::E => -3,
5924 Register8::D => -4,
5925 Register8::C => -5,
5926 Register8::B => -6
5927 };
5928 if delta < 0 {
5929 byte -= delta.unsigned_abs();
5930 }
5931 else {
5932 byte += delta as u8;
5933 }
5934 }
5935 bytes.push(byte);
5936 }
5937
5938 Ok(bytes)
5939 }
5940}
5941
5942fn assemble_ld<D: DataAccessElem + Debug>(
5943 arg1: &D,
5944 arg2: &D,
5945 env: &mut Env
5946) -> Result<Bytes, AssemblerError>
5947where
5948 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
5949{
5950 let mut bytes = Bytes::new();
5951
5952 if arg1.is_register8() {
5954 let dst = register8_to_code(arg1.get_register8().unwrap());
5955 if arg2.is_register8() {
5956 let src = arg2.get_register8().unwrap();
5957 {
5958 let src = register8_to_code(src);
5960
5961 let code = 0b0100_0000 + (dst << 3) + src;
5962 bytes.push(code);
5963 }
5964 }
5965 else if arg2.is_indexregister8() {
5966 let src = arg2.get_indexregister8().unwrap();
5967 {
5968 bytes.push(indexed_register16_to_code(src.complete()));
5969 let src = indexregister8_to_code(src);
5970 let code = 0b0100_0000 + (dst << 3) + src;
5971 bytes.push(code);
5972 }
5973 }
5974 else if arg2.is_expression() {
5975 let exp = arg2.get_expression().unwrap();
5976 {
5977 let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
5978
5979 bytes.push(0b0000_0110 | (dst << 3));
5980 bytes.push(val);
5981 }
5982 }
5983 else if arg2.is_indexregister_with_index() {
5984 let reg = arg2.get_indexregister16().unwrap();
5985 let idx = arg2.get_index().unwrap();
5986 {
5987 let val = env.resolve_index_may_fail_in_first_pass(idx)?.int()?;
5988
5989 add_index_register_code(&mut bytes, reg);
5990 add_byte(&mut bytes, 0b0100_0110 | (dst << 3));
5991 add_index(&mut bytes, val)?;
5992 }
5993 }
5994 else if arg2.is_address_in_register16() {
5995 match arg2.get_register16().unwrap() {
5996 Register16::Hl => {
5997 add_byte(&mut bytes, 0b0100_0110 | (dst << 3));
5998 },
5999 memreg => {
6000 assert!(arg1.is_register_a());
6001 let byte = match memreg {
6002 Register16::Bc => 0x0A,
6003 Register16::De => 0x1A,
6004 _ => unreachable!()
6005 };
6006 add_byte(&mut bytes, byte);
6007 }
6008 }
6009 }
6010 else if arg2.is_address_in_indexregister16() {
6011 let reg = arg2.get_indexregister16().unwrap();
6012 {
6013 add_index_register_code(&mut bytes, reg);
6014 add_byte(&mut bytes, 0b0100_0110 | (dst << 3));
6015 }
6016 }
6017 else if arg2.is_memory() {
6018 let expr = arg2.get_expression().unwrap();
6019
6020 {
6021 let val = env.resolve_expr_may_fail_in_first_pass(expr)?.int()?;
6023 add_byte(&mut bytes, 0x3A);
6024 add_word(&mut bytes, val as _);
6025 }
6026 }
6027 else if arg2.is_register_i() {
6028 {
6029 assert!(arg1.is_register_a());
6030 bytes.push(0xED);
6031 bytes.push(0x57);
6032 }
6033 }
6034 else if arg2.is_register_r() {
6035 {
6036 assert!(arg1.is_register_a());
6037 bytes.push(0xED);
6038 bytes.push(0x5F);
6039 }
6040 }
6041 else {
6042 return Err(AssemblerError::BugInAssembler {
6043 file: file!(),
6044 line: line!(),
6045 msg: format!("LD: not properly implemented for '{:?}, {:?}'", arg1, arg2)
6046 });
6047 }
6048 }
6049 else if arg1.is_register16() {
6051 let dst = arg1.get_register16().unwrap();
6052 let dst_code = register16_to_code_with_sp(dst);
6053
6054 if arg2.is_expression() {
6055 let exp = arg2.get_expression().unwrap();
6056 {
6057 let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFFFF) as u16;
6058
6059 add_byte(&mut bytes, 0b0000_0001 | (dst_code << 4));
6060 add_word(&mut bytes, val);
6061 }
6062 }
6063 else if arg2.is_register_hl() && dst.is_sp() {
6064 add_byte(&mut bytes, 0xF9);
6065 }
6066 else if arg2.is_indexregister16() && dst.is_sp() {
6067 let reg = arg2.get_indexregister16().unwrap();
6068 {
6069 add_byte(&mut bytes, indexed_register16_to_code(reg));
6070 add_byte(&mut bytes, 0xF9);
6071 }
6072 }
6073 else if arg2.is_register16() {
6074 let src = arg2.get_register16().unwrap();
6075 {
6077 let bytes_high = assemble_ld(
6078 &DataAccess::Register8(dst.high().unwrap()),
6079 &DataAccess::Register8(src.high().unwrap()),
6080 env
6081 )
6082 .unwrap();
6083 let bytes_low = assemble_ld(
6084 &DataAccess::Register8(dst.low().unwrap()),
6085 &DataAccess::Register8(src.low().unwrap()),
6086 env
6087 )
6088 .unwrap();
6089
6090 bytes.extend_from_slice(&bytes_low);
6091 bytes.extend_from_slice(&bytes_high);
6092 }
6093 }
6094 else if arg2.is_memory() {
6095 let expr = arg2.get_expression().unwrap();
6096 {
6097 let val = (env.resolve_expr_may_fail_in_first_pass(expr)?.int()? & 0xFFFF) as u16;
6098
6099 if let Register16::Hl = dst {
6100 add_byte(&mut bytes, 0x2A);
6101 add_word(&mut bytes, val);
6102 }
6103 else {
6104 add_byte(&mut bytes, 0xED);
6105 add_byte(
6106 &mut bytes,
6107 (register16_to_code_with_sp(dst) << 4) + 0b0100_1011
6108 );
6109 add_word(&mut bytes, val);
6110 }
6111 }
6112 }
6113 }
6114 else if arg1.is_indexregister8() {
6115 let dst = arg1.get_indexregister8().unwrap();
6116 add_byte(&mut bytes, indexed_register16_to_code(dst.complete()));
6117
6118 if arg2.is_expression() {
6119 let exp = arg2.get_expression().unwrap();
6120 {
6121 let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
6122 bytes.push(0b0000_0110 | (indexregister8_to_code(dst) << 3));
6123 bytes.push(val);
6124 }
6125 }
6126 else if arg2.is_register8() {
6127 let src = arg2.get_register8().unwrap();
6128
6129 {
6130 let code = register8_to_code(src);
6131
6132 let code = if dst.is_high() {
6133 0b0110_0000 + code
6134 }
6135 else {
6136 0x68 + code
6137 };
6138 bytes.push(code);
6139 }
6140 }
6141 else if arg2.is_indexregister8() {
6142 let src = arg2.get_indexregister8().unwrap();
6143 {
6144 assert_eq!(dst.complete(), src.complete());
6145
6146 let byte = match (dst.is_low(), src.is_low()) {
6147 (false, false) => 0x64,
6148 (false, true) => 0x65,
6149 (true, false) => 0x6C,
6150 (true, true) => 0x6D
6151 };
6152 bytes.push(byte)
6153 }
6154 }
6155 else {
6156 unreachable!()
6157 }
6158 }
6159 else if arg1.is_indexregister16() {
6161 let dst = arg1.get_indexregister16().unwrap();
6162 let code = indexed_register16_to_code(dst);
6163
6164 if arg2.is_expression() {
6165 let exp = arg2.get_expression().unwrap();
6166 {
6167 let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFFFF) as u16;
6168
6169 add_byte(&mut bytes, code);
6170 add_byte(&mut bytes, 0x21);
6171 add_word(&mut bytes, val);
6172 }
6173 }
6174 else if arg2.is_memory() {
6175 let exp = arg2.get_expression().unwrap();
6176
6177 {
6178 let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFFFF) as u16;
6179
6180 add_byte(&mut bytes, code);
6181 add_byte(&mut bytes, 0x2A);
6182 add_word(&mut bytes, val);
6183 }
6184 }
6185 }
6186 else if arg1.is_address_in_register16() {
6188 let dst = arg1.get_register16().unwrap();
6189 match dst {
6191 Register16::Hl => {
6192 if arg2.is_register8() {
6193 let src = arg2.get_register8().unwrap();
6194 let src = register8_to_code(src);
6195 let code = 0b0111_0000 | src;
6196 bytes.push(code);
6197 }
6198 else if arg2.is_expression() {
6199 let exp = arg2.get_expression().unwrap();
6200 let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
6201 bytes.push(0x36);
6202 bytes.push(val);
6203 }
6204 },
6205
6206 Register16::De if arg2.is_register_a() => {
6207 bytes.push(0b0001_0010);
6208 },
6209
6210 Register16::Bc if arg2.is_register_a() => {
6211 bytes.push(0b0000_0010);
6212 },
6213
6214 _ => {}
6215 }
6216 }
6217 else if arg1.is_address_in_indexregister16() {
6218 let dst = arg1.get_indexregister16().unwrap();
6219 add_index_register_code(&mut bytes, dst);
6220
6221 if arg2.is_register8() {
6222 let src = arg2.get_register8().unwrap();
6223 let src = register8_to_code(src);
6224 let code = 0b0111_0000 | src;
6225 bytes.push(code);
6226 bytes.push(0);
6227 }
6228 else if arg2.is_expression() {
6229 let exp = arg2.get_expression().unwrap();
6230 let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
6231 bytes.push(0x36);
6232 bytes.push(val);
6233 }
6234 }
6235 else if arg1.is_indexregister_with_index() {
6237 let reg = arg1.get_indexregister16().unwrap();
6238 let idx = arg1.get_index().unwrap();
6239 add_byte(&mut bytes, indexed_register16_to_code(reg));
6240 let delta = (env.resolve_index_may_fail_in_first_pass(idx)?.int()? & 0xFF) as u8;
6241
6242 if arg2.is_expression() {
6243 let exp = arg2.get_expression().unwrap();
6244 {
6245 let value = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
6246 add_byte(&mut bytes, 0x36);
6247 add_byte(&mut bytes, delta);
6248 add_byte(&mut bytes, value);
6249 }
6250 }
6251 else if arg2.is_register8() {
6252 let src = arg2.get_register8().unwrap();
6253
6254 {
6255 add_byte(&mut bytes, 0x70 + register8_to_code(src));
6256 add_byte(&mut bytes, delta);
6257 }
6258 }
6259 else {
6260 bytes.clear();
6262 }
6263 }
6264 else if arg1.is_memory() {
6266 let exp = arg1.get_expression().unwrap();
6267 let address = env.resolve_expr_may_fail_in_first_pass(exp)?.int()?;
6268
6269 if arg2.is_indexregister16() {
6270 match arg2.get_indexregister16().unwrap() {
6271 IndexRegister16::Ix => {
6272 bytes.push(DD);
6273 bytes.push(0b0010_0010);
6274 add_word(&mut bytes, address as _);
6275 },
6276 IndexRegister16::Iy => {
6277 bytes.push(FD);
6278 bytes.push(0b0010_0010);
6279 add_word(&mut bytes, address as _);
6280 }
6281 }
6282 }
6283 else if arg2.is_register_hl() {
6284 bytes.push(0b0010_0010);
6285 add_word(&mut bytes, address as _);
6286 }
6287 else if arg2.is_register16() {
6288 let reg = arg2.get_register16().unwrap();
6289 {
6290 bytes.push(0xED);
6291 bytes.push(0b0100_0011 | (register16_to_code_with_sp(reg) << 4));
6292 add_word(&mut bytes, address as _);
6293 }
6294 }
6295 else if arg2.is_register_a() {
6296 bytes.push(0x32);
6297 add_word(&mut bytes, address as _);
6298 }
6299 }
6300 else if arg1.is_register_i() {
6301 assert!(arg2.is_register_a());
6302 {
6303 bytes.push(0xED);
6304 bytes.push(0x47)
6305 }
6306 }
6307 else if arg1.is_register_r() {
6308 assert!(arg2.is_register_a());
6309 {
6310 bytes.push(0xED);
6311 bytes.push(0x4F)
6312 }
6313 }
6314
6315 if bytes.is_empty() {
6317 if arg1.is_register16() && arg2.is_register16() {
6318 let dst = arg1.get_register16().unwrap();
6319 let src = arg2.get_register16().unwrap();
6320 {
6321 bytes.extend(assemble_ld(
6322 &DataAccess::Register8(dst.low().unwrap()),
6323 &DataAccess::Register8(src.low().unwrap()),
6324 env
6325 )?);
6326 bytes.extend(assemble_ld(
6327 &DataAccess::Register8(dst.high().unwrap()),
6328 &DataAccess::Register8(src.high().unwrap()),
6329 env
6330 )?);
6331 }
6332 }
6333 else if (arg1.is_register_hl() && arg2.is_indexregister16())
6334 || (arg1.is_indexregister16() && arg2.is_register_hl())
6335 || (arg1.is_indexregister16() && arg2.is_indexregister16())
6336 {
6337 bytes.extend(assemble_push(arg2)?);
6338 bytes.extend(assemble_pop(arg1)?);
6339 }
6340 else if arg1.is_register16() && arg2.is_indexregister16() {
6341 let dst = arg1.get_register16().unwrap();
6342 let src = arg2.get_indexregister16().unwrap();
6343
6344 bytes.extend(
6345 assemble_ld(
6346 &DataAccess::Register8(dst.low().unwrap()),
6347 &DataAccess::IndexRegister8(src.low()),
6348 env
6349 )?
6350 .iter()
6351 .cloned()
6352 );
6353 bytes.extend(
6354 assemble_ld(
6355 &DataAccess::Register8(dst.high().unwrap()),
6356 &DataAccess::IndexRegister8(src.high()),
6357 env
6358 )?
6359 .iter()
6360 .cloned()
6361 );
6362 }
6363 else if arg1.is_indexregister16() && arg2.is_register16() {
6364 let dst = arg1.get_indexregister16().unwrap();
6365 let _res = arg2.get_register16().unwrap();
6366 let src = arg2.get_register16().unwrap();
6367
6368 {
6370 bytes.extend(assemble_ld(
6371 &DataAccess::IndexRegister8(dst.low()),
6372 &DataAccess::Register8(src.low().unwrap()),
6373 env
6374 )?);
6375 bytes.extend(assemble_ld(
6376 &DataAccess::IndexRegister8(dst.high()),
6377 &DataAccess::Register8(src.high().unwrap()),
6378 env
6379 )?);
6380 }
6381 }
6382 else if arg1.is_register16() && arg2.is_indexregister_with_index() {
6383 let dst = arg1.get_register16().unwrap();
6384 let src = arg2.get_indexregister16().unwrap();
6385 let idx = arg2.get_index().unwrap();
6386
6387 {
6388 bytes.extend(assemble_ld(
6389 &DataAccess::Register8(dst.low().unwrap()),
6390 &DataAccess::IndexRegister16WithIndex(src, idx.0, idx.1.to_expr().into_owned()),
6391 env
6392 )?);
6393 bytes.extend(assemble_ld(
6394 &DataAccess::Register8(dst.high().unwrap()),
6395 &DataAccess::IndexRegister16WithIndex(
6396 src,
6397 idx.0,
6398 idx.1.to_expr().into_owned().add(1)
6399 ),
6400 env
6401 )?);
6402 }
6403 }
6404 else if arg1.is_indexregister_with_index() && arg2.is_register16() {
6405 let dst = arg1.get_indexregister16().unwrap();
6406 let index = arg1.get_index().unwrap();
6407 let src = arg2.get_register16().unwrap();
6408 {
6409 bytes.extend(assemble_ld(
6410 &DataAccess::IndexRegister16WithIndex(
6411 dst,
6412 index.0,
6413 index.1.to_expr().into_owned()
6414 ),
6415 &DataAccess::Register8(src.low().unwrap()),
6416 env
6417 )?);
6418 bytes.extend(assemble_ld(
6419 &DataAccess::IndexRegister16WithIndex(
6420 dst,
6421 index.0,
6422 index.1.to_expr().into_owned().add(1)
6423 ),
6424 &DataAccess::Register8(src.high().unwrap()),
6425 env
6426 )?);
6427 }
6428 }
6429 else if arg1.is_register16()
6430 && arg2.is_address_in_indexregister16()
6431 && arg2.get_register16().unwrap() == Register16::Hl
6432 {
6433 let dst = arg1.get_register16().unwrap();
6434 {
6435 bytes.extend(
6436 assemble_ld(
6437 &DataAccess::Register8(dst.low().unwrap()),
6438 &DataAccess::MemoryRegister16(Register16::Hl),
6439 env
6440 )?
6441 .iter()
6442 .cloned()
6443 );
6444 bytes.extend(assemble_inc_dec(
6445 Mnemonic::Inc,
6446 &DataAccess::Register16(Register16::Hl),
6447 env
6448 )?);
6449 bytes.extend(
6450 assemble_ld(
6451 &DataAccess::Register8(dst.high().unwrap()),
6452 &DataAccess::MemoryRegister16(Register16::Hl),
6453 env
6454 )?
6455 .iter()
6456 .cloned()
6457 );
6458 bytes.extend(assemble_inc_dec(
6459 Mnemonic::Dec,
6460 &DataAccess::Register16(Register16::Hl),
6461 env
6462 )?);
6463 }
6464 }
6465 else if arg2.is_register16()
6466 && arg1.is_address_in_indexregister16()
6467 && arg1.get_register16().unwrap() == Register16::Hl
6468 {
6469 let src = arg2.get_register16().unwrap();
6470 bytes.extend(
6471 assemble_ld(
6472 &DataAccess::MemoryRegister16(Register16::Hl),
6473 &DataAccess::Register8(src.low().unwrap()),
6474 env
6475 )?
6476 .iter()
6477 .cloned()
6478 );
6479 bytes.extend(assemble_inc_dec(
6480 Mnemonic::Inc,
6481 &DataAccess::Register16(Register16::Hl),
6482 env
6483 )?);
6484 bytes.extend(
6485 assemble_ld(
6486 &DataAccess::MemoryRegister16(Register16::Hl),
6487 &DataAccess::Register8(src.high().unwrap()),
6488 env
6489 )?
6490 .iter()
6491 .cloned()
6492 );
6493 bytes.extend(assemble_inc_dec(
6494 Mnemonic::Dec,
6495 &DataAccess::Register16(Register16::Hl),
6496 env
6497 )?);
6498 }
6499 }
6500
6501 if bytes.is_empty() {
6502 Err(AssemblerError::BugInAssembler {
6503 file: file!(),
6504 line: line!(),
6505 msg: format!("LD: not properly implemented for '{:?}, {:?}'", arg1, arg2)
6506 })
6507 }
6508 else {
6509 Ok(bytes)
6510 }
6511}
6512
6513fn assemble_in<D: DataAccessElem>(
6514 arg1: &D,
6515 arg2: &D,
6516 env: &mut Env
6517) -> Result<Bytes, AssemblerError>
6518where
6519 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
6520{
6521 let mut bytes = Bytes::new();
6522
6523 if arg1.is_expression() {
6524 assert_eq!(
6525 env.resolve_expr_must_never_fail(arg1.get_expression().unwrap())?,
6526 ExprResult::from(0)
6527 );
6528 assert!(arg2.is_port_c());
6529 bytes.push(0xED);
6530 bytes.push(0x70);
6531 }
6532 else if arg2.is_port_c() && arg1.is_register8() {
6533 let reg = arg1.get_register8().unwrap();
6534 {
6535 bytes.push(0xED);
6536 bytes.push(0b0100_0000 | (register8_to_code(reg) << 3))
6537 }
6538 }
6539 else if arg2.is_port_n() {
6540 let exp = arg2.get_expression().unwrap();
6541 {
6542 if arg1.is_register_a() {
6543 let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
6544 bytes.push(0xDB);
6545 bytes.push(val);
6546 }
6547 }
6548 }
6549
6550 if bytes.is_empty() {
6551 Err(AssemblerError::BugInAssembler {
6552 file: file!(),
6553 line: line!(),
6554 msg: format!("IN: not properly implemented for '{:?}, {:?}'", arg1, arg2)
6555 })
6556 }
6557 else {
6558 Ok(bytes)
6559 }
6560}
6561
6562fn assemble_out<D: DataAccessElem>(
6563 arg1: &D,
6564 arg2: &D,
6565 env: &mut Env
6566) -> Result<Bytes, AssemblerError>
6567where
6568 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
6569{
6570 let mut bytes = Bytes::new();
6571
6572 if arg2.is_expression() {
6573 assert_eq!(
6574 env.resolve_expr_must_never_fail(arg2.get_expression().unwrap())?,
6575 0.into()
6576 );
6577 assert!(arg1.is_port_c());
6578 bytes.push(0xED);
6579 bytes.push(0x71);
6580 }
6581 else if arg1.is_port_c() {
6582 if arg2.is_register8() {
6583 let reg = arg2.get_register8().unwrap();
6584 bytes.push(0xED);
6585 bytes.push(0b0100_0001 | (register8_to_code(reg) << 3))
6586 }
6587 }
6588 else if arg1.is_port_n() {
6589 let exp = arg1.get_expression().unwrap();
6590 {
6591 if arg2.is_register_a() {
6592 let val = (env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF) as u8;
6593 bytes.push(0xD3);
6594 bytes.push(val);
6595 }
6596 }
6597 }
6598
6599 if bytes.is_empty() {
6600 Err(AssemblerError::BugInAssembler {
6601 file: file!(),
6602 line: line!(),
6603 msg: format!("OUT: not properly implemented for '{:?}, {:?}'", arg1, arg2)
6604 })
6605 }
6606 else {
6607 Ok(bytes)
6608 }
6609}
6610
6611fn assemble_pop<D: DataAccessElem>(arg1: &D) -> Result<Bytes, AssemblerError> {
6612 let mut bytes = Bytes::new();
6613
6614 if arg1.is_register16() {
6615 let reg = arg1.get_register16().unwrap();
6616 let byte = 0b1100_0001 | (register16_to_code_with_af(reg) << 4);
6617 bytes.push(byte);
6618 }
6619 else if arg1.is_indexregister16() {
6620 let reg = arg1.get_indexregister16().unwrap();
6621 bytes.push(indexed_register16_to_code(reg));
6622 bytes.push(0xE1);
6623 }
6624 else {
6625 return Err(AssemblerError::InvalidArgument {
6626 msg: format!("POP: not implemented for {:?}", arg1)
6627 });
6628 }
6629
6630 Ok(bytes)
6631}
6632
6633fn assemble_push<D: DataAccessElem>(arg1: &D) -> Result<Bytes, AssemblerError> {
6634 let mut bytes = Bytes::new();
6635
6636 if arg1.is_register16() {
6637 let reg = arg1.get_register16().unwrap();
6638 let byte = 0b1100_0101 | (register16_to_code_with_af(reg) << 4);
6639 bytes.push(byte);
6640 }
6641 else if arg1.is_indexregister16() {
6642 let reg = arg1.get_indexregister16().unwrap();
6643 bytes.push(indexed_register16_to_code(reg));
6644 bytes.push(0xE5);
6645 }
6646 else {
6647 return Err(AssemblerError::InvalidArgument {
6648 msg: format!("PUSH: not implemented for {:?}", arg1)
6649 });
6650 }
6651
6652 Ok(bytes)
6653}
6654
6655fn assemble_logical_operator<D: DataAccessElem>(
6656 mnemonic: Mnemonic,
6657 arg1: &D,
6658 env: &mut Env
6659) -> Result<Bytes, AssemblerError>
6660where
6661 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
6662{
6663 let mut bytes = Bytes::new();
6664
6665 let memory_code = || {
6666 match mnemonic {
6667 Mnemonic::And => 0xA6,
6668 Mnemonic::Or => 0xB6,
6669 Mnemonic::Xor => 0xAE,
6670 _ => unreachable!()
6671 }
6672 };
6673
6674 if arg1.is_register8() {
6675 let reg = arg1.get_register8().unwrap();
6676 {
6677 let base = match mnemonic {
6678 Mnemonic::And => 0b1010_0000,
6679 Mnemonic::Or => 0b1011_0000,
6680 Mnemonic::Xor => 0b1010_1000,
6681 _ => unreachable!()
6682 };
6683 bytes.push(base + register8_to_code(reg));
6684 }
6685 }
6686 else if arg1.is_indexregister8() {
6687 let reg = arg1.get_indexregister8().unwrap();
6688 {
6689 bytes.push(indexed_register16_to_code(reg.complete()));
6690 let base = match mnemonic {
6691 Mnemonic::And => 0b1010_0000,
6692 Mnemonic::Or => 0b1011_0000,
6693 Mnemonic::Xor => 0b1010_1000,
6694 _ => unreachable!()
6695 };
6696 bytes.push(base + indexregister8_to_code(reg));
6697 }
6698 }
6699 else if arg1.is_expression() {
6700 let exp = arg1.get_expression().unwrap();
6701
6702 {
6703 let base = match mnemonic {
6704 Mnemonic::And => 0xE6,
6705 Mnemonic::Or => 0xF6,
6706 Mnemonic::Xor => 0xEE,
6707 _ => unreachable!()
6708 };
6709 let value = env.resolve_expr_may_fail_in_first_pass(exp)?.int()? & 0xFF;
6710 bytes.push(base);
6711 bytes.push(value as u8);
6712 }
6713 }
6714 else if arg1.is_address_in_register16() {
6715 assert_eq!(arg1.get_register16(), Some(Register16::Hl));
6716
6717 {
6718 bytes.push(memory_code());
6719 }
6720 }
6721 else if arg1.is_indexregister_with_index() {
6722 let reg = arg1.get_indexregister16().unwrap();
6723 let idx = arg1.get_index().unwrap();
6724
6725 {
6726 let value = env.resolve_index_may_fail_in_first_pass(idx)?.int()? & 0xFF;
6727 bytes.push(indexed_register16_to_code(reg));
6728 bytes.push(memory_code());
6729 bytes.push(value as u8);
6730 }
6731 }
6732 else {
6733 unreachable!()
6734 }
6735
6736 Ok(bytes)
6737}
6738
6739fn assemble_ex_memsp<D: DataAccessElem>(arg1: &D) -> Result<Bytes, AssemblerError> {
6740 let mut bytes = Bytes::new();
6741
6742 if let Some(reg) = arg1.get_indexregister16() {
6743 bytes.push(indexed_register16_to_code(reg));
6744 }
6745
6746 bytes.push(0xE3);
6747 Ok(bytes)
6748}
6749
6750fn assemble_add_or_adc<D: DataAccessElem>(
6751 mnemonic: Mnemonic,
6752 arg1: Option<&D>,
6753 arg2: &D,
6754 env: &mut Env
6755) -> Result<Bytes, AssemblerError>
6756where
6757 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt + ExprElement
6758{
6759 let mut bytes = Bytes::new();
6760 let is_add = match mnemonic {
6761 Mnemonic::Add => true,
6762 Mnemonic::Adc => false,
6763 _ => panic!("Impossible case")
6764 };
6765
6766 if arg1.is_none() || arg1.as_ref().map(|arg1| arg1.is_register_a()).unwrap() {
6767 if arg2.is_address_in_hl() {
6768 if is_add {
6769 bytes.push(0b1000_0110);
6770 }
6771 else {
6772 bytes.push(0b1000_1110);
6773 }
6774 }
6775 else if arg2.is_indexregister_with_index() {
6776 let reg = arg2.get_indexregister16().unwrap();
6777 let idx = arg2.get_index().unwrap();
6778
6779 {
6780 let val = env.resolve_index_may_fail_in_first_pass(idx)?.int()?;
6781
6782 bytes.push(indexed_register16_to_code(reg));
6784 if is_add {
6785 bytes.push(0b1000_0110);
6786 }
6787 else {
6788 bytes.push(0x8E);
6789 }
6790 add_index(&mut bytes, val)?;
6791 }
6792 }
6793 else if arg2.is_expression() {
6794 let exp = arg2.get_expression().unwrap();
6795 {
6796 let val = env.resolve_expr_may_fail_in_first_pass(exp)?.int()? as u8;
6797 if is_add {
6798 bytes.push(0b1100_0110);
6799 }
6800 else {
6801 bytes.push(0xCE);
6802 }
6803 bytes.push(val);
6804 }
6805 }
6806 else if arg2.is_register8() {
6807 let reg = arg2.get_register8().unwrap();
6808 {
6809 let base = if is_add { 0b1000_0000 } else { 0b1000_1000 };
6810 bytes.push(base | register8_to_code(reg));
6811 }
6812 }
6813 else if arg2.is_indexregister8() {
6814 let reg = arg2.get_indexregister8().unwrap();
6815
6816 {
6817 bytes.push(indexed_register16_to_code(reg.complete()));
6818 let base = if is_add { 0b1000_0000 } else { 0b1000_1000 };
6819 bytes.push(base | indexregister8_to_code(reg));
6820 }
6821 }
6822 }
6823 else if arg1.as_ref().unwrap().is_register_hl() {
6824 if arg2.is_register16() {
6825 let reg = arg2.get_register16().unwrap();
6826 let base = if is_add {
6827 0b0000_1001
6828 }
6829 else {
6830 bytes.push(0xED);
6831 0b0100_1010
6832 };
6833
6834 bytes.push(base | (register16_to_code_with_sp(reg) << 4));
6835 }
6836 }
6837 else if arg1.as_ref().unwrap().is_indexregister16() {
6838 let reg1 = arg1.as_ref().unwrap().get_indexregister16().unwrap();
6839 {
6840 if arg2.is_register16() {
6841 let reg2 = arg2.get_register16().unwrap();
6842 {
6843 bytes.push(indexed_register16_to_code(reg1));
6845 let base = if is_add {
6846 0b0000_1001
6847 }
6848 else {
6849 panic!();
6850 };
6851 bytes.push(
6852 base | (register16_to_code_with_indexed(&DataAccess::Register16(reg2))
6853 << 4)
6854 )
6855 }
6856 }
6857 else if arg2.is_indexregister16() {
6858 let reg2 = arg2.get_indexregister16().unwrap();
6859
6860 {
6861 if reg1 != reg2 {
6862 return Err(AssemblerError::InvalidArgument {
6863 msg: "Unable to add different indexed registers".to_owned()
6864 });
6865 }
6866
6867 bytes.push(indexed_register16_to_code(reg1));
6868 let base = if is_add {
6869 0b0000_1001
6870 }
6871 else {
6872 panic!();
6873 };
6874 bytes.push(
6875 base | (register16_to_code_with_indexed(&DataAccess::IndexRegister16(
6876 reg2
6877 )) << 4)
6878 )
6879 }
6880 }
6881 }
6882 }
6883
6884 if bytes.is_empty() {
6885 Err(AssemblerError::BugInAssembler {
6886 file: file!(),
6887 line: line!(),
6888 msg: format!("{:?} not implemented for {:?} {:?}", mnemonic, arg1, arg2)
6889 })
6890 }
6891 else {
6892 Ok(bytes)
6893 }
6894}
6895
6896fn assemble_bit_res_or_set<D: DataAccessElem>(
6897 mnemonic: Mnemonic,
6898 arg1: &D,
6899 arg2: &D,
6900 hidden: Option<&Register8>,
6901 env: &mut Env
6902) -> Result<Bytes, AssemblerError>
6903where
6904 <D as cpclib_tokens::DataAccessElem>::Expr: ExprEvaluationExt
6905{
6906 let mut bytes = Bytes::new();
6907
6908 let bit = match arg1.get_expression() {
6910 Some(e) => {
6911 let bit = (env.resolve_expr_may_fail_in_first_pass(e)?.int()? & 0xFF) as u8;
6912 if bit > 7 {
6913 return Err(AssemblerError::InvalidArgument {
6914 msg: format!("{}: {} is an invalid value", mnemonic, bit)
6915 });
6916 }
6917 bit
6918 },
6919 _ => unreachable!()
6920 };
6921
6922 let code = match mnemonic {
6925 Mnemonic::Res => 0b1000_0000,
6926 Mnemonic::Set => 0b1100_0000,
6927 Mnemonic::Bit => 0b0100_0000,
6928 _ => unreachable!()
6929 };
6930
6931 if let Some(ref reg) = arg2.get_register8() {
6933 bytes.push(0xCB);
6936 bytes.push(code | (bit << 3) | register8_to_code(*reg))
6937 }
6938 else {
6939 assert!(arg2.is_address_in_register16() || arg2.is_indexregister_with_index());
6940 let mut code = code + 0b0110;
6941
6942 if arg2.is_indexregister_with_index() {
6943 let reg = arg2.get_indexregister16().unwrap();
6944 let idx = arg2.get_index().unwrap();
6945
6946 bytes.push(indexed_register16_to_code(reg));
6947 add_byte(&mut bytes, 0xCB);
6948 let delta = (env.resolve_index_may_fail_in_first_pass(idx)?.int()? & 0xFF) as u8;
6949 add_byte(&mut bytes, delta);
6950
6951 if hidden.is_some() {
6953 let fix: i8 = match hidden.unwrap() {
6954 Register8::A => 1,
6955 Register8::L => -1,
6956 Register8::H => -2,
6957 Register8::E => -3,
6958 Register8::D => -4,
6959 Register8::C => -5,
6960 Register8::B => -6
6961 };
6962 if fix < 0 {
6963 code -= fix.unsigned_abs();
6964 }
6965 else {
6966 code += fix as u8;
6967 }
6968 }
6969 }
6970 else {
6971 bytes.push(0xCB);
6972 }
6973
6974 bytes.push(code | (bit << 3));
6975 }
6976
6977 Ok(bytes)
6978}
6979
6980fn indexed_register16_to_code(reg: IndexRegister16) -> u8 {
6981 match reg {
6982 IndexRegister16::Ix => DD,
6983 IndexRegister16::Iy => FD
6984 }
6985}
6986
6987#[inline]
6996fn register8_to_code(reg: Register8) -> u8 {
6997 match reg {
6998 Register8::A => 0b111,
6999 Register8::B => 0b000,
7000 Register8::C => 0b001,
7001 Register8::D => 0b010,
7002 Register8::E => 0b011,
7003 Register8::H => 0b100,
7004 Register8::L => 0b101
7005 }
7006}
7007
7008#[inline]
7009fn indexregister8_to_code(reg: IndexRegister8) -> u8 {
7010 match reg {
7011 IndexRegister8::Ixh | IndexRegister8::Iyh => register8_to_code(Register8::H),
7012 IndexRegister8::Ixl | IndexRegister8::Iyl => register8_to_code(Register8::L)
7013 }
7014}
7015
7016fn register16_to_code_with_af(reg: Register16) -> u8 {
7018 match reg {
7019 Register16::Bc => 0b00,
7020 Register16::De => 0b01,
7021 Register16::Hl => 0b10,
7022 Register16::Af => 0b11,
7023 _ => panic!("no mapping for {:?}", reg)
7024 }
7025}
7026
7027fn register16_to_code_with_sp(reg: Register16) -> u8 {
7028 match reg {
7029 Register16::Bc => 0b00,
7030 Register16::De => 0b01,
7031 Register16::Hl => 0b10,
7032 Register16::Sp => 0b11,
7033 _ => panic!("no mapping for {:?}", reg)
7034 }
7035}
7036
7037fn register16_to_code_with_indexed<D: DataAccessElem>(reg: &D) -> u8 {
7038 if reg.is_register_bc() {
7039 0b00
7040 }
7041 else if reg.is_register_de() {
7042 0b01
7043 }
7044 else if reg.is_indexregister16() {
7045 0b10
7046 }
7047 else if reg.is_register_sp() {
7048 0b11
7049 }
7050 else {
7051 panic!("no mapping for {:?}", reg)
7052 }
7053}
7054
7055fn flag_test_to_code(flag: FlagTest) -> u8 {
7056 match flag {
7057 FlagTest::NZ => 0b000,
7058 FlagTest::Z => 0b001,
7059 FlagTest::NC => 0b010,
7060 FlagTest::C => 0b011,
7061
7062 FlagTest::PO => 0b100,
7064 FlagTest::PE => 0b101,
7065 FlagTest::P => 0b110,
7066 FlagTest::M => 0b111
7067 }
7068}
7069
7070#[cfg(test_to_clean)]
7072#[allow(deprecated)]
7073mod test {
7074
7075 use super::processed_token::build_processed_token;
7076 use super::*;
7077
7078 fn visit_token(token: &Token, env: &mut Env) -> Result<(), AssemblerError> {
7079 let mut processed = build_processed_token(token, env);
7080 processed.visited(env)
7081 }
7082
7083 fn visit_tokens(tokens: &[Token]) -> Result<Env, AssemblerError> {
7084 let mut env = Env::default();
7085 for t in tokens {
7086 visit_token(t, &mut env)?;
7087 }
7088 Ok(env)
7089 }
7090
7091 #[test]
7092 pub fn test_inc_b() {
7093 let mut env = Env::default();
7094 let res = assemble_inc_dec(
7095 Mnemonic::Inc,
7096 &DataAccess::Register8(Register8::B),
7097 &mut env
7098 )
7099 .unwrap();
7100 assert_eq!(res.len(), 1);
7101 assert_eq!(res[0], 0x04);
7102 }
7103
7104 #[test]
7105 pub fn test_pop() {
7106 let res = assemble_pop(&DataAccess::Register16(Register16::Af)).unwrap();
7107 assert_eq!(res.len(), 1);
7108 assert_eq!(res[0], 0b1111_0001);
7109 }
7110
7111 #[test]
7112 fn test_jump() {
7113 let res = assemble_call_jr_or_jp(
7114 Mnemonic::Jp,
7115 Some(&DataAccess::FlagTest(FlagTest::Z)),
7116 &DataAccess::Expression(Expr::Value(0x1234)),
7117 &mut Env::default()
7118 )
7119 .unwrap();
7120 assert_eq!(res.len(), 3);
7121 assert_eq!(res[0], 0b1100_1010);
7122 assert_eq!(res[1], 0x34);
7123 assert_eq!(res[2], 0x12);
7124 }
7125
7126 #[test]
7127 pub fn test_assert() {
7128 let mut env = Env::default();
7129 env.start_new_pass();
7130
7131 assert!(
7132 visit_assert(
7133 &Expr::BinaryOperation(
7134 BinaryOperation::Equal,
7135 Box::new(0i32.into()),
7136 Box::new(0i32.into())
7137 ),
7138 None,
7139 &mut env,
7140 None
7141 )
7142 .unwrap()
7143 );
7144 assert!(
7145 !visit_assert(
7146 &Expr::BinaryOperation(
7147 BinaryOperation::Equal,
7148 Box::new(1i32.into()),
7149 Box::new(0i32.into())
7150 ),
7151 None,
7152 &mut env,
7153 None
7154 )
7155 .unwrap()
7156 );
7157 }
7158
7159 #[test]
7160 pub fn test_undef() {
7161 let mut env = Env::default();
7162 env.start_new_pass();
7163
7164 env.visit_label("toto").unwrap();
7165 assert!(env.symbols().contains_symbol("toto").unwrap());
7166 env.visit_undef("toto").unwrap();
7167 assert!(!env.symbols().contains_symbol("toto").unwrap());
7168 assert!(env.visit_undef("toto").is_err());
7169 }
7170
7171 #[test]
7172 pub fn test_inc_dec() {
7173 let env = Env::default();
7174 let res =
7175 assemble_inc_dec(Mnemonic::Inc, &DataAccess::Register16(Register16::De), &env).unwrap();
7176 assert_eq!(res.len(), 1);
7177 assert_eq!(res[0], 0x13);
7178
7179 let res =
7180 assemble_inc_dec(Mnemonic::Dec, &DataAccess::Register8(Register8::B), &env).unwrap();
7181 assert_eq!(res.len(), 1);
7182 assert_eq!(res[0], 0x05);
7183 }
7184
7185 #[test]
7186 pub fn test_res() {
7187 let env = Env::default();
7188 let res = assemble_bit_res_or_set(
7189 Mnemonic::Res,
7190 &DataAccess::Expression(0.into()),
7191 &DataAccess::Register8(Register8::B),
7192 None,
7193 &env
7194 )
7195 .unwrap();
7196
7197 assert_eq!(res.as_ref(), &[0xCB, 0b10000000]);
7198
7199 let env = Env::default();
7200 let res = assemble_bit_res_or_set(
7201 Mnemonic::Res,
7202 &DataAccess::Expression(2.into()),
7203 &DataAccess::Register8(Register8::C),
7204 None,
7205 &env
7206 )
7207 .unwrap();
7208
7209 assert_eq!(res.as_ref(), &[0xCB, 0b10010001]);
7210
7211 let env = Env::default();
7212 let res = assemble_bit_res_or_set(
7213 Mnemonic::Res,
7214 &DataAccess::Expression(2.into()),
7215 &DataAccess::MemoryRegister16(Register16::Hl),
7216 None,
7217 &env
7218 )
7219 .unwrap();
7220
7221 assert_eq!(res.as_ref(), &[0xCB, 0b10010110]);
7222
7223 let env = Env::default();
7224 let res = assemble_bit_res_or_set(
7225 Mnemonic::Res,
7226 &DataAccess::Expression(2.into()),
7227 &DataAccess::IndexRegister16WithIndex(IndexRegister16::Ix, 3.into()),
7228 None,
7229 &env
7230 )
7231 .unwrap();
7232
7233 assert_eq!(res.as_ref(), &[DD, 0xCB, 3, 0b10010110]);
7234
7235 let env = Env::default();
7236 let res = assemble_bit_res_or_set(
7237 Mnemonic::Res,
7238 &DataAccess::Expression(2.into()),
7239 &DataAccess::IndexRegister16WithIndex(IndexRegister16::Ix, 3.into()),
7240 Some(&Register8::B),
7241 &env
7242 )
7243 .unwrap();
7244
7245 assert_eq!(res.as_ref(), &[DD, 0xCB, 3, 0b10010000]);
7246 }
7247
7248 #[test]
7249 pub fn test_ld() {
7250 let res = assemble_ld(
7251 &DataAccess::Register16(Register16::De),
7252 &DataAccess::Expression(Expr::Value(0x1234)),
7253 &Env::default()
7254 )
7255 .unwrap();
7256 assert_eq!(res.len(), 3);
7257 assert_eq!(res[0], 0x11);
7258 assert_eq!(res[1], 0x34);
7259 assert_eq!(res[2], 0x12);
7260 }
7261
7262 #[test]
7263 #[should_panic]
7264 pub fn test_ld_fail() {
7265 let _res = assemble_ld(
7266 &DataAccess::Register16(Register16::Af),
7267 &DataAccess::Expression(Expr::Value(0x1234)),
7268 &Env::default()
7269 )
7270 .unwrap();
7271 }
7272
7273 #[test]
7274 pub fn test_ld_r16_r16() {
7275 let res = assemble_ld(
7276 &DataAccess::Register16(Register16::De),
7277 &DataAccess::Register16(Register16::Hl),
7278 &Env::default()
7279 )
7280 .unwrap();
7281 assert_eq!(res.len(), 2);
7282 }
7283
7284 #[test]
7285 pub fn test_repeat() {
7286 let tokens = vec![
7287 Token::Org(0.into(), None),
7288 Token::Repeat(
7289 10.into(),
7290 vec![Token::OpCode(Mnemonic::Nop, None, None, None)].into(),
7291 None,
7292 None
7293 ),
7294 ];
7295
7296 let count = visit_tokens(&tokens).unwrap().size();
7297 assert_eq!(count, 10);
7298 }
7299
7300 #[test]
7301 pub fn test_double_repeat() {
7302 let tokens = vec![
7303 Token::Org(0.into(), None),
7304 Token::Repeat(
7305 10.into(),
7306 vec![Token::Repeat(
7307 10.into(),
7308 vec![Token::OpCode(Mnemonic::Nop, None, None, None)].into(),
7309 None,
7310 None
7311 )]
7312 .into(),
7313 None,
7314 None
7315 ),
7316 ];
7317
7318 let count = visit_tokens(&tokens).unwrap().size();
7319 assert_eq!(count, 100);
7320 }
7321
7322 #[test]
7323 pub fn test_assemble_logical_operator() {
7324 let operators = [Mnemonic::And, Mnemonic::Or, Mnemonic::Xor];
7325 let operands = [
7326 DataAccess::Register8(Register8::A),
7327 DataAccess::Expression(0.into()),
7328 DataAccess::MemoryRegister16(Register16::Hl),
7329 DataAccess::IndexRegister16WithIndex(IndexRegister16::Ix, 2.into())
7330 ];
7331
7332 for operator in &operators {
7333 for operand in &operands {
7334 let token = Token::OpCode(*operator, Some(operand.clone()), None, None);
7335 visit_tokens(&[token]).unwrap();
7336 }
7337 }
7338 }
7339
7340 #[test]
7341 pub fn test_count() {
7342 let tokens = vec![
7343 Token::Org(0.into(), None),
7344 Token::OpCode(Mnemonic::Nop, None, None, None),
7345 Token::OpCode(Mnemonic::Nop, None, None, None),
7346 Token::OpCode(Mnemonic::Nop, None, None, None),
7347 Token::OpCode(Mnemonic::Nop, None, None, None),
7348 Token::OpCode(Mnemonic::Nop, None, None, None),
7349 Token::OpCode(Mnemonic::Nop, None, None, None),
7350 Token::OpCode(Mnemonic::Nop, None, None, None),
7351 Token::OpCode(Mnemonic::Nop, None, None, None),
7352 Token::OpCode(Mnemonic::Nop, None, None, None),
7353 Token::OpCode(Mnemonic::Nop, None, None, None),
7354 ];
7355
7356 let count = visit_tokens(&tokens).unwrap().size();
7357 assert_eq!(count, 10);
7358 }
7359
7360 #[test]
7361 pub fn test_stableticker() {
7362 let tokens = vec![
7363 Token::StableTicker(StableTickerAction::Start("myticker".into())),
7364 Token::OpCode(
7365 Mnemonic::Inc,
7366 Some(DataAccess::Register16(Register16::Hl)),
7367 None,
7368 None
7369 ),
7370 Token::StableTicker(StableTickerAction::Stop),
7371 ];
7372
7373 let env = visit_tokens(&tokens);
7374 assert!(env.is_ok());
7375 let env = env.unwrap();
7376
7377 let val = env.symbols().int_value("myticker");
7378 assert_eq!(val.unwrap().unwrap(), 2);
7379 }
7380
7381 #[test]
7382 pub fn basic_no_variable() {
7383 let tokens = vec![Token::Basic(None, None, "10 PRINT &DEAD".to_owned())];
7384
7385 let env = visit_tokens(&tokens);
7386 println!("{:?}", env);
7387 assert!(env.is_ok());
7388 }
7389
7390 #[test]
7391 pub fn basic_variable_unset() {
7392 let tokens = vec![Token::Basic(
7393 Some(vec!["STUFF".into()]),
7394 None,
7395 "10 PRINT {STUFF}".to_owned()
7396 )];
7397
7398 let env = visit_tokens(&tokens);
7399 println!("{:?}", env);
7400 assert!(env.is_err());
7401 }
7402
7403 #[test]
7404 pub fn basic_variable_set() {
7405 let tokens = vec![
7406 Token::Label("STUFF".into()),
7407 Token::Basic(Some(vec!["STUFF".into()]), None, "10 PRINT {STUFF}".into()),
7408 ];
7409
7410 let env = visit_tokens(&tokens);
7411 println!("{:?}", env);
7412 assert!(env.is_ok());
7413 }
7414
7415 #[test]
7416 pub fn test_duration() {
7417 let tokens = vec![Token::OpCode(
7418 Mnemonic::Ld,
7419 Some(DataAccess::Register8(Register8::A)),
7420 Some(DataAccess::Expression(Expr::UnaryTokenOperation(
7421 UnaryTokenOperation::Duration,
7422 Box::new(Token::OpCode(
7423 Mnemonic::Inc,
7424 Some(DataAccess::Register16(Register16::Hl)),
7425 None,
7426 None
7427 ))
7428 ))),
7429 None
7430 )];
7431
7432 let env = visit_tokens(&tokens);
7433 assert!(env.is_ok());
7434 let env = env.unwrap();
7435 let bytes = env.memory(0, 2);
7436 assert_eq!(bytes[1], 2);
7437 }
7438
7439 #[test]
7440 pub fn test_opcode() {
7441 let tokens = vec![Token::OpCode(
7442 Mnemonic::Ld,
7443 Some(DataAccess::Register8(Register8::A)),
7444 Some(DataAccess::Expression(Expr::UnaryTokenOperation(
7445 UnaryTokenOperation::Opcode,
7446 Box::new(Token::OpCode(
7447 Mnemonic::Inc,
7448 Some(DataAccess::Register16(Register16::Hl)),
7449 None,
7450 None
7451 ))
7452 ))),
7453 None
7454 )];
7455
7456 let env = visit_tokens(&tokens);
7457 assert!(env.is_ok());
7458 let env = env.unwrap();
7459 let bytes = env.memory(0, 2);
7460 assert_eq!(
7461 bytes[1],
7462 assemble_inc_dec(Mnemonic::Inc, &DataAccess::Register16(Register16::Hl), &env).unwrap()
7463 [0]
7464 );
7465 }
7466
7467 #[test]
7468 pub fn test_bytes() {
7469 let mut m = Bytes::new();
7470
7471 add_byte(&mut m, 2);
7472 assert_eq!(m.len(), 1);
7473 assert_eq!(m[0], 2);
7474
7475 add_word(&mut m, 0x1234);
7476 assert_eq!(m.len(), 3);
7477 assert_eq!(m[1], 0x34);
7478 assert_eq!(m[2], 0x12);
7479 }
7480
7481 #[test]
7482 pub fn test_labels() {
7483 let mut env = Env::default();
7484 let res = visit_token(&Token::Org(0x4000.into(), None), &mut env);
7485 assert!(res.is_ok());
7486 assert!(!env.symbols().contains_symbol("hello").unwrap());
7487 let res = visit_token(&Token::Label("hello".into()), &mut env);
7488 assert!(res.is_ok());
7489 assert!(env.symbols().contains_symbol("hello").unwrap());
7490 assert_eq!(env.symbols().int_value("hello").unwrap(), 0x4000.into());
7491 }
7492
7493 #[test]
7494 pub fn test_jr() {
7495 let res = dbg!(visit_tokens_all_passes(
7496 &[
7497 Token::Org(0x4000.into(), None),
7498 Token::OpCode(
7499 Mnemonic::Jr,
7500 None,
7501 Some(DataAccess::Expression(Expr::Label("$".into()))),
7502 None,
7503 ),
7504 ],
7505 ctx()
7506 ));
7507
7508 assert!(res.is_ok());
7509 let env = res.unwrap();
7510
7511 assert_eq!(
7512 env.memory(0x4000, 2),
7513 &[0x18, 0u8.wrapping_sub(1).wrapping_sub(1)]
7514 );
7515 }
7516
7517 #[test]
7519 pub fn label_exists() {
7520 let res = visit_tokens_all_passes(
7521 &[
7522 Token::Org(0x4000.into(), None),
7523 Token::Label("hello".into()),
7524 Token::Label("hello".into())
7525 ],
7526 ctx()
7527 );
7528 assert!(res.is_err());
7529 }
7530
7531 #[test]
7532 pub fn test_rorg() {
7533 let res = visit_tokens_all_passes(
7534 &[
7535 Token::Org(0x4000i32.into(), None),
7536 Token::Rorg(
7537 0x8000i32.into(),
7538 vec![Token::Defb(vec![Expr::Label("$".into())])].into()
7539 )
7540 ],
7541 ctx()
7542 );
7543 assert!(res.is_ok());
7544 }
7545
7546 #[test]
7547 pub fn test_two_passes() {
7548 let tokens = vec![
7549 Token::Org(0x123i32.into(), None),
7550 Token::OpCode(
7551 Mnemonic::Ld,
7552 Some(DataAccess::Register16(Register16::Hl)),
7553 Some(DataAccess::Expression(Expr::Label("test".into()))),
7554 None
7555 ),
7556 Token::Label("test".into()),
7557 ];
7558 let env = visit_tokens(&tokens);
7559 assert!(env.is_err());
7560
7561 let env = visit_tokens_all_passes(&tokens, ctx());
7562 assert!(env.is_ok());
7563 let env = env.ok().unwrap();
7564
7565 let count = env.size();
7566 assert_eq!(count, 3);
7567
7568 assert_eq!(
7569 env.symbols()
7570 .int_value(&"test".to_owned())
7571 .unwrap()
7572 .unwrap(),
7573 0x123 + 3
7574 );
7575 let buffer = env.memory(0x123, 3);
7576 assert_eq!(buffer[1], 0x23 + 3);
7577 assert_eq!(buffer[2], 0x1);
7578 }
7579
7580 #[test]
7581 fn test_read_bytes() {
7582 let tokens = vec![
7583 Token::Org(0x100.into(), None),
7584 Token::Defb(vec![1.into(), 2.into()]),
7585 Token::Defb(vec![3.into(), 4.into()]),
7586 ];
7587
7588 let env = visit_tokens(&tokens).unwrap();
7589 let bytes = env.memory(0x100, 4);
7590 assert_eq!(bytes, vec![1, 2, 3, 4]);
7591 }
7592
7593 #[test]
7594 pub fn test_undocumented_rlc() {
7595 let res = visit_tokens_all_passes(
7596 &[
7597 Token::Org(0x100.into(), None),
7598 Token::OpCode(
7599 Mnemonic::Rlc,
7600 Some(DataAccess::IndexRegister16WithIndex(
7601 IndexRegister16::Iy,
7602 2.into()
7603 )),
7604 Some(DataAccess::Register8(Register8::C)),
7605 None
7606 )
7607 ],
7608 ctx()
7609 );
7610 assert!(res.is_ok());
7611 let env = res.unwrap();
7612 let bytes = env.memory(0x100, 4);
7613 assert_eq!(bytes, vec![0xFD, 0xCB, 0x2, 0x1]);
7614 }
7615
7616 #[test]
7617 pub fn test_undocumented_res() {
7618 let res = visit_tokens_all_passes(
7620 &[
7621 Token::Org(0x100.into(), None),
7622 Token::OpCode(
7623 Mnemonic::Res,
7624 Some(DataAccess::Expression(4.into())),
7625 Some(DataAccess::MemoryRegister16(Register16::Hl)),
7626 None
7627 )
7628 ],
7629 ctx()
7630 );
7631 assert!(res.is_ok());
7632 let env = res.unwrap();
7633 let bytes = env.memory(0x100, 2);
7634 assert_eq!(bytes, vec![0xCB, 0xA6]);
7635
7636 let res = visit_tokens_one_pass(
7637 &[
7638 Token::Org(0x100.into(), None),
7639 Token::OpCode(
7640 Mnemonic::Res,
7641 Some(DataAccess::Expression(4.into())),
7642 Some(DataAccess::IndexRegister16WithIndex(
7643 IndexRegister16::Iy,
7644 2.into()
7645 )),
7646 Some(Register8::A)
7647 )
7648 ],
7649 ctx()
7650 );
7651 assert!(res.is_ok());
7652 let env = res.unwrap();
7653 let bytes = env.memory(0x100, 4);
7654 assert_eq!(bytes, vec![0xFD, 0xCB, 0x2, 0xA7]);
7655 }
7656}