mirror of
https://github.com/KarolS/millfork.git
synced 2025-01-01 06:29:53 +00:00
Report lines with invalid short branches
This commit is contained in:
parent
2eb8ef53ca
commit
17e660a2f6
@ -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
|
||||
|
@ -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)) {
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user