1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-10-01 07:59:30 +00:00

Report lines with invalid short branches

This commit is contained in:
Karol Stasiak 2020-03-17 21:46:43 +01:00
parent 2eb8ef53ca
commit 17e660a2f6
7 changed files with 49 additions and 34 deletions

View File

@ -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

View File

@ -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)) {

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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))
}
}

View File

@ -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")
}