mirror of
https://github.com/KarolS/millfork.git
synced 2024-08-14 08:28:58 +00:00
Fix macros and few other things when compiling for Z80
This commit is contained in:
parent
39dfe13a3f
commit
5a8fe547bf
@ -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
|
||||
???
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user