mirror of
https://github.com/KarolS/millfork.git
synced 2025-07-06 16:24:00 +00:00
Fix function pointers (fixes #86)
This commit is contained in:
@ -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`.
|
||||||
|
@ -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) =>
|
||||||
|
@ -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)(
|
||||||
"""
|
"""
|
||||||
|
Reference in New Issue
Block a user