mirror of
https://github.com/KarolS/millfork.git
synced 2025-02-21 21:29:00 +00:00
Allow refering to labels from other functions in assembly (fixes #101)
This commit is contained in:
parent
ff6106a838
commit
196ad6542f
@ -52,6 +52,17 @@ Global label names have to start with a letter and can contain digits, underscor
|
||||
Local label names (available since Millfork 0.3.22) start with a period and are visible only in the given function.
|
||||
Anonymous labels designated with `+` or `-` are also not supported.
|
||||
|
||||
Referring to a global label with an offset requires wrapping it in `label(…)`:
|
||||
|
||||
STA .local_opcode // ok
|
||||
STA label(.local_opcode) // ok
|
||||
STA .local_opcode + 1 // ok
|
||||
STA label(.local_opcode) + 1 // ok
|
||||
STA global_opcode // ok
|
||||
STA label(global_opcode) // ok
|
||||
STA global_opcode + 1 // NOT OK
|
||||
sta label(global_opcode) + 1 // ok
|
||||
|
||||
Assembly can refer to variables and constants defined in Millfork,
|
||||
but you need to be careful with using absolute vs immediate addressing:
|
||||
|
||||
|
@ -27,6 +27,17 @@ Global label names have to start with a letter and can contain digits, underscor
|
||||
Local label names (available since Millfork 0.3.22) start with a period and are visible only in the given function.
|
||||
Anonymous labels designated with `+` or `-` are also not supported.
|
||||
|
||||
Referring to a global label with an offset requires wrapping it in `label(…)`:
|
||||
|
||||
STA .local_opcode // ok
|
||||
STA label(.local_opcode) // ok
|
||||
STA .local_opcode + 1 // ok
|
||||
STA label(.local_opcode) + 1 // ok
|
||||
STA global_opcode // ok
|
||||
STA label(global_opcode) // ok
|
||||
STA global_opcode + 1 // NOT OK
|
||||
STA label(global_opcode) + 1 // ok
|
||||
|
||||
Assembly can refer to variables and constants defined in Millfork,
|
||||
but you need to be careful with using absolute vs immediate addressing:
|
||||
|
||||
|
@ -52,6 +52,17 @@ Global label names have to start with a letter and can contain digits, underscor
|
||||
Local label names (available since Millfork 0.3.22) start with a period and are visible only in the given function.
|
||||
Anonymous labels designated with `+` or `-` are also not supported.
|
||||
|
||||
Referring to a global label with an offset requires wrapping it in `label(…)`:
|
||||
|
||||
LD (.local_opcode),A // ok
|
||||
LD (label(.local_opcode)),A // ok
|
||||
LD (.local_opcode + 1),A // ok
|
||||
LD (label(.local_opcode) + 1),A // ok
|
||||
LD (global_opcode),A // ok
|
||||
LD (label(global_opcode)),A // ok
|
||||
LD (global_opcode + 1),A // NOT OK
|
||||
LD (label(global_opcode) + 1),A // ok
|
||||
|
||||
Assembly can refer to variables and constants defined in Millfork,
|
||||
but you need to be careful with using absolute vs immediate addressing:
|
||||
|
||||
|
@ -6,7 +6,7 @@ import millfork.assembly.m6809.{Inherent, MLine, MOpcode, NonExistent}
|
||||
import millfork.compiler.{AbstractCompiler, AbstractExpressionCompiler, AbstractStatementCompiler, BranchSpec, CompilationContext}
|
||||
import millfork.node.{Assignment, BlackHoleExpression, BreakStatement, ContinueStatement, DoWhileStatement, EmptyStatement, ExecutableStatement, Expression, ExpressionStatement, ForEachStatement, ForStatement, FunctionCallExpression, GotoStatement, IfStatement, LabelStatement, LiteralExpression, M6809AssemblyStatement, MemsetStatement, ReturnDispatchStatement, ReturnStatement, VariableExpression, WhileStatement}
|
||||
import millfork.assembly.m6809.MOpcode._
|
||||
import millfork.env.{BooleanType, ConstantBooleanType, FatBooleanType, Label, MemoryAddressConstant, StructureConstant, ThingInMemory}
|
||||
import millfork.env.{BooleanType, Constant, ConstantBooleanType, FatBooleanType, Label, MemoryAddressConstant, StructureConstant, ThingInMemory}
|
||||
|
||||
/**
|
||||
* @author Karol Stasiak
|
||||
@ -58,12 +58,21 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
|
||||
}
|
||||
(eval ++ epilogue ++ rts) -> Nil
|
||||
case M6809AssemblyStatement(opcode, addrMode, expression, elidability) =>
|
||||
ctx.env.evalForAsm(expression, opcode) match {
|
||||
case Some(e) => List(MLine(opcode, addrMode, e, elidability)) -> Nil
|
||||
val e = ctx.env.evalForAsm(expression) match {
|
||||
case Some(e) => e
|
||||
case None =>
|
||||
println(statement)
|
||||
???
|
||||
expression match {
|
||||
case VariableExpression(name) =>
|
||||
env.maybeGet[ThingInMemory](name).map(_.toAddress).getOrElse {
|
||||
val fqName = if (name.startsWith(".")) env.prefix + name else name
|
||||
MemoryAddressConstant(Label(fqName))
|
||||
}
|
||||
case _ =>
|
||||
ctx.log.error("Invalid parameter", statement.position)
|
||||
Constant.Zero
|
||||
}
|
||||
}
|
||||
List(MLine(opcode, addrMode, e, elidability)) -> Nil
|
||||
case Assignment(destination, source) =>
|
||||
if (destination == BlackHoleExpression) return M6809ExpressionCompiler.compile(ctx, source, MExpressionTarget.NOTHING, BranchSpec.None) -> Nil
|
||||
val destinationType = AbstractExpressionCompiler.getExpressionType(ctx, destination)
|
||||
@ -107,13 +116,22 @@ object M6809StatementCompiler extends AbstractStatementCompiler[MLine] {
|
||||
case s:ContinueStatement =>
|
||||
compileContinueStatement(ctx, s) -> Nil
|
||||
case M6809AssemblyStatement(opcode, addrMode, expression, elidability) =>
|
||||
ctx.env.evalForAsm(expression, opcode) match {
|
||||
case Some(param) =>
|
||||
List(MLine(opcode, addrMode, param, elidability)) -> Nil
|
||||
val silent = MOpcode.Branching(opcode) || opcode == LABEL || opcode == CHANGED_MEM
|
||||
val param: Constant = ctx.env.evalForAsm(expression, silent = silent) match {
|
||||
case Some(param) => param
|
||||
case None =>
|
||||
ctx.log.error("Invalid parameter", expression.position)
|
||||
Nil -> Nil
|
||||
expression match {
|
||||
case VariableExpression(name) =>
|
||||
env.maybeGet[ThingInMemory](name).map(_.toAddress).getOrElse{
|
||||
val fqName = if (name.startsWith(".")) env.prefix + name else name
|
||||
MemoryAddressConstant(Label(fqName))
|
||||
}
|
||||
case _ =>
|
||||
ctx.log.error("Invalid parameter", expression.position)
|
||||
Constant.Zero
|
||||
}
|
||||
}
|
||||
List(MLine(opcode, addrMode, param, elidability)) -> Nil
|
||||
case s:LabelStatement =>
|
||||
List(MLine.label(env.prefix + s.name)) -> Nil
|
||||
case s: GotoStatement =>
|
||||
|
@ -342,11 +342,10 @@ object MosStatementCompiler extends AbstractStatementCompiler[AssemblyLine] {
|
||||
x match {
|
||||
// TODO: hmmm
|
||||
case VariableExpression(name) =>
|
||||
if (OpcodeClasses.ShortBranching(o) || o == JMP || o == LABEL || o == CHANGED_MEM || OpcodeClasses.HudsonTransfer(o)) {
|
||||
val silent = OpcodeClasses.ShortBranching(o) || o == JMP || o == LABEL || o == CHANGED_MEM || OpcodeClasses.HudsonTransfer(o)
|
||||
env.evalForAsm(x, silent = silent).orElse(env.maybeGet[ThingInMemory](name).map(_.toAddress)).getOrElse{
|
||||
val fqName = if (name.startsWith(".")) env.prefix + name else name
|
||||
MemoryAddressConstant(Label(fqName))
|
||||
} else {
|
||||
env.evalForAsm(x).getOrElse(env.get[ThingInMemory](name, x.position).toAddress)
|
||||
}
|
||||
case FunctionCallExpression("byte_and_pointer$", List(z, b@VariableExpression(name))) =>
|
||||
StructureConstant(env.get[StructType]("byte_and_pointer$"), List(
|
||||
|
18
src/main/scala/millfork/env/Environment.scala
vendored
18
src/main/scala/millfork/env/Environment.scala
vendored
@ -973,15 +973,15 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
}
|
||||
}
|
||||
|
||||
def evalForAsm(e: Expression, op: MOpcode.Value = MOpcode.NOP, silent: Boolean = false): Option[Constant] = {
|
||||
def evalForAsm(e: Expression, silent: Boolean = false): Option[Constant] = {
|
||||
e match {
|
||||
// TODO: hmmm
|
||||
case VariableExpression(name) =>
|
||||
import MOpcode._
|
||||
if (MOpcode.Branching(op) || op == LABEL || op == CHANGED_MEM) {
|
||||
val fqName = if (name.startsWith(".")) prefix + name else name
|
||||
return Some(MemoryAddressConstant(Label(fqName)))
|
||||
}
|
||||
case FunctionCallExpression("label", List(VariableExpression(name))) if (!name.contains(".")) =>
|
||||
return Some(Label(name).toAddress)
|
||||
case FunctionCallExpression("label", List(VariableExpression(name))) if (name.startsWith(".")) =>
|
||||
return Some(Label(prefix + name).toAddress)
|
||||
case FunctionCallExpression("label", _) =>
|
||||
log.error("Invalid label reference", e.position)
|
||||
return Some(Constant.Zero)
|
||||
case _ =>
|
||||
}
|
||||
e match {
|
||||
@ -994,7 +994,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
|
||||
case None =>
|
||||
if (name.startsWith(".")) Some(Label(prefix + name).toAddress)
|
||||
else {
|
||||
if (!silent) log.warn(s"$name is not known", e.position)
|
||||
if (!silent) log.warn(s"$name is not known. If it is a label, consider wrapping it in label(...).", e.position)
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ class AssemblySuite extends FunSuite with Matchers with AppendedClues {
|
||||
| // w&x
|
||||
| asm void main () {
|
||||
| lda #3
|
||||
| sta label(.l)+1
|
||||
| sta .l+1
|
||||
| .l: lda #55
|
||||
| sta output
|
||||
@ -36,6 +37,56 @@ class AssemblySuite extends FunSuite with Matchers with AppendedClues {
|
||||
""".stripMargin)(_.readByte(0xc000) should equal(3))
|
||||
}
|
||||
|
||||
test("Self-modifying assembly 2") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Motorola6809)(
|
||||
"""
|
||||
| byte output @$c000
|
||||
| // w&x
|
||||
| asm void f() {
|
||||
| f_data:
|
||||
| lda #$ff
|
||||
| rts
|
||||
| }
|
||||
|
|
||||
| asm void main () {
|
||||
| lda f_data
|
||||
| sta f_data
|
||||
| lda #3
|
||||
| sta label(f_data)+1
|
||||
| lda #0
|
||||
| jsr f_data
|
||||
| sta output
|
||||
| lda #lo(f)
|
||||
| rts
|
||||
| ignored:}
|
||||
""".stripMargin)(_.readByte(0xc000) should equal(3))
|
||||
}
|
||||
|
||||
test("Self-modifying assembly 2 (Z80)") {
|
||||
EmuCrossPlatformBenchmarkRun(Cpu.Z80)(
|
||||
"""
|
||||
| byte output @$c000
|
||||
| // w&x
|
||||
| asm void f() {
|
||||
| f_data:
|
||||
| ld a, $ff
|
||||
| ret
|
||||
| }
|
||||
|
|
||||
| asm void main () {
|
||||
| ld a,(f_data)
|
||||
| ld (f_data),a
|
||||
| ld a,3
|
||||
| ld (label(f_data)+1),a
|
||||
| ld a,0
|
||||
| call f_data
|
||||
| ld (output),a
|
||||
| ld b,lo(f)
|
||||
| ret
|
||||
| ignored:}
|
||||
""".stripMargin)(_.readByte(0xc000) should equal(3))
|
||||
}
|
||||
|
||||
test("Assembly functions") {
|
||||
EmuBenchmarkRun(
|
||||
"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user