diff --git a/src/main/scala/millfork/output/AbstractAssembler.scala b/src/main/scala/millfork/output/AbstractAssembler.scala index ba9dae16..073e44fe 100644 --- a/src/main/scala/millfork/output/AbstractAssembler.scala +++ b/src/main/scala/millfork/output/AbstractAssembler.scala @@ -4,7 +4,7 @@ import millfork.assembly._ import millfork.compiler.{AbstractCompiler, CompilationContext} import millfork.env._ import millfork.error.Logger -import millfork.node.{CallGraph, Expression, FunctionCallExpression, LiteralExpression, NiceFunctionProperty, Program, SumExpression} +import millfork.node.{CallGraph, Expression, FunctionCallExpression, LiteralExpression, NiceFunctionProperty, Position, Program, SumExpression} import millfork._ import millfork.assembly.z80.ZLine @@ -36,8 +36,8 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program val mem = new CompiledMemory(platform.bankNumbers.toList, platform.bankFill, platform.isBigEndian) val labelMap: mutable.Map[String, (Int, Int)] = mutable.Map() val breakpointSet: mutable.Set[(Int, Int)] = mutable.Set() - private val bytesToWriteLater = mutable.ListBuffer[(String, Int, Constant)]() - private val wordsToWriteLater = mutable.ListBuffer[(String, Int, Constant)]() + private val bytesToWriteLater = mutable.ListBuffer[(String, Int, Constant, Option[Position])]() + private val wordsToWriteLater = mutable.ListBuffer[(String, Int, Constant, Option[Position])]() def writeByte(bank: String, addr: Int, value: Byte): Unit = { mem.banks(bank).occupied(addr) = true @@ -54,7 +54,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program mem.banks(bank).output(addr) = value.toByte } - def writeByte(bank: String, addr: Int, value: Constant): Unit = { + def writeByte(bank: String, addr: Int, value: Constant)(implicit position: Option[Position]): Unit = { mem.banks(bank).occupied(addr) = true mem.banks(bank).initialized(addr) = true mem.banks(bank).readable(addr) = true @@ -63,11 +63,11 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program if (x > 0xff) log.error("Byte overflow: " + x.toHexString) mem.banks(bank).output(addr) = x.toByte case _ => - bytesToWriteLater += ((bank, addr, value)) + bytesToWriteLater += ((bank, addr, value, position)) } } - def writeWord(bank: String, addr: Int, value: Constant): Unit = { + def writeWord(bank: String, addr: Int, value: Constant)(implicit position: Option[Position]): Unit = { mem.banks(bank).occupied(addr) = true mem.banks(bank).occupied(addr + 1) = true mem.banks(bank).initialized(addr) = true @@ -81,7 +81,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program mem.banks(bank).output(addr) = (x >> 8).toByte mem.banks(bank).output(addr + 1) = x.toByte case _ => - wordsToWriteLater += ((bank, addr, value)) + wordsToWriteLater += ((bank, addr, value, position)) } } else { value match { @@ -90,14 +90,14 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program mem.banks(bank).output(addr) = x.toByte mem.banks(bank).output(addr + 1) = (x >> 8).toByte case _ => - wordsToWriteLater += ((bank, addr, value)) + wordsToWriteLater += ((bank, addr, value, position)) } } } var stackProbeCount = 0 - def deepConstResolve(c: Constant): Long = { + def deepConstResolve(c: Constant)(implicit position: Option[Position]): Long = { def stackProbe(n: Int): Int = { stackProbeCount += 1 if (n == 0) 0 else stackProbe(n - 1) + 1 @@ -107,7 +107,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program case AssertByte(inner) => val value = deepConstResolve(inner) if (value.toByte == value) value else { - log.error("Invalid relative jump: " + c + " calculated offset: " + value) + log.error("Invalid relative jump: " + c + " calculated offset: " + value, position) -2 // spin } case MemoryAddressConstant(th) => @@ -348,7 +348,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program env.eval(item) match { case Some(c) => for(i <- 0 until elementType.size) { - writeByte(bank, index, subbyte(c, i, elementType.size)) + writeByte(bank, index, subbyte(c, i, elementType.size))(None) bank0.occupied(index) = true bank0.initialized(index) = true bank0.writeable(index) = true @@ -466,7 +466,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program throw new IllegalStateException("LUnix cannot run on big-endian architectures") } for (i <- 0 until typ.size) { - writeByte(bank, index, subbyte(c, i, typ.size)) + writeByte(bank, index, subbyte(c, i, typ.size))(None) assembly.append(" " + bytePseudoopcode + " " + subbyte(c, i, typ.size).quickSimplify) index += 1 } @@ -515,7 +515,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program env.eval(item) match { case Some(c) => for (i <- 0 until elementType.size) { - writeByte(bank, index, subbyte(c, i, elementType.size)) + writeByte(bank, index, subbyte(c, i, elementType.size))(None) index += 1 } case None => @@ -545,7 +545,7 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program env.eval(value) match { case Some(c) => for (i <- 0 until typ.size) { - writeByte(bank, index, subbyte(c, i, typ.size)) + writeByte(bank, index, subbyte(c, i, typ.size))(None) assembly.append(" " + bytePseudoopcode + " " + subbyte(c, i, typ.size).quickSimplify) index += 1 } @@ -579,16 +579,16 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program } val debugArray = Array.fill[Option[Constant]](size)(None) bytesToWriteLater ++= bytesToWriteLater.flatMap{ - case ("default", addr, value) if addr >= rwDataStart && addr < rwDataEnd => + case ("default", addr, value, position) if addr >= rwDataStart && addr < rwDataEnd => debugArray(addr - rwDataStart) = Some(value) - Some(ivBank, addr + ivAddr - rwDataStart, value) + Some(ivBank, addr + ivAddr - rwDataStart, value, position) case _ => None } wordsToWriteLater ++= wordsToWriteLater.flatMap { - case ("default", addr, value) if addr >= rwDataStart && addr < rwDataEnd => + case ("default", addr, value, position) if addr >= rwDataStart && addr < rwDataEnd => debugArray(addr - rwDataStart) = Some(value.loByte) debugArray(addr - rwDataStart + 1) = Some(value.hiByte) - Some(ivBank, addr + ivAddr - rwDataStart, value) + Some(ivBank, addr + ivAddr - rwDataStart, value, position) case _ => None } assembly.append("* = $" + ivAddr.toHexString) @@ -634,12 +634,12 @@ abstract class AbstractAssembler[T <: AbstractCode](private val program: Program env = rootEnv.allThings - for ((bank, addr, b) <- bytesToWriteLater) { - val value = deepConstResolve(b) + for ((bank, addr, b, position) <- bytesToWriteLater) { + val value = deepConstResolve(b)(position) mem.banks(bank).output(addr) = value.toByte } - for ((bank, addr, b) <- wordsToWriteLater) { - val value = deepConstResolve(b) + for ((bank, addr, b, position) <- wordsToWriteLater) { + val value = deepConstResolve(b)(position) if (platform.isBigEndian) { mem.banks(bank).output(addr) = value.>>>(8).toByte mem.banks(bank).output(addr + 1) = value.toByte diff --git a/src/main/scala/millfork/output/M6809Assembler.scala b/src/main/scala/millfork/output/M6809Assembler.scala index ce4ad9e0..298f1ecf 100644 --- a/src/main/scala/millfork/output/M6809Assembler.scala +++ b/src/main/scala/millfork/output/M6809Assembler.scala @@ -64,7 +64,7 @@ class M6809Assembler(program: Program, } override def emitInstruction(bank: String, options: CompilationOptions, startIndex: Int, instr: MLine): Int = { - val position = instr.source.map(sl => Position(sl.moduleName, sl.line, 0, 0)) + implicit val position = instr.source.map(sl => Position(sl.moduleName, sl.line, 0, 0)) import millfork.assembly.m6809.MOpcode._ var index: Int = startIndex if (MOpcode.PrefixedBy10(instr.opcode)) { diff --git a/src/main/scala/millfork/output/MosAssembler.scala b/src/main/scala/millfork/output/MosAssembler.scala index 93f15e6a..b4bd37c2 100644 --- a/src/main/scala/millfork/output/MosAssembler.scala +++ b/src/main/scala/millfork/output/MosAssembler.scala @@ -4,7 +4,7 @@ import millfork.assembly.mos.opt.{CoarseFlowAnalyzer, CpuStatus, HudsonOptimizat import millfork.assembly._ import millfork.env._ import millfork.error.{ConsoleLogger, FatalErrorReporting} -import millfork.node.{FunctionCallExpression, MosNiceFunctionProperty, NiceFunctionProperty, Program} +import millfork.node.{FunctionCallExpression, MosNiceFunctionProperty, NiceFunctionProperty, Position, Program} import millfork._ import millfork.assembly.mos._ import millfork.assembly.opt.{SingleStatus, Status} @@ -33,6 +33,7 @@ class MosAssembler(program: Program, override def emitInstruction(bank: String, options: CompilationOptions, index: Int, instr: AssemblyLine): Int = { import millfork.assembly.mos.AddrMode._ import millfork.assembly.mos.Opcode._ + implicit val position = instr.source.map(sl => Position(sl.moduleName, sl.line, 0, 0)) instr match { case AssemblyLine0(BYTE, RawByte, c) => writeByte(bank, index, c) diff --git a/src/main/scala/millfork/output/Z80Assembler.scala b/src/main/scala/millfork/output/Z80Assembler.scala index 48561338..a179b72b 100644 --- a/src/main/scala/millfork/output/Z80Assembler.scala +++ b/src/main/scala/millfork/output/Z80Assembler.scala @@ -8,7 +8,7 @@ import millfork.assembly.z80.opt.{CoarseFlowAnalyzer, ConditionalInstructions, C import millfork.compiler.z80.Z80Compiler import millfork.env._ import millfork.node.Z80NiceFunctionProperty.{DoesntChangeBC, DoesntChangeDE, DoesntChangeHL, DoesntChangeIY, SetsATo} -import millfork.node.{NiceFunctionProperty, Program, ZRegister} +import millfork.node.{NiceFunctionProperty, Position, Program, ZRegister} import scala.annotation.tailrec import scala.collection.mutable @@ -77,6 +77,7 @@ class Z80Assembler(program: Program, options.flag(EmitSharpOpcodes) } + implicit val position = instr.source.map(sl => Position(sl.moduleName, sl.line, 0, 0)) try { instr match { case ZLine0(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName))) => val bank0 = mem.banks(bank) diff --git a/src/main/scala/millfork/output/Z80ToX86Crossassembler.scala b/src/main/scala/millfork/output/Z80ToX86Crossassembler.scala index ab8ea386..b1ed089f 100644 --- a/src/main/scala/millfork/output/Z80ToX86Crossassembler.scala +++ b/src/main/scala/millfork/output/Z80ToX86Crossassembler.scala @@ -5,7 +5,7 @@ import millfork.assembly.z80.{ZOpcode, _} import millfork.assembly.z80.opt.{ConditionalInstructions, JumpFollowing, JumpShortening} import millfork.compiler.z80.Z80Compiler import millfork.env._ -import millfork.node.{NiceFunctionProperty, Program, ZRegister} +import millfork.node.{NiceFunctionProperty, Position, Program, ZRegister} import scala.collection.mutable @@ -72,6 +72,7 @@ class Z80ToX86Crossassembler(program: Program, import ZRegister._ import CompilationFlag._ import Z80ToX86Crossassembler._ + implicit val position = instr.source.map(sl => Position(sl.moduleName, sl.line, 0, 0)) instr match { case ZLine0(LABEL, NoRegisters, MemoryAddressConstant(Label(labelName))) => val bank0 = mem.banks(bank) diff --git a/src/test/scala/millfork/test/AssemblySuite.scala b/src/test/scala/millfork/test/AssemblySuite.scala index 426059d7..9dc838b7 100644 --- a/src/test/scala/millfork/test/AssemblySuite.scala +++ b/src/test/scala/millfork/test/AssemblySuite.scala @@ -1,6 +1,6 @@ package millfork.test import millfork.Cpu -import millfork.test.emu.{EmuBenchmarkRun, EmuCrossPlatformBenchmarkRun, EmuOptimizedCmosRun, EmuOptimizedHudsonRun, EmuOptimizedRun, EmuUndocumentedRun, EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedHudsonRun} +import millfork.test.emu.{EmuBenchmarkRun, EmuCrossPlatformBenchmarkRun, EmuOptimizedCmosRun, EmuOptimizedHudsonRun, EmuOptimizedRun, EmuUndocumentedRun, EmuUnoptimizedCrossPlatformRun, EmuUnoptimizedHudsonRun, ShouldNotCompile} import org.scalatest.{AppendedClues, FunSuite, Matchers} /** @@ -350,4 +350,16 @@ class AssemblySuite extends FunSuite with Matchers with AppendedClues { |""".stripMargin) } + test("Short branch too large") { + ShouldNotCompile( + """ + |asm void main() { + |bne __main_exit + |[for i,0,until,200 [$EA]] + |__main_exit: + |rts + |} + |""".stripMargin, Set(Cpu.Mos)) + } + } diff --git a/src/test/scala/millfork/test/emu/ShouldNotCompile.scala b/src/test/scala/millfork/test/emu/ShouldNotCompile.scala index 03e585a6..99731a27 100644 --- a/src/test/scala/millfork/test/emu/ShouldNotCompile.scala +++ b/src/test/scala/millfork/test/emu/ShouldNotCompile.scala @@ -20,10 +20,10 @@ import scala.collection.JavaConverters._ object ShouldNotCompile extends Matchers { - def apply(source: String): Unit = { - checkCase(Cpu.Mos, source) - checkCase(Cpu.Z80, source) - checkCase(Cpu.Motorola6809, source) + def apply(source: String, cpus: Iterable[Cpu.Value] = Set(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)): Unit = { + for (cpu <- cpus) { + checkCase(cpu, source) + } } private def checkCase(cpu: Cpu.Value, source: String) { @@ -97,17 +97,17 @@ object ShouldNotCompile extends Matchers { val assembler = new MosAssembler(program, env2, platform) val output = assembler.assemble(callGraph, Nil, options, (_, _) => Nil) output.asm.takeWhile(s => !(s.startsWith(".") && s.contains("= $"))).filterNot(_.contains("; DISCARD_")).foreach(println) - fail("Failed: Compilation succeeded for 6502") + if (!log.hasErrors) fail("Failed: Compilation succeeded for 6502") case CpuFamily.I80 => val assembler = new Z80Assembler(program, env2, platform) val output = assembler.assemble(callGraph, Nil, options, (_, _) => Nil) output.asm.takeWhile(s => !(s.startsWith(".") && s.contains("= $"))).filterNot(_.contains("; DISCARD_")).foreach(println) - fail("Failed: Compilation succeeded for Z80") + if (!log.hasErrors) fail("Failed: Compilation succeeded for Z80") case CpuFamily.M6809 => val assembler = new M6809Assembler(program, env2, platform) val output = assembler.assemble(callGraph, Nil, options, (_, _) => Nil) output.asm.takeWhile(s => !(s.startsWith(".") && s.contains("= $"))).filterNot(_.contains("; DISCARD_")).foreach(println) - fail("Failed: Compilation succeeded for 6809") + if (!log.hasErrors) fail("Failed: Compilation succeeded for 6809") case _ => fail("Failed: Compilation succeeded for unknown CPU") }