1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-12-23 08:29:35 +00:00

Placeholder for future expansion

This commit is contained in:
Karol Stasiak 2019-07-08 09:26:51 +02:00
parent 32bb0d4453
commit 767f0da703
17 changed files with 597 additions and 1 deletions

View File

@ -174,6 +174,7 @@ case class CompilationOptions(platform: Platform,
log.error("Either Sharp LR35902 or Intel 8080 opcodes have to be enabled")
}
case CpuFamily.I86 =>
case CpuFamily.M6809 =>
}
}
@ -265,6 +266,7 @@ object CpuFamily extends Enumeration {
case Mos | StrictMos | Ricoh | StrictRicoh | Cmos | HuC6280 | CE02 | Sixteen => M6502
case Intel8080 | Intel8085 | StrictIntel8085 | Sharp | Z80 | StrictZ80 | EZ80 => I80
case Intel8086 | Intel80186 => I86
case Cpu.Motorola6809 => M6809
}
}
}
@ -339,6 +341,10 @@ object Cpu extends Enumeration {
* The Intel 80186 or 80188 processor
*/
val Intel80186: Cpu.Value = Value
/**
* The Motorola 6809 processor
*/
val Motorola6809: Cpu.Value = Value
/**
* Processors that can run code for WDC 65C02
@ -367,6 +373,8 @@ object Cpu extends Enumeration {
private val i80AlwaysDefaultFlags = alwaysDefaultFlags
private val m6809AlwaysDefaultFlags = alwaysDefaultFlags
def defaultFlags(x: Cpu.Value): Set[CompilationFlag.Value] = x match {
case StrictMos =>
mosAlwaysDefaultFlags ++ Set(DecimalMode, PreventJmpIndirectBug)
@ -396,6 +404,8 @@ object Cpu extends Enumeration {
i80AlwaysDefaultFlags ++ Set(EmitExtended80Opcodes, EmitSharpOpcodes)
case Intel8086 | Intel80186 =>
i80AlwaysDefaultFlags ++ Set(EmitIntel8080Opcodes, UseIxForStack, EmitIntel8085Opcodes, EmitIllegals)
case Motorola6809 =>
m6809AlwaysDefaultFlags
}
def fromString(name: String)(implicit log: Logger): Cpu.Value = name match {
@ -453,6 +463,8 @@ object Cpu extends Enumeration {
case "intel80286" => Intel80186
case "i80286" => Intel80186
case "80286" => Intel80186
// disabled for now
// case "6809" => Motorola6809
case _ => log.fatal("Unknown CPU achitecture: " + name)
}
@ -460,6 +472,7 @@ object Cpu extends Enumeration {
CpuFamily.forType(cpu) match {
case CpuFamily.M6502 => 2
case CpuFamily.I80 | CpuFamily.I86 => 4
case CpuFamily.M6809 => 2
case _ => ???
}
}

View File

@ -0,0 +1,36 @@
package millfork.assembly.m6809
import millfork.node.M6809Register
/**
* @author Karol Stasiak
*/
sealed trait MAddrMode
case object Inherent extends MAddrMode
case object InherentA extends MAddrMode
case object InherentB extends MAddrMode
case class TwoRegisters(source: M6809Register.Value, target: M6809Register.Value) extends MAddrMode
case class RegisterSet(registers: Set[M6809Register.Value]) extends MAddrMode
case class Absolute(indirect: Boolean) extends MAddrMode
case class Indexed(base: M6809Register.Value, indirect: Boolean) extends MAddrMode
case class AccumulatorIndexed(base: M6809Register.Value, indirect: Boolean) extends MAddrMode
case class PostIncremented(base: M6809Register.Value, amount: Int, indirect: Boolean) extends MAddrMode
case class PreDecremented(base: M6809Register.Value, amount: Int, indirect: Boolean) extends MAddrMode
case object Relative extends MAddrMode
case object Immediate extends MAddrMode
case object NonExistent extends MAddrMode
case object RawByte extends MAddrMode

View File

@ -0,0 +1,76 @@
package millfork.assembly.m6809
import millfork.assembly.{AbstractCode, Elidability, SourceLine}
import millfork.env.{Constant, Label}
import millfork.node.Position
/**
* @author Karol Stasiak
*/
object MLine0 {
@inline
def unapply(a: MLine): Some[(MOpcode.Value, MAddrMode, Constant)] = Some(a.opcode, a.addrMode, a.parameter)
}
object MLine {
import MOpcode._
def label(label: String): MLine = MLine.label(Label(label))
def label(label: Label): MLine = MLine(LABEL, NonExistent, label.toAddress)
def inherent(opcode: MOpcode.Value): MLine = MLine(opcode, Inherent, Constant.Zero)
def inherentA(opcode: MOpcode.Value): MLine = MLine(opcode, InherentA, Constant.Zero)
def inherentB(opcode: MOpcode.Value): MLine = MLine(opcode, InherentB, Constant.Zero)
}
case class MLine(opcode: MOpcode.Value, addrMode: MAddrMode, parameter: Constant, elidability: Elidability.Value = Elidability.Elidable, source: Option[SourceLine] = None) extends AbstractCode {
def pos(s: Option[SourceLine]): MLine = if (s.isEmpty || s == source) this else this.copy(source = s)
def pos(s1: Option[SourceLine], s2: Option[SourceLine]): MLine = pos(Seq(s1, s2))
def position(s: Option[Position]): MLine = pos(SourceLine.of(s))
def positionIfEmpty(s: Option[Position]): MLine = if (s.isEmpty || source.isDefined) this else pos(SourceLine.of(s))
def pos(s: Seq[Option[SourceLine]]): MLine = pos(SourceLine.merge(s))
def mergePos(s: Seq[Option[SourceLine]]): MLine = if (s.isEmpty) this else pos(SourceLine.merge(this.source, s))
def refersTo(name: String): Boolean = parameter.refersTo(name)
override def sizeInBytes: Int = 1 // TODO
override def isPrintable: Boolean = true // TODO
override def toString: String = {
if (opcode == MOpcode.LABEL) return parameter + ":"
if (opcode == MOpcode.BYTE) return s" FCB $parameter"
val suffix = addrMode match {
case NonExistent => ""
case Inherent => ""
case InherentA => "A"
case InherentB => "B"
case Relative => s" $parameter"
case Absolute(false) => s" $parameter"
case Indexed(base, false) => s" $parameter,$base"
case Indexed(base, true) => s" [$parameter,$base]"
case PreDecremented(base, 1, false) => s" ,-$base"
case PreDecremented(base, 2, false) => s" ,--$base"
case PreDecremented(base, 1, true) => s" [-$base]"
case PreDecremented(base, 2, true) => s" [--$base]"
case PostIncremented(base, 1, false) => s" ,$base+"
case PostIncremented(base, 2, false) => s" ,$base++"
case PostIncremented(base, 1, true) => s" [,$base+]"
case PostIncremented(base, 2, true) => s" [,$base++]"
}
s" $opcode$suffix"
}
}

View File

@ -0,0 +1,35 @@
package millfork.assembly.m6809
/**
* @author Karol Stasiak
*/
object MFlag extends Enumeration {
val Z, C, H, N, V = Value
}
object MOpcode extends Enumeration {
val ABX, ADCA, ADCB, ADDA, ADDB, ADDD, ANDA, ANDB, ANDCC, ASL, ASR,
BITA, BITB,
BRA, BRN, BHI, BLS, BCC, BCS, BNE, BEQ, BVC, BVS, BPL, BMI, BGE, BLT, BGT, BLE,
CLR, CMPA, CMPB, CMPD, CMPS, CMPU, CMPX, CMPY, COMA, COMB, COM, CWAI,
DAA, DEC,
EORA, EORB, EXG,
INC,
JMP, JSR,
LDA, LDB, LDD, LDS, LDU, LDX, LDY, LEAS, LEAU, LEAX, LEAY, LSR,
LBRA, LBRN, LBHI, LBLS, LBCC, LBCS, LBNE, LBEQ, LBVC, LBVS, LBPL, LBMI, LBGE, LBLT, LBGT, LBLE,
MUL,
NEG, NOP,
ORA, ORB, ORCC,
PSHS, PSHU, PULS, PULU,
ROL, ROR, RTI, RTS,
SBCA, SBCB, SEX, STA, STB, STD, STS, STU, STX, STY, SUBA, SUBB, SUBD, SWI, SWI2, SWI3, SYNC,
TFR, TST,
DISCARD_D, DISCARD_X, DISCARD_Y, DISCARD_CC, CHANGED_MEM, BYTE, LABEL = Value
val NoopDiscard: Set[MOpcode.Value] = Set(DISCARD_D, DISCARD_X, DISCARD_Y, DISCARD_CC)
val PrefixedBy10: Set[MOpcode.Value] = Set(CMPD, CMPY, LDS, LDY, SWI2) // TODO: branches
val PrefixedBy11: Set[MOpcode.Value] = Set(CMPS, CMPU, SWI3)
val Prefixed: Set[MOpcode.Value] = PrefixedBy10 ++ PrefixedBy11
}

View File

@ -0,0 +1,19 @@
package millfork.compiler.m6809
import millfork.assembly.Elidability
import millfork.assembly.m6809.{Inherent, MLine, MOpcode, NonExistent}
import millfork.compiler.{AbstractCompiler, CompilationContext}
import millfork.env.{Constant, Label, MemoryAddressConstant}
/**
* @author Karol Stasiak
*/
object M6809Compiler extends AbstractCompiler[MLine] {
override def compile(ctx: CompilationContext): List[MLine] = {
ctx.env.nameCheck(ctx.function.code)
val label = MLine.label(Label(ctx.function.name)).copy(elidability = Elidability.Fixed)
val chunk = packHalves(M6809StatementCompiler.compile(ctx, new M6809StatementPreprocessor(ctx, ctx.function.code)()))
// TODO
label :: chunk
}
}

View File

@ -0,0 +1,50 @@
package millfork.compiler.m6809
import millfork.assembly.BranchingOpcodeMapping
import millfork.assembly.m6809.MLine
import millfork.compiler.{AbstractCompiler, AbstractStatementCompiler, BranchSpec, CompilationContext}
import millfork.node.{ExecutableStatement, Expression, M6809AssemblyStatement, ReturnStatement, VariableExpression, WhileStatement}
import millfork.assembly.m6809.MOpcode._
import millfork.env.{Label, ThingInMemory}
/**
* @author Karol Stasiak
*/
object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
def compile(ctx: CompilationContext, statement: ExecutableStatement): (List[MLine], List[MLine]) = {
val code: (List[MLine], List[MLine]) = statement match {
case ReturnStatement(None) =>
// TODO: clean stack
// TODO: RTI
List(MLine.inherent(RTS)) -> Nil
case M6809AssemblyStatement(opcode, addrMode, expression, elidability) =>
ctx.env.evalForAsm(expression) match {
case Some(e) => List(MLine(opcode, addrMode, e, elidability)) -> Nil
case None =>
println(statement)
???
}
case WhileStatement(VariableExpression("true"),List(),List(),_) =>
Nil -> Nil // TODO
case _ =>
println(statement)
???
}
code._1.map(_.positionIfEmpty(statement.position)) -> code._2.map(_.positionIfEmpty(statement.position))
}
override def labelChunk(labelName: String): List[MLine] = ???
override def jmpChunk(label: Label): List[MLine] = ???
override def branchChunk(opcode: BranchingOpcodeMapping, labelName: String): List[MLine] = ???
override def compileExpressionForBranching(ctx: CompilationContext, expr: Expression, branching: BranchSpec): List[MLine] = ???
override def replaceLabel(ctx: CompilationContext, line: MLine, from: String, to: String): MLine = ???
override def returnAssemblyStatement: ExecutableStatement = ???
override def callChunk(label: ThingInMemory): List[MLine] = ???
override def areBlocksLarge(blocks: List[MLine]*): Boolean = ???
}

View File

@ -0,0 +1,13 @@
package millfork.compiler.m6809
import millfork.assembly.m6809.MLine
import millfork.compiler.{AbstractStatementPreprocessor, CompilationContext}
import millfork.node.{ExecutableStatement, ForStatement}
/**
* @author Karol Stasiak
*/
class M6809StatementPreprocessor(ctx: CompilationContext, statements: List[ExecutableStatement])
extends AbstractStatementPreprocessor(ctx, statements) {
override def maybeOptimizeForStatement(f: ForStatement): Option[(ExecutableStatement, VV)] = None
}

View File

@ -1,5 +1,6 @@
package millfork.env
import millfork.assembly.m6809.{MOpcode, NonExistent}
import millfork.assembly.{BranchingOpcodeMapping, Elidability}
import millfork.{env, _}
import millfork.assembly.mos.{AddrMode, Opcode}
@ -1806,6 +1807,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
case CpuFamily.M6502 => List(MosAssemblyStatement(Opcode.CHANGED_MEM, AddrMode.DoesNotExist, LiteralExpression(0, 1), Elidability.Fixed))
case CpuFamily.I80 => List(Z80AssemblyStatement(ZOpcode.CHANGED_MEM, NoRegisters, None, LiteralExpression(0, 1), Elidability.Fixed))
case CpuFamily.I86 => List(Z80AssemblyStatement(ZOpcode.CHANGED_MEM, NoRegisters, None, LiteralExpression(0, 1), Elidability.Fixed))
case CpuFamily.M6809 => List(M6809AssemblyStatement(MOpcode.CHANGED_MEM, NonExistent, LiteralExpression(0, 1), Elidability.Fixed))
case _ => ???
})
}

View File

@ -1,6 +1,7 @@
package millfork.node
import millfork.assembly.Elidability
import millfork.assembly.m6809.{MAddrMode, MOpcode}
import millfork.assembly.mos.{AddrMode, Opcode}
import millfork.assembly.z80.{ZOpcode, ZRegisters}
import millfork.env.{Constant, ParamPassingConvention, Type}
@ -197,6 +198,15 @@ object ZRegister extends Enumeration {
val main7Registers: Set[ZRegister.Value] = Set[ZRegister.Value](ZRegister.A, ZRegister.B, ZRegister.C, ZRegister.D, ZRegister.D, ZRegister.E, ZRegister.H, ZRegister.L)
}
object M6809Register extends Enumeration {
val A, B, D, DP, X, Y, U, S, PC, CC = Value
def registerSize(reg: Value): Int = reg match {
case D | X | Y | U | S | PC => 2
case A | B | DP | CC => 1
}
}
//case class Indexing(child: Expression, register: Register.Value) extends Expression
case class VariableExpression(name: String) extends LhsExpression {
@ -501,6 +511,10 @@ case class Z80AssemblyStatement(opcode: ZOpcode.Value, registers: ZRegisters, of
override def getAllExpressions: List[Expression] = List(expression)
}
case class M6809AssemblyStatement(opcode: MOpcode.Value, addrMode: MAddrMode, expression: Expression, elidability: Elidability.Value) extends ExecutableStatement {
override def getAllExpressions: List[Expression] = List(expression)
}
case class IfStatement(condition: Expression, thenBranch: List[ExecutableStatement], elseBranch: List[ExecutableStatement]) extends CompoundStatement {
override def getAllExpressions: List[Expression] = condition :: (thenBranch ++ elseBranch).flatMap(_.getAllExpressions)

View File

@ -0,0 +1,103 @@
package millfork.output
import millfork.{CompilationOptions, Platform}
import millfork.assembly.m6809.{MOpcode, _}
import millfork.compiler.m6809.M6809Compiler
import millfork.env.{Environment, Label, MemoryAddressConstant, NormalFunction}
import millfork.node.{NiceFunctionProperty, Program}
import scala.collection.mutable
/**
* @author Karol Stasiak
*/
class M6809Assembler(program: Program,
rootEnv: Environment,
platform: Platform) extends AbstractAssembler[MLine](program, rootEnv, platform, M6809InliningCalculator, M6809Compiler) {
override def bytePseudoopcode: String = "FCB"
override def deduplicate(options: CompilationOptions, compiledFunctions: mutable.Map[String, CompiledFunction[MLine]]): Unit = ()
override def injectLabels(labelMap: Map[String, (Int, Int)], code: List[MLine]): List[MLine] = code
override def quickSimplify(code: List[MLine]): List[MLine] = code
override def gatherNiceFunctionProperties(niceFunctionProperties: mutable.Set[(NiceFunctionProperty, String)], functionName: String, code: List[MLine]): Unit = ()
override def performFinalOptimizationPass(f: NormalFunction, actuallyOptimize: Boolean, options: CompilationOptions, code: List[MLine]): List[MLine] = code
override def emitInstruction(bank: String, options: CompilationOptions, index: Int, instr: MLine): Int = {
import millfork.assembly.m6809.MOpcode._
instr match {
case MLine0(BYTE, RawByte, c) =>
writeByte(bank, index, c)
index + 1
case MLine0(BYTE, _, _) => log.fatal("BYTE opcode failure")
case MLine0(_, RawByte, _) => log.fatal("BYTE opcode failure")
case MLine0(LABEL, NonExistent, MemoryAddressConstant(Label(labelName))) =>
val bank0 = mem.banks(bank)
labelMap(labelName) = bank0.index -> index
index
case MLine0(op, NonExistent, _) if MOpcode.NoopDiscard(op) =>
index
case MLine0(op, Inherent, _) if M6809Assembler.inherent.contains(op) =>
writeByte(bank, index, M6809Assembler.inherent(op))
index + 1
case MLine0(op, InherentA, _) if M6809Assembler.inherentA.contains(op) =>
writeByte(bank, index, M6809Assembler.inherentA(op))
index + 1
case MLine0(op, InherentB, _) if M6809Assembler.inherentB.contains(op) =>
writeByte(bank, index, M6809Assembler.inherentB(op))
index + 1
case MLine0(op, Immediate, param) if M6809Assembler.immediate.contains(op) =>
writeByte(bank, index, M6809Assembler.immediate(op))
writeByte(bank, index + 1, param)
index + 1
case _ =>
// TODO
throw new IllegalArgumentException("Not supported: " + instr)
}
}
}
object M6809Assembler {
val inherent: mutable.Map[MOpcode.Value, Byte] = mutable.Map[MOpcode.Value, Byte]()
val inherentA: mutable.Map[MOpcode.Value, Byte] = mutable.Map[MOpcode.Value, Byte]()
val inherentB: mutable.Map[MOpcode.Value, Byte] = mutable.Map[MOpcode.Value, Byte]()
val immediate: mutable.Map[MOpcode.Value, Byte] = mutable.Map[MOpcode.Value, Byte]()
private def inh(op: MOpcode.Value, value: Int): Unit = inherent(op) = value.toByte
private def inab(op: MOpcode.Value, value: Int): Unit = {
inherentA(op) = value.toByte
inherentB(op) = value.+(0x10).toByte
}
private def imm(op: MOpcode.Value, value: Int): Unit = immediate(op) = value.toByte
import MOpcode._
inh(ABX, 0x3a)
inh(DAA, 0x19)
inh(MUL, 0x3d)
inh(NOP, 0x12)
inh(RTI, 0x3B)
inh(RTS, 0x39)
inh(SEX, 0x1d)
inh(SWI, 0x3f)
inh(SYNC, 0x13)
inab(ASL, 0x48)
inab(ASR, 0x47)
inab(CLR, 0x4f)
inab(COM, 0x43)
inab(DEC, 0x4a)
inab(INC, 0x48)
inab(LSR, 0x44)
inab(NEG, 0x40)
inab(ROL, 0x49)
inab(ROR, 0x46)
inab(TST, 0x4d)
}

View File

@ -0,0 +1,16 @@
package millfork.output
import millfork.JobContext
import millfork.assembly.m6809.MLine
/**
* @author Karol Stasiak
*/
object M6809InliningCalculator extends AbstractInliningCalculator[MLine] {
override def codeForInlining(fname: String, functionsThatCanBeCalledFromInlinedFunctions: Set[String], code: List[MLine]): Option[List[MLine]] = None
override def inline(code: List[MLine], inlinedFunctions: Map[String, List[MLine]], jobContext: JobContext): List[MLine] = {
if (inlinedFunctions.isEmpty) code
else ???
}
}

View File

@ -0,0 +1,31 @@
package millfork.parser
import fastparse.all
import millfork.CompilationOptions
import millfork.assembly.m6809.MLine
import millfork.node.{ExecutableStatement, ParameterDeclaration, Position, Statement}
import millfork.output.{MemoryAlignment, NoAlignment, WithinPageAlignment}
/**
* @author Karol Stasiak
*/
class M6809Parser(filename: String,
input: String,
currentDirectory: String,
options: CompilationOptions,
featureConstants: Map[String, Long],
useIntelSyntax: Boolean) extends MfParser[MLine](filename, input, currentDirectory, options, featureConstants) {
override def allowIntelHexAtomsInAssembly: Boolean = false
override def asmParamDefinition: all.P[ParameterDeclaration] = ???
def fastAlignmentForArrays: MemoryAlignment = WithinPageAlignment
def fastAlignmentForFunctions: MemoryAlignment = NoAlignment
override def asmStatement: all.P[ExecutableStatement] = ???
override def validateAsmFunctionBody(p: Position, flags: Set[String], name: String, statements: Option[List[Statement]]): Unit = {
// TODO
}
}

View File

@ -9,7 +9,7 @@ import org.scalatest.{FunSuite, Matchers}
*/
class BasicSymonTest extends FunSuite with Matchers {
test("Empty test") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086)(
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Intel8086, Cpu.Motorola6809)(
"""
| void main () {
|

View File

@ -0,0 +1,175 @@
package millfork.test.emu
import java.nio.charset.StandardCharsets
import java.nio.file.{Files, Paths}
import fastparse.core.Parsed.{Failure, Success}
import millfork._
import millfork.assembly.AssemblyOptimization
import millfork.assembly.m6809.MLine
import millfork.compiler.m6809.M6809Compiler
import millfork.compiler.{CompilationContext, LabelGenerator}
import millfork.env.{Environment, InitializedArray, InitializedMemoryVariable, NormalFunction}
import millfork.node.opt.NodeOptimization
import millfork.node.{Program, StandardCallGraph}
import millfork.output.{M6809Assembler, MemoryBank}
import millfork.parser.{PreprocessingResult, Preprocessor, Z80Parser}
import org.scalatest.Matchers
import scala.collection.JavaConverters._
import scala.collection.mutable
/**
* @author Karol Stasiak
*/
object EmuM6809Run {
private def preload(cpu: millfork.Cpu.Value, filename: String): Option[Program] = {
TestErrorReporting.log.info(s"Loading $filename for $cpu")
val source = Files.readAllLines(Paths.get(filename), StandardCharsets.US_ASCII).asScala.mkString("\n")
val options = CompilationOptions(EmuPlatform.get(cpu), Map(
CompilationFlag.LenientTextEncoding -> true
), None, 0, Map(), JobContext(TestErrorReporting.log, new LabelGenerator))
val PreprocessingResult(preprocessedSource, features, _) = Preprocessor.preprocessForTest(options, source)
TestErrorReporting.log.debug(s"Features: $features")
TestErrorReporting.log.info(s"Parsing $filename")
val parser = Z80Parser(filename, preprocessedSource, "", options, features, useIntelSyntax = false)
parser.toAst match {
case Success(x, _) => Some(x)
case f: Failure[_, _] =>
TestErrorReporting.log.error(f.toString)
TestErrorReporting.log.error(f.extra.toString)
TestErrorReporting.log.error(f.lastParser.toString)
TestErrorReporting.log.error("Syntax error", Some(parser.lastPosition))
TestErrorReporting.log.error("Parsing error")
???
}
}
private lazy val cache: mutable.Map[(millfork.Cpu.Value, String), Option[Program]] = mutable.Map[(millfork.Cpu.Value, String), Option[Program]]()
private def get(cpu: millfork.Cpu.Value, path: String): Program =
synchronized { cache.getOrElseUpdate(cpu->path, preload(cpu, path)).getOrElse(throw new IllegalStateException()) }
def cachedMath(cpu: millfork.Cpu.Value): Program = get(cpu, "include/m6809_math.mfk")
def cachedStdio(cpu: millfork.Cpu.Value): Program = get(cpu, "src/test/resources/include/dummy_stdio.mfk")
}
class EmuM6809Run(cpu: millfork.Cpu.Value, nodeOptimizations: List[NodeOptimization], assemblyOptimizations: List[AssemblyOptimization[MLine]]) extends Matchers {
def inline: Boolean = false
def optimizeForSize: Boolean = false
private val TooManyCycles: Long = 1500000
def apply(source: String): MemoryBank = {
apply2(source)._2
}
def apply2(source: String): (Timings, MemoryBank) = {
Console.out.flush()
Console.err.flush()
val log = TestErrorReporting.log
println(source)
val platform = EmuPlatform.get(cpu)
val extraFlags = Map(
CompilationFlag.DangerousOptimizations -> true,
CompilationFlag.EnableInternalTestSyntax -> true,
CompilationFlag.InlineFunctions -> this.inline,
CompilationFlag.OptimizeStdlib -> this.inline,
CompilationFlag.OptimizeForSize -> this.optimizeForSize,
CompilationFlag.SubroutineExtraction -> optimizeForSize,
CompilationFlag.EmitIllegals -> false,
CompilationFlag.LenientTextEncoding -> true)
val options = CompilationOptions(platform, millfork.Cpu.defaultFlags(cpu).map(_ -> true).toMap ++ extraFlags, None, 0, Map(), JobContext(log, new LabelGenerator))
println(cpu)
println(options.flags.filter(_._2).keys.toSeq.sorted)
log.hasErrors = false
log.verbosity = 999
var effectiveSource = source
if (!source.contains("_panic")) effectiveSource += "\n void _panic(){while(true){}}"
log.setSource(Some(effectiveSource.linesIterator.toIndexedSeq))
val PreprocessingResult(preprocessedSource, features, pragmas) = Preprocessor.preprocessForTest(options, effectiveSource)
// tests use Intel syntax only when forced to:
val parserF = Z80Parser("", preprocessedSource, "", options, features, pragmas.contains("intel_syntax"))
parserF.toAst match {
case Success(unoptimized, _) =>
log.assertNoErrors("Parse failed")
// prepare
val withLibraries = {
var tmp = unoptimized
// tmp += EmuM6809Run.cachedMath(cpu) // TODO: add this only after you implement maths
if (source.contains("import stdio")) {
tmp += EmuM6809Run.cachedStdio(cpu)
}
tmp
}
val program = nodeOptimizations.foldLeft(withLibraries.applyImportantAliases)((p, opt) => p.applyNodeOptimization(opt, options))
val callGraph = new StandardCallGraph(program, log)
val env = new Environment(None, "", CpuFamily.I80, options)
env.collectDeclarations(program, options)
val hasOptimizations = assemblyOptimizations.nonEmpty
var unoptimizedSize = 0L
// print unoptimized asm
env.allPreallocatables.foreach {
case f: NormalFunction =>
val unoptimized = M6809Compiler.compile(CompilationContext(f.environment, f, 0, options, Set()))
unoptimizedSize += unoptimized.map(_.sizeInBytes).sum
case d: InitializedArray =>
unoptimizedSize += d.contents.length
case d: InitializedMemoryVariable =>
unoptimizedSize += d.typ.size
}
log.assertNoErrors("Compile failed")
// compile
val env2 = new Environment(None, "", CpuFamily.I80, options)
env2.collectDeclarations(program, options)
val assembler = new M6809Assembler(program, env2, platform)
val output = assembler.assemble(callGraph, assemblyOptimizations, options)
println(";;; compiled: -----------------")
output.asm.takeWhile(s => !(s.startsWith(".") && s.contains("= $"))).filterNot(_.contains("////; DISCARD_")).foreach(println)
println(";;; ---------------------------")
assembler.labelMap.foreach { case (l, (_, addr)) => println(f"$l%-15s $$$addr%04x") }
val optimizedSize = assembler.mem.banks("default").initialized.count(identity).toLong
if (unoptimizedSize == optimizedSize) {
println(f"Size: $unoptimizedSize%5d B")
} else {
println(f"Unoptimized size: $unoptimizedSize%5d B")
println(f"Optimized size: $optimizedSize%5d B")
println(f"Gain: ${(100L * (unoptimizedSize - optimizedSize) / unoptimizedSize.toDouble).round}%5d%%")
}
if (log.hasErrors) {
fail("Code generation failed")
}
val memoryBank = assembler.mem.banks("default")
(0x1f0 until 0x200).foreach(i => memoryBank.readable(i) = true)
(0xff00 to 0xffff).foreach{i =>
memoryBank.readable(i) = true
memoryBank.writeable(i) = true
}
(0x200 until 0x2000).takeWhile(memoryBank.occupied(_)).map(memoryBank.output).grouped(16).map(_.map(i => f"$i%02x").mkString(" ")).foreach(log.debug(_))
val timings = platform.cpu match {
case _ =>
Timings(-1, -1) -> memoryBank
}
log.clearErrors()
timings
case f: Failure[_, _] =>
println(f)
println(f.extra.toString)
println(f.lastParser.toString)
log.error("Syntax error", Some(parserF.lastPosition))
fail("Parsing error")
}
}
}

View File

@ -14,6 +14,7 @@ object EmuUnoptimizedCrossPlatformRun {
val (_, mz) = if (platforms.contains(Cpu.Z80)) EmuUnoptimizedZ80Run.apply2(source) else Timings(-1, -1) -> null
val (_, mi) = if (platforms.contains(Cpu.Intel8080)) EmuUnoptimizedIntel8080Run.apply2(source) else Timings(-1, -1) -> null
val (_, ms) = if (platforms.contains(Cpu.Sharp)) EmuUnoptimizedSharpRun.apply2(source) else Timings(-1, -1) -> null
val (_, mo) = if (platforms.contains(Cpu.Motorola6809)) EmuUnoptimizedM6809Run.apply2(source) else Timings(-1, -1) -> null
val (_, mx) = if (Settings.enableIntel8086Tests && platforms.contains(Cpu.Intel8086)) EmuUnoptimizedIntel8086Run.apply2(source) else Timings(-1, -1) -> null
if (Settings.enable6502Tests && platforms.contains(Cpu.Mos)) {
println(f"Running 6502")
@ -43,5 +44,9 @@ object EmuUnoptimizedCrossPlatformRun {
println(f"Running 8086")
verifier(mx)
}
if (Settings.enableMotorola6809Tests && platforms.contains(Cpu.Motorola6809)) {
println(f"Running 6809")
verifier(mx)
}
}
}

View File

@ -25,3 +25,5 @@ object EmuUnoptimizedIntel8085Run extends EmuZ80Run(Cpu.Intel8085, Nil, Nil)
object EmuUnoptimizedIntel8086Run extends EmuI86Run(Nil, Nil)
object EmuUnoptimizedSharpRun extends EmuZ80Run(Cpu.Sharp, Nil, Nil)
object EmuUnoptimizedM6809Run extends EmuM6809Run(Cpu.Motorola6809, Nil, Nil)

View File

@ -48,6 +48,12 @@ object Settings {
*/
val enableUnemulatedTests: Boolean = true
/**
* Should the Motorola 6809 tests be enabled?
* Motorola 6809 emulation is not yet implemented, so keep this false for the time being.
*/
val enableMotorola6809Tests: Boolean = false
// the following are the core platforms and they are all tested by default
val enable6502Tests: Boolean = true