1
0
mirror of https://github.com/KarolS/millfork.git synced 2025-07-06 01:23:51 +00:00

Fix function pointers (fixes #86)

This commit is contained in:
Karol Stasiak
2020-11-18 09:34:02 +01:00
parent fc7643c416
commit 385b2fd40b
3 changed files with 40 additions and 5 deletions

View File

@ -39,7 +39,7 @@ Examples:
You are not allowed to call such functions directly. You are not allowed to call such functions directly.
The function cannot have parameters and the return type should be `void`. The function cannot have parameters and the return type should be `void`.
* `kernal_interrupt` the function is an interrupt handler called from a generic vendor-provider hardware interrupt handler. * `kernal_interrupt` the function is an interrupt handler called from a generic vendor-provided hardware interrupt handler.
The hardware instruction handler is assumed to have preserved the CPU registers, The hardware instruction handler is assumed to have preserved the CPU registers,
so this function only has to preserve the zeropage pseudoregisters. so this function only has to preserve the zeropage pseudoregisters.
An example is the Commodore 64 interrupt handler that calls the function at an address read from $314/$315. An example is the Commodore 64 interrupt handler that calls the function at an address read from $314/$315.
@ -85,9 +85,12 @@ and return `void` or a value of size max 2 bytes,
can be accessed via a pointer. can be accessed via a pointer.
void f() {} void f() {}
void g(byte x) {}
function.void.to.void p = f.pointer function.void.to.void p = f.pointer
function.byte.to.void p = g.pointer
call(p) call(p)
call(p, 13)
The value of the pointer `f.pointer` may not be the same as the value of the function address `f.addr`. The value of the pointer `f.pointer` may not be the same as the value of the function address `f.addr`.

View File

@ -2211,9 +2211,15 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
return None return None
} }
val function = thing.asInstanceOf[MangledFunction] val function = thing.asInstanceOf[MangledFunction]
if (function.params.length != actualParams.length) { if (function.name == "call") {
if (actualParams.isEmpty || actualParams.length > 2) {
log.error("Invalid number of parameters for function `call`", actualParams.headOption.flatMap(_._2.position))
}
} else {
if (function.params.length != actualParams.length && function.name != "call") {
log.error(s"Invalid number of parameters for function `$name`", actualParams.headOption.flatMap(_._2.position)) log.error(s"Invalid number of parameters for function `$name`", actualParams.headOption.flatMap(_._2.position))
} }
}
if (name == "call") return Some(function) if (name == "call") return Some(function)
function.params match { function.params match {
case NormalParamSignature(params) => case NormalParamSignature(params) =>

View File

@ -1,7 +1,7 @@
package millfork.test package millfork.test
import millfork.Cpu import millfork.Cpu
import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun, ShouldNotCompile} import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuSizeOptimizedCrossPlatformRun, EmuUnoptimizedCrossPlatformRun, ShouldNotCompile}
import org.scalatest.{AppendedClues, FunSuite, Matchers} import org.scalatest.{AppendedClues, FunSuite, Matchers}
/** /**
@ -30,7 +30,7 @@ class FunctionPointerSuite extends FunSuite with Matchers with AppendedClues{
} }
test("Function pointers 2") { test("Function pointers 2") {
EmuUnoptimizedCrossPlatformRun (Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Motorola6809)( EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Cmos, Cpu.Z80, Cpu.Intel8080, Cpu.Sharp, Cpu.Motorola6809)(
""" """
| const byte COUNT = 128 | const byte COUNT = 128
| array output0[COUNT] @$c000 | array output0[COUNT] @$c000
@ -100,7 +100,7 @@ class FunctionPointerSuite extends FunSuite with Matchers with AppendedClues{
} }
test("Function pointers 3") { test("Function pointers 3") {
EmuUnoptimizedCrossPlatformRun (Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)( EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
""" """
| const byte COUNT = 128 | const byte COUNT = 128
| array(word) output0[COUNT] @$c000 | array(word) output0[COUNT] @$c000
@ -122,6 +122,32 @@ class FunctionPointerSuite extends FunSuite with Matchers with AppendedClues{
} }
} }
test("Function pointers 4") {
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
"""
| const byte COUNT = 128
| array(byte) output0[COUNT] @$c000
| noinline void fill(function.byte.to.byte f) {
| byte i
| for i,0,until,COUNT {
| call(f, i)
| }
| }
| byte iota_at(byte x) {
| output0[x] = x
| return x
| }
| void main() {
| fill(iota_at.pointer)
| }
|
""".stripMargin) { m =>
for (i <- 0 until 0x80) {
m.readByte(0xc000 + i) should equal(i) withClue ("id " + i)
}
}
}
test("Interrupt pointers") { test("Interrupt pointers") {
EmuUnoptimizedCrossPlatformRun (Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)( EmuUnoptimizedCrossPlatformRun (Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
""" """