1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-07-05 09:28:54 +00:00

Fix macros and few other things when compiling for Z80

This commit is contained in:
Karol Stasiak 2018-07-16 23:02:34 +02:00
parent 39dfe13a3f
commit 5a8fe547bf
3 changed files with 70 additions and 12 deletions

View File

@ -517,6 +517,8 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
case AssemblyParamSignature(List(AssemblyParam(typ1, ZRegisterVariable(ZRegister.HL, typ2), AssemblyParameterPassingBehaviour.Copy)))
if typ1.size == 2 && typ2.size == 2 =>
compileToHL(ctx, params.head) :+ ZLine(CALL, NoRegisters, function.toAddress)
case AssemblyParamSignature(Nil) =>
List(ZLine(CALL, NoRegisters, function.toAddress))
case AssemblyParamSignature(paramConvs) =>
// TODO: stop being lazy and implement this
???

View File

@ -1,9 +1,12 @@
package millfork.compiler.z80
import java.util.Locale
import millfork.assembly.z80.ZLine
import millfork.compiler.{CompilationContext, MacroExpander}
import millfork.env.AssemblyParam
import millfork.node.{ExecutableStatement, Expression}
import millfork.env._
import millfork.error.ErrorReporting
import millfork.node._
/**
* @author Karol Stasiak
@ -11,5 +14,52 @@ import millfork.node.{ExecutableStatement, Expression}
object Z80MacroExpander extends MacroExpander[ZLine] {
override def nextLabel(prefix: String): String = Z80Compiler.nextLabel(prefix)
override def prepareAssemblyParams(ctx: CompilationContext, assParams: List[AssemblyParam], params: List[Expression], code: List[ExecutableStatement]): (List[ZLine], List[ExecutableStatement]) = ???
}
override def prepareAssemblyParams(ctx: CompilationContext, assParams: List[AssemblyParam], params: List[Expression], code: List[ExecutableStatement]): (List[ZLine], List[ExecutableStatement]) = {
var paramPreparation = List[ZLine]()
var actualCode = code
var hadRegisterParam = false
assParams.zip(params).foreach {
case (AssemblyParam(typ, Placeholder(ph, phType), AssemblyParameterPassingBehaviour.ByReference), actualParam) =>
actualParam match {
case VariableExpression(vname) =>
ctx.env.get[ThingInMemory](vname)
case l: LhsExpression =>
// TODO: ??
Z80ExpressionCompiler.compileToA(ctx, l)
case _ =>
ErrorReporting.error("A non-assignable expression was passed to an inlineable function as a `ref` parameter", actualParam.position)
}
actualCode = actualCode.map {
case a@MosAssemblyStatement(_, _, expr, _) =>
a.copy(expression = expr.replaceVariable(ph, actualParam))
case x => x
}
case (AssemblyParam(typ, Placeholder(ph, phType), AssemblyParameterPassingBehaviour.ByConstant), actualParam) =>
ctx.env.eval(actualParam).getOrElse(Constant.error("Non-constant expression was passed to an inlineable function as a `const` parameter", actualParam.position))
actualCode = actualCode.map {
case a@Z80AssemblyStatement(_, _, _, expr, _) =>
a.copy(expression = expr.replaceVariable(ph, actualParam))
case x => x
}
case (AssemblyParam(typ, v@ZRegisterVariable(register, _), AssemblyParameterPassingBehaviour.Copy), actualParam) =>
if (hadRegisterParam) {
ErrorReporting.error("Only one macro assembly function parameter can be passed via a register", actualParam.position)
}
hadRegisterParam = true
paramPreparation = (register, typ.size) match {
case (ZRegister.A, 1) => Z80ExpressionCompiler.compileToA(ctx, actualParam)
case (r@(ZRegister.B | ZRegister.C | ZRegister.D | ZRegister.E | ZRegister.H | ZRegister.L), 1) => Z80ExpressionCompiler.compileToA(ctx, actualParam) :+ ZLine.ld8(r, ZRegister.A)
case (ZRegister.HL, 2) => Z80ExpressionCompiler.compileToHL(ctx, actualParam)
case (ZRegister.BC, 2) => Z80ExpressionCompiler.compileToBC(ctx, actualParam)
case (ZRegister.DE, 2) => Z80ExpressionCompiler.compileToDE(ctx, actualParam)
case _ =>
ErrorReporting.error(s"Invalid parameter for macro: ${typ.name} ${register.toString.toLowerCase(Locale.ROOT)}", actualParam.position)
Nil
}
case (AssemblyParam(_, _, AssemblyParameterPassingBehaviour.Copy), actualParam) =>
???
case (_, actualParam) =>
}
paramPreparation -> actualCode
}
}

View File

@ -19,6 +19,7 @@ object Z80StatementCompiler extends AbstractStatementCompiler[ZLine] {
def compile(ctx: CompilationContext, statement: ExecutableStatement): List[ZLine] = {
val options = ctx.options
val env = ctx.env
statement match {
case ReturnStatement(None) =>
fixStackOnReturn(ctx) ++ (ctx.function.returnType match {
@ -132,7 +133,7 @@ object Z80StatementCompiler extends AbstractStatementCompiler[ZLine] {
case s: ContinueStatement =>
compileContinueStatement(ctx, s)
case ExpressionStatement(e@FunctionCallExpression(name, params)) =>
ctx.env.lookupFunction(name, params.map(p => Z80ExpressionCompiler.getExpressionType(ctx, p) -> p)) match {
env.lookupFunction(name, params.map(p => Z80ExpressionCompiler.getExpressionType(ctx, p) -> p)) match {
case Some(i: MacroFunction) =>
val (paramPreparation, inlinedStatements) = Z80MacroExpander.inlineFunction(ctx, i, params, e.position)
paramPreparation ++ compile(ctx.withInlinedEnv(i.environment, Z80Compiler.nextLabel("en")), inlinedStatements)
@ -142,14 +143,19 @@ object Z80StatementCompiler extends AbstractStatementCompiler[ZLine] {
case ExpressionStatement(e) =>
Z80ExpressionCompiler.compile(ctx, e, ZExpressionTarget.NOTHING)
case Z80AssemblyStatement(op, reg, offset, expression, elidable) =>
val param = ctx.env.evalForAsm(expression) match {
case Some(v) => v
case None =>
ErrorReporting.error("Inlining failed due to non-constant things", expression.position)
Constant.Zero
val param: Constant = expression match {
// TODO: hmmm
case VariableExpression(name) =>
if (Seq(JP, JR, DJNZ, LABEL).contains(op)) {
MemoryAddressConstant(Label(name))
} else {
env.evalForAsm(expression).getOrElse(env.get[ThingInMemory](name, expression.position).toAddress)
}
case _ =>
env.evalForAsm(expression).getOrElse(Constant.error(s"`$expression` is not a constant", expression.position))
}
val registers = (reg, offset) match {
case (OneRegister(r), Some(o)) => ctx.env.evalForAsm(expression) match {
case (OneRegister(r), Some(o)) => env.evalForAsm(expression) match {
case Some(NumericConstant(v, _)) => OneRegisterOffset(r, v.toInt)
case Some(_) =>
ErrorReporting.error("Non-numeric constant", o.position)
@ -158,7 +164,7 @@ object Z80StatementCompiler extends AbstractStatementCompiler[ZLine] {
ErrorReporting.error("Inlining failed due to non-constant things", o.position)
reg
}
case (TwoRegisters(t, s), Some(o)) => ctx.env.evalForAsm(expression) match {
case (TwoRegisters(t, s), Some(o)) => env.evalForAsm(expression) match {
case Some(NumericConstant(v, _)) => TwoRegistersOffset(t, s, v.toInt)
case Some(_) =>
ErrorReporting.error("Non-numeric constant", o.position)