t-edson / P65Pas

CPU 6502 Pascal Compiler/IDE/Debugger
GNU General Public License v3.0
119 stars 27 forks source link

[example] interrupts #33

Closed mvdhoning closed 5 months ago

mvdhoning commented 3 years ago
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?.

mvdhoning commented 3 years ago

https://wiki.freepascal.org/Inline

t-edson commented 3 years ago

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.

Squall-FF8 commented 3 years ago

I had same issue, so here what I did: {$DEFINE SEI=asm SEI end}

after that to use it in p65: {$SEI}

Squall-FF8 commented 3 years ago

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!!!

mvdhoning commented 3 years ago

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;?

Squall-FF8 commented 3 years ago

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.

mvdhoning commented 3 years ago

JMP (IRQ_Kernel) does not want to compile?

Squall-FF8 commented 3 years ago

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.

mvdhoning commented 3 years ago

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.

Squall-FF8 commented 3 years ago

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.

mvdhoning commented 5 months ago

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.
mvdhoning commented 5 months ago

redownloaded 1.01 version (somehow i must have downloaded the 1.0 verson and now

 irqVector := @myirqexample;

works.

t-edson commented 5 months ago

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.