diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f7896d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/Cargo.toml b/Cargo.toml index b88550f..308043b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,5 +21,8 @@ regex = "1" itertools = "0.13.0" [features] +default = [] +65C02 = [] atari2600 = [] atari7800 = [] +atarilynx = [ "65C02" ] diff --git a/src/assemble.rs b/src/assemble.rs index a87f713..30cb5d3 100644 --- a/src/assemble.rs +++ b/src/assemble.rs @@ -32,6 +32,8 @@ pub enum AsmMnemonic { STA, STX, STY, + #[cfg(feature = "65C02")] + STZ, TAX, TAY, TXA, @@ -63,6 +65,8 @@ pub enum AsmMnemonic { DEX, DEY, JMP, + #[cfg(feature = "65C02")] + BRA, JSR, RTS, RTI, @@ -236,15 +240,114 @@ impl AssemblyCode { Ok(s) } - pub fn optimize(&mut self) -> u32 { + pub(crate) fn distance(&self, inst: &AsmInstruction, position: usize) -> i32 { + let mut bytes_above = 0; + let mut bytes_below = 0; + let mut index_above = position; + let mut index_below = position + 1; + let mut reached_above = false; + let above; + let mut notfound = 0; + loop { + if !reached_above { + match &self.code[index_above] { + AsmLine::Label(l) => { + debug!("Iter above: {:?}", l); + if *l == inst.dasm_operand { + above = true; + break; + } + } + AsmLine::Inline(_, s) => { + bytes_above += s; + } + AsmLine::Instruction(k) => { + debug!("Iter above: {:?}", k); + bytes_above += k.nb_bytes; + } + _ => (), + } + } + match self.code.get(index_below) { + Some(AsmLine::Label(l)) => { + debug!("Iter below: {:?}", l); + if *l == inst.dasm_operand { + above = false; + break; + } + } + Some(AsmLine::Inline(_, s)) => { + bytes_below += s; + } + Some(AsmLine::Instruction(k)) => { + debug!("Iter below: {:?}", k); + bytes_below += k.nb_bytes; + } + None => notfound |= 2, + _ => (), + } + if index_above == 0 { + reached_above = true; + notfound |= 1; + } else { + index_above -= 1; + } + index_below += 1; + if notfound == 3 { + error!("Label {} not found", inst.dasm_operand); + unreachable!() + }; + } + // Ok, now we have the distance in bytes + if above { bytes_above as i32 } else { -(bytes_below as i32) } + } + + + #[cfg(feature = "65C02")] + fn optimize_jmp_bra(&mut self) { + let to_replace: Vec = self + .code + .iter() + .enumerate() + .filter_map(|(pos, line)| { + if let AsmLine::Instruction(jmp) = line { + if jmp.mnemonic == AsmMnemonic::JMP + && !jmp.protected + && (-127..=128).contains(&self.distance(jmp, pos)) + { + Some(pos) + } else { + None + } + } else { + None + } + }) + .collect(); + + for pos in to_replace { + if let AsmLine::Instruction(jmp) = &self.code[pos] { + self.code[pos] = AsmLine::Instruction(AsmInstruction { + mnemonic: AsmMnemonic::BRA, + dasm_operand: jmp.dasm_operand.clone(), + cycles: 3, + cycles_alt: Some(4), + nb_bytes: 2, + protected: false, + }); + } + } + } + + fn general_6502_optimizations(&mut self) -> u32 { let mut removed_instructions = 0u32; let mut accumulator = None; let mut x_register = None; let mut y_register = None; + let mut flags = FlagsState::Unknown; let mut iter = itertools::multipeek(self.code.iter_mut()); let mut first = iter.next(); - let mut flags = FlagsState::Unknown; - + loop { match &first { None => return removed_instructions, @@ -785,6 +888,15 @@ impl AssemblyCode { } } + pub fn optimize(&mut self) -> u32 { + let removed_instructions = self.general_6502_optimizations(); + + #[cfg(feature = "65C02")] + self.optimize_jmp_bra(); + + removed_instructions + } + pub fn check_branches(&mut self) -> u32 { // Loop until there is no problematic branch instruction let mut restart = true; @@ -810,69 +922,10 @@ impl AssemblyCode { | AsmMnemonic::BPL | AsmMnemonic::BCS | AsmMnemonic::BCC => { - // Ok, let's try to find the label above and under and try to count the bytes - let mut bytes_above = 0; - let mut bytes_below = 0; - let mut index_above = position; - let mut index_below = position + 1; - let mut reached_above = false; - let above; - let mut notfound = 0; - loop { - if !reached_above { - match &self.code[index_above] { - AsmLine::Label(l) => { - debug!("Iter above: {:?}", l); - if *l == inst.dasm_operand { - above = true; - break; - } - } - AsmLine::Inline(_, s) => { - bytes_above += s; - } - AsmLine::Instruction(k) => { - debug!("Iter above: {:?}", k); - bytes_above += k.nb_bytes; - } - _ => (), - } - } - match self.code.get(index_below) { - Some(AsmLine::Label(l)) => { - debug!("Iter below: {:?}", l); - if *l == inst.dasm_operand { - above = false; - break; - } - } - Some(AsmLine::Inline(_, s)) => { - bytes_below += s; - } - Some(AsmLine::Instruction(k)) => { - debug!("Iter below: {:?}", k); - bytes_below += k.nb_bytes; - } - None => notfound |= 2, - _ => (), - } - if index_above == 0 { - reached_above = true; - notfound |= 1; - } else { - index_above -= 1; - } - index_below += 1; - if notfound == 3 { - error!("Label {} not found", inst.dasm_operand); - unreachable!() - }; - } - // Ok, now we have the distance in bytes - let distance = if above { bytes_above } else { bytes_below }; + let distance = self.distance(inst, position); //error!("distance = {:?}", distance); //if above {unreachable!();} - if distance > 127 { + if !(-127..=128).contains(&distance) { // OK. We have a problem here // This branch should be changed for a jump repair = true; diff --git a/src/cc6502.pest b/src/cc6502.pest index f8c1892..d9f1410 100644 --- a/src/cc6502.pest +++ b/src/cc6502.pest @@ -27,16 +27,19 @@ decl = { enclosed_decl | func_vec_decl | func_decl | included_assembler + | bank_org_decl } enclosed_decl = { bank ~ "{" ~ decl+ ~ "}" } var_decl = { var_type ~ global_id ~ ("," ~ global_id)* ~ ";"+ } -var_type = ${ ((var_const | superchip | ramchip | ramplus | bank | aligned | display | frequency | reversed | scattered | holeydma | noholeydma | screencode | nopagecross) ~ WHITESPACE+ )* ~ (var_sign ~ WHITESPACE+)? ~ var_simple_type ~ WHITESPACE+ } +var_type = ${ ((var_const | superchip | zp | ramchip | ramplus | bank | aligned | display | frequency | reversed | scattered | holeydma | noholeydma | screencode | nopagecross) ~ WHITESPACE+ )* ~ (var_sign ~ WHITESPACE+)? ~ var_simple_type ~ WHITESPACE+ } local_var_decl = { local_var_decl_const | local_var_decl_mut } local_var_decl_const = { "const" ~ var_type ~ global_id ~ ("," ~ global_id)* ~ ";" } local_var_decl_mut = { local_var_type ~ local_id ~ ("," ~ local_id)* ~ ";" } local_var_type = ${ (var_sign ~ WHITESPACE+)? ~ var_simple_type ~ WHITESPACE+ } +bank_org_decl = { bank ~ "org" ~ int ~ ";" } var_const = { "const" } superchip = { "superchip" } +zp = { "zp" } ramchip = { "ramchip" } ramplus = { "ramplus" } display = { "display" } diff --git a/src/compile.rs b/src/compile.rs index dfcc3c2..ec58abc 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -49,6 +49,14 @@ pub enum VariableType { ShortPtr, } +#[cfg(feature = "atarilynx")] +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum VariableMemory { + Zeropage, + Bank(u32), +} + +#[cfg(not(feature = "atarilynx"))] #[derive(Debug, Copy, Clone, PartialEq)] pub enum VariableMemory { ROM(u32), @@ -184,7 +192,7 @@ pub(crate) enum Statement<'a> { #[derive(Debug, Clone)] pub struct StatementLoc<'a> { - pub(crate) pos: usize, + pub pos: usize, pub(crate) label: Option, pub(crate) statement: Statement<'a>, } @@ -220,6 +228,8 @@ pub struct CompilerState<'a> { variable_counter: u32, default_bank: Option, function_bank: Option, + #[cfg(feature = "atarilynx")] + pub bank_orgs: HashMap, } impl<'a> CompilerState<'a> { @@ -390,7 +400,10 @@ impl<'a> CompilerState<'a> { Variable { order: self.variables.len(), signed: false, + #[cfg(not(feature = "atarilynx"))] memory: VariableMemory::ROM(0), + #[cfg(feature = "atarilynx")] + memory: VariableMemory::Bank(0), var_const: true, alignment: 1, def: VariableDefinition::Array(v), @@ -555,7 +568,10 @@ impl<'a> CompilerState<'a> { Variable { order: self.variables.len(), signed: false, + #[cfg(not(feature = "atarilynx"))] memory: VariableMemory::ROM(0), + #[cfg(feature = "atarilynx")] + memory: VariableMemory::Bank(0), var_const: true, alignment: 1, def: VariableDefinition::Array(v), @@ -1116,7 +1132,10 @@ impl<'a> CompilerState<'a> { let mut var_const_ex = !global; let mut signedness_specified = false; let mut signed = self.signed_chars; + #[cfg(not(feature = "atarilynx"))] let mut memory = VariableMemory::Zeropage; + #[cfg(feature = "atarilynx")] + let mut memory = VariableMemory::Bank(0); let mut alignment = 1; let mut reversed = false; let mut scattered = None; @@ -1131,6 +1150,7 @@ impl<'a> CompilerState<'a> { for p in pair.into_inner() { //debug!("{:?}", p); let start = p.as_span().start(); + #[cfg(not(feature = "atarilynx"))] match p.as_rule() { Rule::var_const => { var_const_ex = true; @@ -1220,6 +1240,51 @@ impl<'a> CompilerState<'a> { } _ => unreachable!(), } + #[cfg(feature = "atarilynx")] + match p.as_rule() { + Rule::zp => { + memory = VariableMemory::Zeropage; + } + Rule::bank => { + memory = VariableMemory::Bank( + p.into_inner() + .next() + .unwrap() + .as_str() + .parse::() + .unwrap(), + ) + } + Rule::var_const => { + var_const_ex = true; + set_const_ex = true; + } + Rule::var_sign => { + signed = p.as_str().eq("signed"); + signedness_specified = true; + } + Rule::var_simple_type => { + if p.as_str().starts_with("short") || p.as_str().starts_with("int") + { + var_type_ex = VariableType::Short; + if !signedness_specified { + signed = true; + } + } + } + Rule::aligned => { + let px = p.into_inner().next().unwrap(); + let a = self.parse_calc(px.into_inner())?; + if a > 0 { + alignment = a as usize + } else { + return Err( + self.syntax_error("Alignement must be positive", start) + ); + } + } + _ => (), + } } } Rule::global_id => { @@ -1272,13 +1337,22 @@ impl<'a> CompilerState<'a> { } if var_type == VariableType::Char { var_type = VariableType::CharPtr; - var_const = true; + #[cfg(not(feature = "atarilynx"))] + { + var_const = true; + } } else if var_type == VariableType::CharPtr { var_type = VariableType::CharPtrPtr; - var_const = true; + #[cfg(not(feature = "atarilynx"))] + { + var_const = true; + } } else if var_type == VariableType::Short { var_type = VariableType::ShortPtr; - var_const = true; + #[cfg(not(feature = "atarilynx"))] + { + var_const = true; + } } else { return Err( self.syntax_error("Kind of array not available", start) @@ -1290,16 +1364,22 @@ impl<'a> CompilerState<'a> { start = px.as_span().start(); match px.as_rule() { Rule::calc_expr => { - if !set_const { - return Err(self.syntax_error("Non constant global variable can't be statically initialized", start)); - } - let vx = self.parse_calc(px.into_inner())?; - def = VariableDefinition::Value(VariableValue::Int(vx)); - if var_type == VariableType::CharPtr && vx > 0xff { - memory = VariableMemory::Ramchip; + { + #[cfg(not(feature = "atarilynx"))] + if !set_const { + return Err(self.syntax_error("Non constant global variable can't be statically initialized", start)); + } + let vx = self.parse_calc(px.into_inner())?; + def = VariableDefinition::Value(VariableValue::Int(vx)); + + #[cfg(not(feature = "atarilynx"))] + if var_type == VariableType::CharPtr && vx > 0xff { + memory = VariableMemory::Ramchip; + } } } Rule::var_ptr => { + #[cfg(not(feature = "atarilynx"))] if !set_const { return Err(self.syntax_error("Non constant global variable can't be statically initialized", start)); } @@ -1338,7 +1418,11 @@ impl<'a> CompilerState<'a> { } } Rule::ptr_offset => { - let sign = if x.as_str().starts_with("-") { -1 } else { 1 }; + let sign = if x.as_str().starts_with("-") { + -1 + } else { + 1 + }; let offset = parse_int( x.into_inner() .next() @@ -1385,23 +1469,27 @@ impl<'a> CompilerState<'a> { }); } Rule::array_def => { - if !set_const { - return Err(self.syntax_error("Non constant global variable can't be statically initialized", start)); - } - memory = match memory { - VariableMemory::ROM(_) - | VariableMemory::Display - | VariableMemory::Frequency => memory, - _ => { - if let Some(bank) = self.function_bank { - VariableMemory::ROM(bank) - } else if let Some(bank) = self.default_bank { - VariableMemory::ROM(bank) - } else { - VariableMemory::ROM(0) - } + #[cfg(not(feature = "atarilynx"))] + { + if !set_const { + return Err(self.syntax_error("Non constant global variable can't be statically initialized", start)); } - }; + memory = match memory { + VariableMemory::ROM(_) + | VariableMemory::Display + | VariableMemory::Frequency => memory, + _ => { + if let Some(bank) = self.function_bank { + VariableMemory::ROM(bank) + } else if let Some(bank) = self.default_bank { + VariableMemory::ROM(bank) + } else { + VariableMemory::ROM(0) + } + } + }; + } + if var_type != VariableType::CharPtr && var_type != VariableType::CharPtrPtr && var_type != VariableType::ShortPtr @@ -1501,7 +1589,7 @@ impl<'a> CompilerState<'a> { match pxx.as_rule() { Rule::calc_expr => v.push(( "__address__".into(), - self.parse_calc(pxx.into_inner())? + self.parse_calc(pxx.into_inner())?, )), Rule::var_ptr => { let mut pxxx = pxx.into_inner(); @@ -1591,15 +1679,19 @@ impl<'a> CompilerState<'a> { } } Rule::quoted_string => { - if !set_const { - return Err(self.syntax_error("Non constant global variable can't be statically initialized", start)); + #[cfg(not(feature = "atarilynx"))] + { + if !set_const { + return Err(self.syntax_error("Non constant global variable can't be statically initialized", start)); + } + memory = match memory { + VariableMemory::ROM(_) + | VariableMemory::Display + | VariableMemory::Frequency => memory, + _ => VariableMemory::ROM(0), + }; } - memory = match memory { - VariableMemory::ROM(_) - | VariableMemory::Display - | VariableMemory::Frequency => memory, - _ => VariableMemory::ROM(0), - }; + if var_type != VariableType::CharPtr { return Err(self.syntax_error( "String provided for something not a char*", @@ -1643,6 +1735,7 @@ impl<'a> CompilerState<'a> { // If there is no definition, then it's not ROM, it's a variable in RAM on the cart if def == VariableDefinition::None { + #[cfg(not(feature = "atarilynx"))] if let VariableMemory::ROM(bank) = memory { memory = VariableMemory::MemoryOnChip(bank); } @@ -1717,7 +1810,10 @@ impl<'a> CompilerState<'a> { let var_const_ex = false; let mut signedness_specified = false; let mut signed = self.signed_chars; - let memory = VariableMemory::Zeropage; + #[cfg(not(feature = "atarilynx"))] + let mut memory = VariableMemory::Zeropage; + #[cfg(feature = "atarilynx")] + let memory = VariableMemory::Bank(0); let alignment = 1; let reversed = false; let scattered = None; @@ -1992,7 +2088,10 @@ impl<'a> CompilerState<'a> { Variable { order: self.variables.len(), signed: false, + #[cfg(not(feature = "atarilynx"))] memory: VariableMemory::Dummy, + #[cfg(feature = "atarilynx")] + memory: VariableMemory::Bank(0), var_const: true, alignment: 1, def: VariableDefinition::None, @@ -2049,7 +2148,10 @@ impl<'a> CompilerState<'a> { let mut var_const = false; let mut signedness_specified = false; let mut signed = self.signed_chars; - let memory = VariableMemory::Zeropage; + #[cfg(not(feature = "atarilynx"))] + let mut memory = VariableMemory::Zeropage; + #[cfg(feature = "atarilynx")] + let memory = VariableMemory::Bank(0); let alignment = 1; let reversed = false; let scattered = None; @@ -2216,6 +2318,29 @@ impl<'a> CompilerState<'a> { self.included_assembler .push((str.into(), filename, codesize, bank)); } + #[cfg(feature = "atarilynx")] + Rule::bank_org_decl => { + let mut bank_number = 0; + let mut bank_org = 0; + for p in pair.into_inner() { + match p.as_rule() { + Rule::bank => { + bank_number = p + .into_inner() + .next() + .unwrap() + .as_str() + .parse::() + .unwrap() + } + Rule::int => { + bank_org = parse_int(p.into_inner().next().unwrap()) as u16 + } + _ => (), + } + } + self.bank_orgs.insert(bank_number, bank_org); + } _ => { debug!("What's this ? {:?}", pair); unreachable!() @@ -2381,6 +2506,8 @@ pub fn compile( context.define("__ATARI2600__", "1"); #[cfg(feature = "atari7800")] context.define("__ATARI7800__", "1"); + #[cfg(feature = "atarilynx")] + context.define("__ATARILYNX__", "1"); for i in &args.defines { let mut s = i.splitn(2, '='); let def = s.next().unwrap(); @@ -2414,6 +2541,8 @@ pub fn compile( variable_counter: 0, default_bank: None, function_bank: None, + #[cfg(feature = "atarilynx")] + bank_orgs: HashMap::new(), }; let r = Cc2600Parser::parse(Rule::program, preprocessed_utf8); diff --git a/src/generate/generate_asm.rs b/src/generate/generate_asm.rs index 1804739..83ec133 100644 --- a/src/generate/generate_asm.rs +++ b/src/generate/generate_asm.rs @@ -103,10 +103,14 @@ impl<'a> GeneratorState<'a> { ExprType::Label(l) => { nb_bytes = match mnemonic { JMP | JSR => 3, + #[cfg(feature = "65C02")] + BRA => 2, _ => 2, }; cycles = match mnemonic { JMP => 3, + #[cfg(feature = "65C02")] + BRA => 3, JSR => 6, _ => { cycles_alt = Some(3); @@ -148,6 +152,8 @@ impl<'a> GeneratorState<'a> { ExprType::Absolute(variable, eight_bits, off) => { let v = self.compiler_state.get_variable(variable); signed = v.signed; + + #[cfg(not(feature = "atarilynx"))] let offset = if v.memory == VariableMemory::Superchip { match mnemonic { STA | STX | STY => *off, @@ -170,6 +176,10 @@ impl<'a> GeneratorState<'a> { } else { *off }; + + #[cfg(feature = "atarilynx")] + let offset = *off; + match v.var_type { VariableType::Char => { if !*eight_bits { @@ -281,6 +291,8 @@ impl<'a> GeneratorState<'a> { let mut indirect = false; let v = self.compiler_state.get_variable(variable); signed = v.signed; + + #[cfg(not(feature = "atarilynx"))] let offset = if v.memory == VariableMemory::Superchip { match mnemonic { STA | STX | STY => 0, @@ -303,6 +315,10 @@ impl<'a> GeneratorState<'a> { } else { 0 }; + + #[cfg(feature = "atarilynx")] + let offset = 0; + if v.var_type == VariableType::CharPtrPtr || v.var_type == VariableType::ShortPtr { let off = offset + if high_byte { v.size } else { 0 }; if off > 0 { @@ -424,6 +440,8 @@ impl<'a> GeneratorState<'a> { ExprType::AbsoluteX(variable) => { let v = self.compiler_state.get_variable(variable); signed = v.signed; + + #[cfg(not(feature = "atarilynx"))] let offset = if v.memory == VariableMemory::Superchip { match mnemonic { STA | STX | STY => 0, @@ -446,6 +464,10 @@ impl<'a> GeneratorState<'a> { } else { 0 }; + + #[cfg(feature = "atarilynx")] + let offset = 0; + if v.var_type == VariableType::CharPtr && !v.var_const && v.size == 1 { return Err(self.compiler_state.syntax_error( "Y-Indirect adressing mode not available with X register", diff --git a/src/generate/generate_assign.rs b/src/generate/generate_assign.rs index 649430e..e19adb4 100644 --- a/src/generate/generate_assign.rs +++ b/src/generate/generate_assign.rs @@ -376,6 +376,21 @@ impl<'a> GeneratorState<'a> { _ => { let mut acc_in_use = self.acc_in_use; let signed; + + #[cfg(feature = "65C02")] + if right == &ExprType::Immediate(0) { + match left { + ExprType::Absolute(_, _, _) + | ExprType::AbsoluteX(_) => { + self.asm(STZ, left, pos, high_byte)?; + self.flags = FlagsState::Unknown; + self.carry_flag_ok = false; + return Ok(ExprType::Nothing); + } + _ => (), + }; + } + match right { ExprType::Absolute(_, _, _) | ExprType::AbsoluteX(_) diff --git a/src/generate/generate_statements.rs b/src/generate/generate_statements.rs index e24ee74..c509e1c 100644 --- a/src/generate/generate_statements.rs +++ b/src/generate/generate_statements.rs @@ -207,6 +207,7 @@ impl<'a> GeneratorState<'a> { } else if f.bank == self.current_bank || self.bankswitching_scheme == "3EP" || (self.bankswitching_scheme.starts_with("SuperGame") + || cfg!(feature = "atarilynx") && (f.bank == 0 || f.bank == fixed_bank)) { self.asm(JSR, &ExprType::Label(var.clone()), pos, false)?; @@ -229,7 +230,8 @@ impl<'a> GeneratorState<'a> { } else { return Err(self.compiler_state.syntax_error("Banked code can only be called from bank 0 or same bank", pos)); } - } else if self.current_bank == 0 || self.current_bank == fixed_bank + } + else if self.current_bank == 0 || self.current_bank == fixed_bank || cfg!(feature = "atarilynx") { // Generate bankswitching call if self.bankswitching_scheme.starts_with("SuperGame") { @@ -247,12 +249,20 @@ impl<'a> GeneratorState<'a> { )?; self.asm(JSR, &ExprType::Label(var.clone()), pos, false)?; } else { + #[cfg(not(feature = "atarilynx"))] self.asm( JSR, &ExprType::Label(format!("Call{}", *var)), pos, false, )?; + #[cfg(feature = "atarilynx")] + self.asm( + JSR, + &ExprType::Label(format!("{}", *var)), + pos, + false, + )?; } } else { return Err(self.compiler_state.syntax_error( diff --git a/src/tests/build.rs b/src/tests/build.rs index 9ffdc91..9625a3a 100644 --- a/src/tests/build.rs +++ b/src/tests/build.rs @@ -68,6 +68,7 @@ pub fn simple_build(compiler_state: &CompilerState, writer: &mut dyn Write, args // Try to figure out what is the bankswitching method // Let's identitfy superchip + #[cfg(not(feature = "atarilynx"))] for v in compiler_state.sorted_variables().iter() { if !v.1.var_const && v.1.memory == VariableMemory::Superchip && v.1.def == VariableDefinition::None { superchip = true; @@ -289,6 +290,7 @@ pub fn simple_build(compiler_state: &CompilerState, writer: &mut dyn Write, args level += 1; } + #[cfg(not(feature = "atarilynx"))] if superchip { gstate.write("\n\tSEG.U SUPERVARS\n\tORG $1000\n\tRORG $1000\n")?; // Superchip variables @@ -317,6 +319,7 @@ pub fn simple_build(compiler_state: &CompilerState, writer: &mut dyn Write, args } // Generate RAM for 3E bankswitching scheme + #[cfg(not(feature = "atarilynx"))] if bankswitching_scheme == "3E" { for bank in 1..=512 { // Max 512ko let mut first = true; @@ -350,6 +353,7 @@ pub fn simple_build(compiler_state: &CompilerState, writer: &mut dyn Write, args } // Generate RAM for 3E+ bankswitching scheme + #[cfg(not(feature = "atarilynx"))] if bankswitching_scheme == "3EP" { for bank in 0..64 { // Max 32ko let mut first = true; @@ -491,98 +495,101 @@ Powerup } // Generate ROM tables - gstate.write("\n; Tables in ROM\n")?; - for v in compiler_state.sorted_variables().iter() { - if let VariableMemory::ROM(rom_bank) = v.1.memory { - if rom_bank == bank { - match &v.1.def { - VariableDefinition::Array(arr) => { - if v.1.alignment != 1 { - gstate.write(&format!("\n\talign {}\n", v.1.alignment))?; - } - gstate.write(v.0)?; - let mut counter = 0; - for vx in arr { - match vx { - VariableValue::Int(i) => { + #[cfg(not(feature = "atarilynx"))] + { + gstate.write("\n; Tables in ROM\n")?; + for v in compiler_state.sorted_variables().iter() { + if let VariableMemory::ROM(rom_bank) = v.1.memory { + if rom_bank == bank { + match &v.1.def { + VariableDefinition::Array(arr) => { + if v.1.alignment != 1 { + gstate.write(&format!("\n\talign {}\n", v.1.alignment))?; + } + gstate.write(v.0)?; + let mut counter = 0; + for vx in arr { + match vx { + VariableValue::Int(i) => { + if counter == 0 { + gstate.write("\n\thex ")?; + } + counter += 1; + if counter == 16 { counter = 0; } + gstate.write(&format!("{:02x}", i & 0xff)) + }, + VariableValue::LowPtr((s, offset)) => { + counter = 0; + if *offset != 0 { + gstate.write(&format!("\n\t.byte <({} + {})", s, offset)) + } else { + gstate.write(&format!("\n\t.byte <{}", s)) + } + }, + VariableValue::HiPtr((s, offset)) => { + counter = 0; + if *offset != 0 { + gstate.write(&format!("\n\t.byte >({} + {})", s, offset)) + } else { + gstate.write(&format!("\n\t.byte >{}", s)) + } + }, + }?; + } + if v.1.var_type == VariableType::ShortPtr { + for vx in arr { if counter == 0 { gstate.write("\n\thex ")?; } counter += 1; if counter == 16 { counter = 0; } - gstate.write(&format!("{:02x}", i & 0xff)) - }, - VariableValue::LowPtr((s, offset)) => { - counter = 0; - if *offset != 0 { - gstate.write(&format!("\n\t.byte <({} + {})", s, offset)) - } else { - gstate.write(&format!("\n\t.byte <{}", s)) - } - }, - VariableValue::HiPtr((s, offset)) => { - counter = 0; - if *offset != 0 { - gstate.write(&format!("\n\t.byte >({} + {})", s, offset)) - } else { - gstate.write(&format!("\n\t.byte >{}", s)) + if let VariableValue::Int(i) = vx { + gstate.write(&format!("{:02x}", (i >> 8) & 0xff))?; } - }, - }?; - } - if v.1.var_type == VariableType::ShortPtr { - for vx in arr { - if counter == 0 { - gstate.write("\n\thex ")?; + } + } + gstate.write("\n")?; + }, + VariableDefinition::ArrayOfPointers(arr) => { + if v.1.alignment != 1 { + gstate.write(&format!("\n\talign {}\n", v.1.alignment))?; + } + gstate.write(v.0)?; + + let mut counter = 0; + for i in arr { + if counter % 8 == 0 { + gstate.write("\n\t.byte ")?; } counter += 1; - if counter == 16 { counter = 0; } - if let VariableValue::Int(i) = vx { - gstate.write(&format!("{:02x}", (i >> 8) & 0xff))?; + if i.1 != 0 { + gstate.write(&format!("<({} + {})", i.0, i.1))?; + } else { + gstate.write(&format!("<{}", i.0))?; } + if counter % 8 != 0 { + gstate.write(", ")?; + } } - } - gstate.write("\n")?; - }, - VariableDefinition::ArrayOfPointers(arr) => { - if v.1.alignment != 1 { - gstate.write(&format!("\n\talign {}\n", v.1.alignment))?; - } - gstate.write(v.0)?; - - let mut counter = 0; - for i in arr { - if counter % 8 == 0 { - gstate.write("\n\t.byte ")?; - } - counter += 1; - if i.1 != 0 { - gstate.write(&format!("<({} + {})", i.0, i.1))?; - } else { - gstate.write(&format!("<{}", i.0))?; - } - if counter % 8 != 0 { - gstate.write(", ")?; - } - } - for i in arr { - if counter % 8 == 0 { - gstate.write("\n\t.byte ")?; - } - counter += 1; - if i.1 != 0 { - gstate.write(&format!(">({} + {})", i.0, i.1))?; - } else { - gstate.write(&format!(">{}", i.0))?; - } - if counter % 8 != 0 && counter < 2 * arr.len() { - gstate.write(", ")?; + for i in arr { + if counter % 8 == 0 { + gstate.write("\n\t.byte ")?; + } + counter += 1; + if i.1 != 0 { + gstate.write(&format!(">({} + {})", i.0, i.1))?; + } else { + gstate.write(&format!(">{}", i.0))?; + } + if counter % 8 != 0 && counter < 2 * arr.len() { + gstate.write(", ")?; + } } - } - gstate.write("\n")?; - }, - _ => () - }; + gstate.write("\n")?; + }, + _ => () + }; + } } } } @@ -660,6 +667,7 @@ Call{} let starting_code = if maxbank > 0 && bank != 0 { "Start" } else { "Powerup" }; + #[cfg(not(feature = "atarilynx"))] if b == maxbank && compiler_state.variables.get("PLUSROM_API").is_some() { let v = compiler_state.get_variable("PLUSROM_API"); let offset = match v.memory { @@ -713,6 +721,7 @@ Call{} } } + #[cfg(not(feature = "atarilynx"))] if bankswitching_scheme == "DPC" { gstate.write(" SEG DISPLAY @@ -752,6 +761,7 @@ Call{} ")?; } + #[cfg(not(feature = "atarilynx"))] if bankswitching_scheme == "DPC+" { gstate.write(" SEG DISPLAY