[example] interrupts
program HelloInterrupt;
uses
Commodore64;
var
IRGVEC: pointer absolute $0314;
SCREENPOS1: byte absolute $0400;
procedure disableInterrupts; {Macro?}
begin
asm
sei ; disable interrupts
end
end;
procedure enableInterrupts; {Macro?}
begin
asm
cli ; enable interrupts
end
end;
(* Calling jmp from inside a procedure call borks out
procedure callDefaultInterrupt; {Macro?}
begin
asm
jmp $EA31 ; jump into KERNAL's standard interrupt service routine to handle keyboard scan, cursor display etc.
end
end;
*)
procedure myirqexample;
begin
SCREENPOS1 := SCREENPOS1 + 1;
asm
jmp $EA31 ; jump into KERNAL's standard interrupt service routine to handle keyboard scan, cursor display etc.
end
end;
procedure init;
begin
disableInterrupts;
IRGVEC := addr(myirqexample);
enableInterrupts;
end;
begin
init;
asm
rts ; is not auto generated for main?
end
end.
some observations on making the above:
Enabling en disabling intterupts require a asm call. As now it works but feels like there might be a need for some kind of macro procedure or a future compiler optimisation level that abstract away some jsr calls that only do one line of stuf.
Putting the jmp to the default irq inside a procedure makes the c64 bork out.
Also i believed that at end. also an rts was generated but not always?.
https://wiki.freepascal.org/Inline
Hi. Inline procedures are projected to be implemented. But I'm not doing changes in the current version, because I'm preparing the new version with drastic changes in the core of the compiler. It's just I just work in free time in my open source projects.
I had same issue, so here what I did:
{$DEFINE SEI=asm SEI end}
after that to use it in p65:
{$SEI}
I will share my IRQ unit, because it might help you. IRQ_Kernel stores old interrupt vector. IRQ_Flag notify my main loop that a VSYNC has occurred and some internals needs update on timer (60 fps).
unit IRQ;
interface
const
VSYNC = $01;
var
IRQ : word absolute $314;
IRQ_Flag : byte absolute $30;
IRQ_Kernel : word;
procedure InitIRQ(Flags: byte registerA);
procedure RestoreIRQ;
implementation
procedure IRQ_Handler;
begin
asm
LDA #VSYNC
STA vIRQ
STA IRQ_Flag
JMP (IRQ_Kernel)
;RTI
end
end;
procedure InitIRQ(Flags: byte registerA);
begin
{$SEI}
vIrqCtrl := Flags;
IRQ_Flag := 0;
IRQ_Kernel := IRQ;
IRQ := addr(IRQ_Handler);
{$CLI}
end;
procedure RestoreIRQ;
begin
IRQ := IRQ_Kernel;
end;
end.
PS Why my code is not formatted as code ... is there a way to show it with syntax highlight? EDIT: now it works as intended, thank you very much!!!
do 3 backticks followed by the word delphi on the next lines your code and close it with 3 backticks
program hello;
begin
writeln('hi');
end.
what is vIrqCtrl := Flags;?
Thank you very much for the tip!!!
Sorry you don't need that line. I'm programming for a new system that hasn't been realized, but is close to c64 called Commander x16. As you can see even the interrupt vector is the same. vIrqCtrl register holds a bit field that determinate which events will trigger IRQ.
JMP (IRQ_Kernel) does not want to compile?
That is very strange, here is my compiled output:
__IRQ_Handler:
;LDA #VSYNC
$08E5 A9 01 LDA #$01
;STA vIRQ
$08E7 8D 27 9F STA vIRQ
;STA IRQ_Flag
$08EA 85 30 STA IRQ_Flag
;JMP (IRQ_Kernel)
$08EC 6C 1A 08 JMP $(081A)
;end;
$08EF 60 RTS
There is a bug that you can't use more them one JSR/JMP in one asm block.
I get a libIrq[28,21] Error: Syntax error: "" Line 28 is JMP (IRQ_Kernel) JMP does not seem to allow () in version 0.7.8 for me. my libIrq is yours only with the 2 defines added on top for SEI and CLI.
That is very sad. My build is custom - I had some issues fixed before official release. On top of that I added 65c02 opcodes for X16. But JMP (...) is 6502 instruction.
In P6502utils there should be:
aIndirect, //Indirect : JMP ($1000)
...
PIC16InstName[i_JMP].name := 'JMP'; //Jump to New Location
PIC16InstName[i_JMP].AddAddressMode(aAbsolute,$4C,3,3,'');
PIC16InstName[i_JMP].AddAddressMode(aIndirect,$6C,3,5,'');
The last line should give you indirect JMP. But if doesn't work report it as a bug.
in 1.1 addr(procedurename) can no longer find the procedure by name and error on variable not found workaround is using assembly also i do like the new optimizing compiler leaving out not used procedures :-) BUT is there a way to leave in certain procedure that are not called directly from code?
program HelloInterrupt;
uses
Commodore64;
//Interrupt Macro Defines
{$DEFINE disableInterrupts=asm SEI end;}
{$DEFINE enableInterrupts=asm CLI end;}
{$DEFINE callDefaultInterrupt=asm JMP $EA31 end;}
const
VSYNC = $01;
var
irqVector: pointer absolute $0314;
irqFlag : byte absolute $30;
screenPos1: byte absolute $0400;
procedure myirqexample;
begin
irqFlag:=VSYNC;
screenPos1 := screenPos1 + 1; //compiles to INC screenPos1
{$callDefaultInterrupt}
end;
procedure init;
begin
{$disableInterrupts}
irqFlag := 0;
//irqVector := addr(myirqexample); //Does not work anymore as it is not a variable
//irqVector := $080D; //Bad HACK as adres of procedure might change
//irqVector := @myirqexample; //Acces Violation in the IDE
asm
lda #<myirqexample
sta irqVector
lda #>myirqexample
sta irqVector+$1
end; // assembly can still find the procedure by name
{$enableInterrupts}
end;
begin
init;
asm
rts ; is not auto generated for main?
end;
myirqexample; //needs to be called or it will not be compiled anymore
end.
redownloaded 1.01 version (somehow i must have downloaded the 1.0 verson and now
irqVector := @myirqexample;
works.
also i do like the new optimizing compiler leaving out not used procedures :-) BUT is there a way to leave in certain procedure that are not called directly from code?
It should be like a VOLATILE procedure. Not currently implemented but I will put in my TODO list.