1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-05-28 13:41:31 +00:00

Interrupt handler pointer types

This commit is contained in:
Karol Stasiak 2020-11-11 00:28:21 +01:00
parent 91409504fb
commit fc7643c416
9 changed files with 177 additions and 7 deletions

View File

@ -134,6 +134,26 @@ Using `call` on 6502 requires at least 4 bytes of zeropage pseudoregister.
The value of the pointer `f.pointer` may not be the same as the value of the function address `f.addr`.
## Interrupt handler pointers
Functions that are interrupt pointers have their own pointer types:
* `pointer.interrupt` for hardware interrupt handlers
* `pointer.kernal_interrupt` for kernal interrupt handlers
`pointer.kernal_interrupt` is automatically convertible to `function.void.to.void`
interrupt void handler1(){}
kernal_interrupt void handler2(){}
pointer.interrupt p1
p1 = handler1.pointer
pointer.kernal_interrupt p2
p2 = handler2.pointer
function.void.to.void p3
p3 = handler2.pointer
## Boolean types
Boolean types can be used as conditions. They have two possible values, `true` and `false`.

View File

@ -450,6 +450,8 @@ object AbstractExpressionCompiler {
log.error(s"Invalid function pointer type: $fpt", fp.position)
}
r
case KernalInterruptPointerType =>
v
case fpt =>
log.error(s"Not a function pointer type: $fpt", fp.position)
v
@ -461,6 +463,9 @@ object AbstractExpressionCompiler {
log.error(s"Invalid function pointer type: $fpt", fp.position)
}
r
case fpt@KernalInterruptPointerType =>
log.error(s"Invalid function pointer type: $fpt", fp.position)
v
case fpt =>
log.error(s"Not a function pointer type: $fpt", fp.position)
v

View File

@ -7,7 +7,7 @@ import millfork.assembly.m6809.{Absolute, DAccumulatorIndexed, Immediate, Indexe
import millfork.compiler.{AbstractExpressionCompiler, BranchIfFalse, BranchIfTrue, BranchSpec, ComparisonType, CompilationContext, NoBranching}
import millfork.node.{DerefExpression, Expression, FunctionCallExpression, GeneratedConstantExpression, IndexedExpression, LhsExpression, LiteralExpression, M6809Register, SeparateBytesExpression, SumExpression, VariableExpression}
import millfork.assembly.m6809.MOpcode._
import millfork.env.{AssemblyOrMacroParamSignature, BuiltInBooleanType, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, FlagBooleanType, FunctionInMemory, FunctionPointerType, Label, M6809RegisterVariable, MacroFunction, MathOperator, MemoryAddressConstant, MemoryVariable, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackOffsetThing, StackVariable, StackVariablePointy, StructureConstant, Thing, ThingInMemory, Type, Variable, VariableInMemory, VariableLikeThing, VariablePointy}
import millfork.env.{AssemblyOrMacroParamSignature, BuiltInBooleanType, Constant, ConstantBooleanType, ConstantPointy, ExternFunction, FatBooleanType, FlagBooleanType, FunctionInMemory, FunctionPointerType, KernalInterruptPointerType, Label, M6809RegisterVariable, MacroFunction, MathOperator, MemoryAddressConstant, MemoryVariable, NonFatalCompilationException, NormalFunction, NormalParamSignature, NumericConstant, StackOffsetThing, StackVariable, StackVariablePointy, StructureConstant, Thing, ThingInMemory, Type, Variable, VariableInMemory, VariableLikeThing, VariablePointy}
import scala.collection.GenTraversableOnce
@ -223,14 +223,22 @@ object M6809ExpressionCompiler extends AbstractExpressionCompiler[MLine] {
params match {
case List(fp) =>
getExpressionType(ctx, fp) match {
case KernalInterruptPointerType =>
compileToX(ctx, fp) :+ MLine.absolute(JSR, env.get[ThingInMemory]("call"))
case FunctionPointerType(_, _, _, _, Some(v)) if (v.name == "void") =>
compileToX(ctx, fp) :+ MLine.absolute(JSR, env.get[ThingInMemory]("call"))
case _: FunctionPointerType =>
ctx.log.error("Incompatible function pointer type", fp.position)
compile(ctx, fp, MExpressionTarget.NOTHING)
case _ =>
ctx.log.error("Not a function pointer", fp.position)
compile(ctx, fp, MExpressionTarget.NOTHING)
}
case List(fp, param) =>
getExpressionType(ctx, fp) match {
case KernalInterruptPointerType =>
ctx.log.error("Incompatible function pointer type", fp.position)
compile(ctx, fp, MExpressionTarget.NOTHING)
case FunctionPointerType(_, _, _, Some(pt), Some(v)) =>
if (pt.size > 2 || pt.size < 1) {
ctx.log.error("Invalid parameter type", param.position)

View File

@ -1257,8 +1257,13 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
params match {
case List(fp) =>
getExpressionType(ctx, fp) match {
case KernalInterruptPointerType =>
compileToZReg2(ctx, fp) :+ AssemblyLine.absolute(JSR, env.get[ThingInMemory]("call"))
case FunctionPointerType(_, _, _, _, Some(v)) if (v.name == "void") =>
compileToZReg2(ctx, fp) :+ AssemblyLine.absolute(JSR, env.get[ThingInMemory]("call"))
case _: FunctionPointerType =>
ctx.log.error("Invalid function pointer type", fp.position)
compile(ctx, fp, None, BranchSpec.None)
case _ =>
ctx.log.error("Not a function pointer", fp.position)
compile(ctx, fp, None, BranchSpec.None)
@ -1281,6 +1286,9 @@ object MosExpressionCompiler extends AbstractExpressionCompiler[AssemblyLine] {
ctx.log.error("Invalid parameter type", param.position)
compile(ctx, fp, None, BranchSpec.None) ++ compile(ctx, param, None, BranchSpec.None)
}
case KernalInterruptPointerType =>
ctx.log.error("Invalid function pointer type", fp.position)
compile(ctx, fp, None, BranchSpec.None)
case _ =>
ctx.log.error("Not a function pointer", fp.position)
compile(ctx, fp, None, BranchSpec.None) ++ compile(ctx, param, None, BranchSpec.None)

View File

@ -751,8 +751,13 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
params match {
case List(fp) =>
getExpressionType(ctx, fp) match {
case KernalInterruptPointerType =>
compileToDE(ctx, fp) :+ callLine
case FunctionPointerType(_, _, _, _, Some(v)) if (v.name == "void") =>
compileToDE(ctx, fp) :+ callLine
case _: FunctionPointerType =>
ctx.log.error("Invalid function pointer type", fp.position)
compile(ctx, fp, ZExpressionTarget.NOTHING, BranchSpec.None)
case _ =>
ctx.log.error("Not a function pointer", fp.position)
compile(ctx, fp, ZExpressionTarget.NOTHING, BranchSpec.None)
@ -774,6 +779,9 @@ object Z80ExpressionCompiler extends AbstractExpressionCompiler[ZLine] {
ctx.log.error("Invalid parameter type", param.position)
compileToHL(ctx, fp) ++ compile(ctx, param, ZExpressionTarget.NOTHING)
}
case KernalInterruptPointerType =>
ctx.log.error("Invalid function pointer type", fp.position)
compile(ctx, fp, ZExpressionTarget.NOTHING, BranchSpec.None)
case _ =>
ctx.log.error("Not a function pointer", fp.position)
compile(ctx, fp, ZExpressionTarget.NOTHING) ++ compile(ctx, param, ZExpressionTarget.NOTHING)

View File

@ -317,8 +317,13 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
}
if (name.startsWith("pointer.") && implicitly[Manifest[T]].runtimeClass.isAssignableFrom(classOf[PointerType])) {
val targetName = name.stripPrefix("pointer.")
val target = maybeGet[VariableType](targetName)
return PointerType(name, targetName, target).asInstanceOf[T]
targetName match {
case "interrupt" => return InterruptPointerType.asInstanceOf[T]
case "kernal_interrupt" => return KernalInterruptPointerType.asInstanceOf[T]
case _ =>
val target = maybeGet[VariableType](targetName)
return PointerType(name, targetName, target).asInstanceOf[T]
}
}
val clazz = implicitly[Manifest[T]].runtimeClass
if (things.contains(name)) {
@ -444,6 +449,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
addThing(Alias("signed8", "sbyte"), None)
addThing(DerivedPlainType("unsigned16", w, isSigned = false, isPointy = false), None)
addThing(DerivedPlainType("signed16", w, isSigned = true, isPointy = false), None)
addThing(InterruptPointerType, None)
addThing(KernalInterruptPointerType, None)
for (bits <- Seq(24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128)) {
addThing(DerivedPlainType("unsigned" + bits, get[BasicPlainType]("int" + bits), isSigned = false, isPointy = false), None)
}
@ -1401,7 +1408,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
private def getFunctionPointerType(f: FunctionInMemory) = f.params.types match {
case List() =>
get[Type]("function.void.to." + f.returnType.name)
if (f.returnType == VoidType) get[Type]("pointer.kernal_interrupt")
else get[Type]("function.void.to." + f.returnType.name)
case p :: _ => // TODO: this only handles one type though!
get[Type]("function." + p.name + ".to." + f.returnType.name)
}
@ -1448,6 +1456,11 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
addThing(typedPointer, position)
addThing(RelativeVariable(thing.name + ".pointer.hi", actualAddr + 1, b, zeropage = false, None, isVolatile = false), position)
addThing(RelativeVariable(thing.name + ".pointer.lo", actualAddr, b, zeropage = false, None, isVolatile = false), position)
case f: FunctionInMemory if f.interrupt =>
val typedPointer = RelativeVariable(thing.name + ".pointer", f.toAddress, InterruptPointerType, zeropage = false, None, isVolatile = false)
addThing(typedPointer, position)
addThing(RelativeVariable(thing.name + ".pointer.hi", f.toAddress + 1, b, zeropage = false, None, isVolatile = false), position)
addThing(RelativeVariable(thing.name + ".pointer.lo", f.toAddress, b, zeropage = false, None, isVolatile = false), position)
case _ =>
}
} else {
@ -1460,7 +1473,6 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
addThing(ConstantThing(thing.name + ".rawaddr.lo", addr.loByte, b), position)
targetType.foreach { tt =>
val pointerType = PointerType("pointer." + tt.name, tt.name, Some(tt))
val typedPointer = RelativeVariable(thing.name + ".pointer", addr, pointerType, zeropage = false, None, isVolatile = false)
addThing(ConstantThing(thing.name + ".pointer", addr, pointerType), position)
addThing(ConstantThing(thing.name + ".pointer.hi", addr.hiByte, b), position)
addThing(ConstantThing(thing.name + ".pointer.lo", addr.loByte, b), position)
@ -1476,6 +1488,10 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
addThing(ConstantThing(thing.name + ".pointer", actualAddr, pointerType), position)
addThing(ConstantThing(thing.name + ".pointer.hi", actualAddr.hiByte, b), position)
addThing(ConstantThing(thing.name + ".pointer.lo", actualAddr.loByte, b), position)
case f: FunctionInMemory if f.interrupt =>
addThing(ConstantThing(thing.name + ".pointer", f.toAddress, InterruptPointerType), position)
addThing(ConstantThing(thing.name + ".pointer.hi", f.toAddress.hiByte, b), position)
addThing(ConstantThing(thing.name + ".pointer.lo", f.toAddress.loByte, b), position)
case _ =>
}
}
@ -2132,7 +2148,7 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
}
case _ => Nil
}
case _: PointerType => if (options.isBigEndian) List(
case InterruptPointerType | _: FunctionPointerType | _: PointerType => if (options.isBigEndian) List(
Subvariable(".raw", 0, get[VariableType]("pointer")),
Subvariable(".raw.lo", 1, b),
Subvariable(".raw.hi", 0, b),

View File

@ -119,6 +119,38 @@ case class FunctionPointerType(name: String, paramTypeName:String, returnTypeNam
override def alignment: MemoryAlignment = NoAlignment
}
case object KernalInterruptPointerType extends VariableType {
def size = 2
override def isSigned: Boolean = false
override def isPointy: Boolean = false
override def alignment: MemoryAlignment = NoAlignment
override def name: String = "pointer.kernal_interrupt"
override def isCompatible(other: Type): Boolean = other match {
case KernalInterruptPointerType => true
case FunctionPointerType(_, "void", "void", _, _) => true
case _ => false
}
}
case object InterruptPointerType extends VariableType {
def size = 2
override def isSigned: Boolean = false
override def isPointy: Boolean = false
override def alignment: MemoryAlignment = NoAlignment
override def name: String = "pointer.interrupt"
override def isCompatible(other: Type): Boolean = other == InterruptPointerType
}
case object NullType extends VariableType {
override def size: Int = 2

View File

@ -122,4 +122,26 @@ class FunctionPointerSuite extends FunSuite with Matchers with AppendedClues{
}
}
test("Interrupt pointers") {
EmuUnoptimizedCrossPlatformRun (Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
"""
| pointer.interrupt i @$c000
| pointer.kernal_interrupt k @$c002
| function.void.to.void f @$c004
| interrupt void i1() @$400 {}
| kernal_interrupt void k1() @$500 {}
| void main() {
| i = i1.pointer
| k = k1.pointer
| f = k1.pointer
| call(k)
| }
|
""".stripMargin) { m =>
m.readWord(0xc000) should equal(0x400)
m.readWord(0xc002) should equal(0x500)
m.readWord(0xc004) should equal(0x500)
}
}
}

View File

@ -1,7 +1,7 @@
package millfork.test
import millfork.Cpu
import millfork.test.emu.{EmuBenchmarkRun, EmuCrossPlatformBenchmarkRun}
import millfork.test.emu.{EmuBenchmarkRun, EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun, ShouldNotCompile}
import org.scalatest.{FunSuite, Matchers}
/**
@ -25,4 +25,55 @@ class TypeSuite extends FunSuite with Matchers {
| }
""".stripMargin)(_.readWord(0xc000) should equal(0x203))
}
test("Function pointer conversions") {
EmuUnoptimizedCrossPlatformRun(Cpu.Mos, Cpu.Z80)("""
| volatile pointer.kernal_interrupt k
| volatile function.void.to.void f
|
| void main () {
| f = k
| }
""".stripMargin){_ => }
ShouldNotCompile("""
| volatile pointer.kernal_interrupt k
| volatile function.void.to.void f
|
| void main () {
| k = f
| }
""".stripMargin)
ShouldNotCompile("""
| volatile pointer.interrupt i
| volatile function.void.to.void f
|
| void main () {
| i = f
| }
""".stripMargin)
ShouldNotCompile("""
| volatile pointer.interrupt i
| volatile function.void.to.void f
|
| void main () {
| f = i
| }
""".stripMargin)
ShouldNotCompile("""
| volatile pointer.interrupt i
| volatile pointer.kernal_interrupt k
|
| void main () {
| i = k
| }
""".stripMargin)
ShouldNotCompile("""
| volatile pointer.interrupt i
| volatile pointer.kernal_interrupt k
|
| void main () {
| k = i
| }
""".stripMargin)
}
}