Jump to content
  • 0

CursorKeys
 Share

Question

Posted (edited)

Hi!
 

I have been playing with interupts a little, in kickc, and it all works nice.  But now I tried to incooperate it in a game I hit a snag.

It seems when I setup an interupt, for scanline, my keyboard functions stop working.

I am probably doing something really basic wrong.
The weird thing is also, when I restore the interupt to it's previous state, the keyboard is still not working.

ps. the keyboard routing I am using is kickc "kbhit", which seems to call kernal routine "GETIN" at $FFE4, I also tried directly calling kernal routines, which works fine, but not when my interupt is enabled.
ps2. I enable the interupt, something like this.

 

Quote

__interrupt void irq_line() {

  //do stuff

}

void main() {
   //kbhit function works fine here

  //store old interupt values
    old_irq = *KERNEL_IRQ;
    old_ien = *VERA_IEN;

  SEI();
  *KERNEL_IRQ = &irq_line;
  *VERA_IEN = VERA_LINE;
  *VERA_IRQLINE_L = 4;
  CLI();


   //kbhit function stopped working


  //try to restore the interupt
   SEI();
  *KERNEL_IRQ = old_irq;
  *VERA_IEN = old_ien;
  CLI();

  //kbhit function is not restored. 

}

 

What I am asking is.

How does the keyboard normally work?

1- Is there an interupt when a key is pressed?  Why does that interup stop working when I set my scanline interupt. How are they related? Do I need to do some extra "magic" at the end of my scanline interupt, to keep the key handling interupt working?

2- Can you somehow check the keyboard in a loop, without interupt, by polling a memory address or maybe a vram address, and if so which one?

 

Also anyone could point me to the correct sections in the documentation, I will be thankfull!

The most accurate I have found an answer is the section in the manual called "'Custom keyboard scan code handler".  But I somehow  don't get the full picture.

Thanks
CC

 

Edited by CursorKeys
Link to comment
Share on other sites

Recommended Posts

  • 0
On 5/27/2021 at 11:07 AM, Greg King said:

....

Note that the __interrupt qualifier makes this function return by jumping to R38 Kernal's $E049, which pulls the registers and does RTI.

I am using KickC, not cc65  is it the same there?

Link to comment
Share on other sites

  • 0
10 hours ago, CursorKeys said:

I am using KickC, not cc65.  Is it the same there?

No.  cc65's interrupt handling is much less efficient.  It goes solely through the interrupt vector "daisy chain".  Several independent handlers can be connected at the same time (if a handler is linked into a program, then it's connected automatically).  Therefore, there's an extra layer that runs each handler, in turn.

If you want to run C code in a handler, then another layer must be used to save and restore all of the housekeeping data that the compiler's runtime needs.

Normal interrupt handling is slow -- not suitable for some video effects!  If you want to stuff a lot of data into video RAM during the vertical blanking period, then your code must start as soon as possible, and run as fast as possible.  Your program would need to intercept the interrupts manually.  The handler should be written in Assembly code.

Link to comment
Share on other sites

  • 0
On 5/27/2021 at 5:07 AM, Greg King said:

He's right.  I had assumed that Kernal checks for the vertical sync interrupt -- but, it doesn't!!  Therefore, our programs are forced to do it.  Your handler must have some additional code.


__interrupt void myInterrupt(void)
{
  if (*VERA_ISR & VERA_LINE) {
    vbcounter++;
    *VERA_IRQLINE_L = 100;

    *VERA_ISR = VERA_LINE;
  } else if (*VERA_ISR & VERA_VSYNC) {
    asm {
      jmp (default_irq_vector)
    }
  }
  // Other interrupts are ignored.
}

Note that the __interrupt qualifier makes this function return by jumping to R38 Kernal's $E049, which pulls the registers and does RTI.

That comment is about KickC.  As I wrote earlier, cc65 works very differently.

  • Thanks 1
Link to comment
Share on other sites

  • 0

Here's how I did IRQ handling in Flappy Bird:
(written in cc65)

The "magic" item here is that I just use the fact that C-space identifiers are available in "ASM-space" as _identifiers.

The void irq(void) function is the game's IRQ handler. The game first copies the default vector from 0x314 into SystemIRQ, then writes the address of irq() into 0x314.

irq() ends by using asm() to jmp into the kernal's IRQ routines after the game's functions are done. note that the command is jmp (_SystemIRQ) - the parens are an indirect jump, which wasn't available on MOS 6502 but works on 65c02, so it's just a one-liner.

Quote

 

#define IRQVECTOR    0x0314
#define IRQvector    (*(uint16_t*)IRQVECTOR)

// global variable:
static uint16_t SystemIRQ;

void irq(void)
{
    //
    // do stuff here
    //
    
    // call system IRQ handler when done with your stuff
    SETROMBANK = 0;
    asm("jmp (_SystemIRQ)");
}

// somewhere in your program's initialization:

// install the IRQ handler
SystemIRQ = IRQvector;
asm("sei");
IRQvector = (uint16_t)&irq;
asm("cli");

 

P.s. : sorry, I am not sure how to get the syntax highlighting to work on the forum....

Edited by ZeroByte
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

Please review our Terms of Use