1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-06-09 16:29:34 +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.
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,
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.
@ -85,9 +85,12 @@ and return `void` or a value of size max 2 bytes,
can be accessed via a pointer.
void f() {}
void g(byte x) {}
function.void.to.void p = f.pointer
function.byte.to.void p = g.pointer
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`.

View File

@ -2211,9 +2211,15 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa
return None
}
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))
}
}
if (name == "call") return Some(function)
function.params match {
case NormalParamSignature(params) =>

View File

@ -1,7 +1,7 @@
package millfork.test
import millfork.Cpu
import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuUnoptimizedCrossPlatformRun, ShouldNotCompile}
import millfork.test.emu.{EmuCrossPlatformBenchmarkRun, EmuSizeOptimizedCrossPlatformRun, EmuUnoptimizedCrossPlatformRun, ShouldNotCompile}
import org.scalatest.{AppendedClues, FunSuite, Matchers}
/**
@ -30,7 +30,7 @@ class FunctionPointerSuite extends FunSuite with Matchers with AppendedClues{
}
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
| array output0[COUNT] @$c000
@ -100,7 +100,7 @@ class FunctionPointerSuite extends FunSuite with Matchers with AppendedClues{
}
test("Function pointers 3") {
EmuUnoptimizedCrossPlatformRun (Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
EmuCrossPlatformBenchmarkRun(Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
"""
| const byte COUNT = 128
| 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") {
EmuUnoptimizedCrossPlatformRun (Cpu.Mos, Cpu.Z80, Cpu.Motorola6809)(
"""