Page 1 of 3

Keyboard

Posted: Sun May 16, 2021 2:26 pm
by CursorKeys

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

 


Keyboard

Posted: Sun May 16, 2021 3:29 pm
by SlithyMatt

You need to enable the VSYNC IRQ, too. Enabling only the LINE IRQ messes up the kernal, which is expecting that VSYNC 60 times a second to keep it regular. It should only be disabled for short periods where you need to maximize CPU usage on some task, and don't care about I/O until it's done.


Keyboard

Posted: Sun May 16, 2021 3:33 pm
by Elektron72


1 hour ago, CursorKeys said:




How does the keyboard normally work?



1- Is there an interupt when a key is pressed?



A number of system functions (keyboard, mouse, and controller scanning, updating the jiffy clock, and blinking the cursor) are performed by the kernal IRQ handler every time the VSYNC interrupt occurs. I believe the best way to restore these functions would be to enable both VSYNC and LINE interrupts, and to check which interrupt occurred in your code. If it was a VSYNC interrupt, jump to the original IRQ handler. If not, execute the line interrupt code.


1 hour ago, CursorKeys said:




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



Currently, most of the things that the X16 inherited from the C64 (BASIC commands, kernal routines, vectors) are completely undocumented.


Keyboard

Posted: Sun May 16, 2021 3:55 pm
by CursorKeys


20 minutes ago, Elektron72 said:




I believe the best way to restore these functions would be to enable both VSYNC and LINE interrupts,



......and to check which interrupt occurred in your code. If it was a VSYNC interrupt, jump to the original IRQ handler. If not, execute the line interrupt code.



 





Thanks for pointing me in the right direction. But how do you check the cause of the interupt?  Is it in the acumulator, or how else is it passed to the interupt routine?



(I haven't done interupts in much detail before)


Keyboard

Posted: Sun May 16, 2021 4:27 pm
by SlithyMatt

You need to read the VERA ISR register.

I have a video about the basics of interrupts here:





Then I have a video on how to manage LINE and VSYNC interrupts here: 





 


Keyboard

Posted: Mon May 24, 2021 9:14 am
by CursorKeys

It took me a bit of time to find a free timeslot to look at, but I managed to "sort of" make it work, Thanks to SlithyMatt excelent videos, and Elektron72

 

Below is my code.

So what works is that I have two interupts, VSYNC and LINE.  Line I like to have so I can figure out where on the screen I am, and when I want to scroll. VSYNC, I like to have for timing.

The code below does 3 things. 

-Update left top character 1, each time you press space.

-Updater left to character 2, each time the main loop detects the line interrupt is executed

-Updater left to character 3, each time the main loop loops

 

It works. Sort of.

It only works, if I make my variables "volatile" inside the main loop.

This to me indicates that there is something ongoing with the registers each time the interrupt runs, that breaks the code in the main loop.   I have tried with only VSYNC interrupt and there is no issue then.

From SlithyMatts code examples, I took as and example the code

{

        ply

        plx

        pla

        rti

}

To end the line interrupt nicely.  Some how it not working.

Any ideas?

 


Quote




// Example program for the Commander X16

// Displays raster bars in the border



#pragma target(cx16)

#include <cx16.h>

#include <6502.h>

#include <string.h>

#include <stdlib.h>

#include <conio.h>

#include <veralib.h>





volatile char vbcounter=0;

volatile void *default_irq_vector;



__interrupt void myInterupt() {



  unsigned char intbits = *VERA_ISR;



  if( intbits & VERA_LINE ) {



    vbcounter++;



    *VERA_ISR = VERA_LINE | VERA_VSYNC;

    *VERA_IEN = VERA_LINE | VERA_VSYNC;

    asm {



        ply

        plx

        pla

        rti

    }



  }



  if( intbits & VERA_VSYNC ) {

    *VERA_ISR = VERA_LINE | VERA_VSYNC;

    *VERA_IEN = VERA_LINE | VERA_VSYNC;



    asm {



        jmp (default_irq_vector)

    }

  }



  *VERA_IEN = VERA_LINE | VERA_VSYNC;

  *VERA_IRQLINE_L = 100;



}





void initMain() {



  volatile unsigned char ll = 0, mm=0;



  SEI();

  default_irq_vector = *KERNEL_IRQ;

  *KERNEL_IRQ = &myInterupt;

  *VERA_IEN = VERA_LINE | VERA_VSYNC;

  *VERA_IRQLINE_L = 4;

  CLI();



  vpoke( 0,0, 0 ); //set an "@" left top screen

  vpoke( 0,1, 0x12 ); //set an "@" left top screen



  char c=0;

  while(1==1) {



    unsigned char c = kbhit();

    if( c== 32 ) {



      vpoke( 0,0, ++mm ); //set an "@" left top screen

      vpoke( 0,0+1, 0x12 ); //set an "@" left top screen



    }



    vpoke( 0,2, vbcounter ); //set an "@" left top screen

    vpoke( 0,3, 0x12 ); //set an "@" left top screen



    vpoke( 0,4, ll++ ); //set an "@" left top screen

    vpoke( 0,5, 0x12 ); //set an "@" left top screen



  }





}



 





void main() {



    initMain();



}



 



And the interupt code in assembly.

 


Quote




    lda VERA_ISR

    sta.z intbits



//line checking and handling



    lda #VERA_LINE

    and.z intbits

    cmp #0

    beq __b1

    inc.z vbcounter

    lda #VERA_LINE|VERA_VSYNC

    sta VERA_ISR

    sta VERA_IEN

    ply

    plx

    pla

    rti

  __b1:



//vsynch checking and handling



    lda #VERA_VSYNC

    and.z intbits

    cmp #0

    beq __b2

    lda #VERA_LINE|VERA_VSYNC

    sta VERA_ISR

    sta VERA_IEN

    jmp (default_irq_vector)



//other (is there other to deal with?)



  __b2:

    lda #VERA_LINE|VERA_VSYNC

    sta VERA_IEN

    lda #$64

    sta VERA_IRQLINE_L

    jmp $e049

 



 


Keyboard

Posted: Mon May 24, 2021 1:38 pm
by SlithyMatt

What's the JMP $E049 for at the end? You should jump to (default_irq_vector) unless you are going to do the early exit. 


Keyboard

Posted: Mon May 24, 2021 2:16 pm
by CursorKeys

Thanks. I think it was auto generated code.

So I added the jump, and it looks like this on the generated assembly now.

But no change. It works fine, when I have the variables as volatile (store them in memory instead of loaded in registers), but when I remove the volatile keyword, it stops  working.  

Or a more exact description is, main loop indicator and the keyboard loop indicator on the screen stop cycling, but the behavior is erratic, when I print a number on the screen in the main loop, suddenly there is no issues in the main loop anymore.

 


Quote




.label intbits = 7



    lda VERA_ISR

    sta.z intbits



//line



    lda #VERA_LINE

    and.z intbits

    cmp #0

    beq __b1

    inc.z vbcounter

    lda #VERA_LINE|VERA_VSYNC

    sta VERA_ISR

    sta VERA_IEN

    ply

    plx

    pla

    rti



//vsync





  __b1:

    lda #VERA_VSYNC

    and.z intbits

    cmp #0

    beq __b2

    lda #VERA_LINE|VERA_VSYNC

    sta VERA_ISR

    sta VERA_IEN

    jmp (default_irq_vector)



//other



  __b2:

    lda #VERA_LINE|VERA_VSYNC

    sta VERA_IEN

    lda #$64

    sta VERA_IRQLINE_L

    jmp (default_irq_vector)



 

 


Keyboard

Posted: Mon May 24, 2021 2:26 pm
by SlithyMatt


7 minutes ago, CursorKeys said:




main loop indicator and the keyboard loop indicator on the screen stop cycling



Those are both indications that the default IRQ handler isn't running. Seems like it would be easier to have your whole interrupt handling code in assembly, then you could have C functions that you jump to for certain cases.


Keyboard

Posted: Mon May 24, 2021 2:48 pm
by CursorKeys


20 minutes ago, SlithyMatt said:




Those are both indications that the default IRQ handler isn't running. Seems like it would be easier to have your whole interrupt handling code in assembly, then you could have C functions that you jump to for certain cases.



Maybe, but how would it explain, that the key-counter works fine on first key-press, and then stops working.  And works fine when it is ensured that the keycounter is in a volatile variable?