Jump to content
IGNORED

(Simple) keyboard reading in assembly


slx

Recommended Posts

I am trying to read the keyboard in order to implement a pause routine in a patched version of Shamus. I read all I could find about SKSTAT and KBCODE but it doesn't really work as expected.

 

I do not use system VBI routines.

 

I tried to load SKSTAT during VBI, AND $04 and act on the results of that, i.e. interpreting anything not zero as a keypress. I then check for a specific KBCODE (Space) to enter the pause routine. After a little delay I check for SKSTAT and KBCODE again to end the pause when it is pressed again. That works as well but the game only stays "unpaused" when I keep the space bar pressed. then SKSTAT seems to remain "latched" as the game will end the pause but jump right back unless that key is held.

 

My understanding is that SKSTAT bit 2 should revert to zero if no key is depressed. In reality it seems to remain set (always?) and as KBCODE does not change when a key is released the next VBI jumps right back into the pause routine.

 

My code is below. Any ideas what I did wrong?

 

(The "PAUSECTR" and countdown from 4 in the PAUSING routine were intended to make sure the key is really depressed for a little while. The behaviour of the routine doesn't change when I leave them out, so I assume I am doing something wrong with SKSTAT.)

 

 

XITVBV		equ $E462
NMIEN		equ $D40E
DLISTL		equ $D402
DLISTH		equ $D403
KBCODE		equ $D209
SKSTAT		equ $D20F
SKCTL		equ SKSTAT
AUDF1		equ $D200
HITCLR		equ $D01E


CHECKKEYS	LDA SKSTAT                ;this is where VVBLKI points
			AND #$04
			BEQ EXIT
			LDA KBCODE
			CMP #$21
			BNE EXIT0
			INC PAUSECTR
			LDA PAUSECTR
			CMP #$04
			BNE EXIT2
	
PAUSE		LDA #$00
			STA NMIEN        ;no more VBIs while pausing
			STA PAUSECTR
			LDA <PAUSEDLIST  ;change to dedicated display list
			STA DLISTL
			LDA >PAUSEDLIST
			STA DLISTH
			LDA #$00
			LDY #$03
KILLAUDIO	STA AUDF1,Y
			DEY
			BPL KILLAUDIO
			
PAUSING		LDX #$04
KEYPRESSED	LDA SKSTAT
			AND #$04
			BNE PAUSING
			LDA KBCODE
			CMP #$21
			BNE PAUSING
			DEX
			BEQ ENDPAUSE
			BNE KEYPRESSED
 
ENDPAUSE	LDA #$B8
			STA DLISTL
			LDA #$35
			STA DLISTH
			LDA #$C0
			STA NMIEN
			STA HITCLR
EXIT0		LDA #$00
EXIT		STA PAUSECTR
EXIT2		JMP XITVBV

PAUSECTR		.BY $00
Link to comment
Share on other sites

probably not much help but on my games I only use CH ($02FC = Last Key Pressed)

if it's 21 (space) I pause and set CH to 255 (clear the key)

then I test for it not being 255

then I exit pause and set it back to 255

 

:)

 

That's what I was used to from BASIC and Action! but I think those only work when using system VBLANK which Shamus doesn't (and it would write all over the game code if I'd enable it).

Link to comment
Share on other sites

I tried changing this from VBI based to keyboard interrupt based code but still face the same problem.

CHECKKEYS	PHA
			TXA
			PHA
			TYA
			PHA
			LDA #$00
			STA NMIEN
			STA IRQEN
			LDA <PAUSEDLIST
			STA DLISTL
			LDA >PAUSEDLIST
			STA DLISTH
			LDA #$00
			LDY #$03
KILLAUDIO	STA AUDF1,Y
			DEY
			BPL KILLAUDIO
			
PAUSING		LDA TRIG0
			BNE PAUSING
 
ENDPAUSE	LDA #$B8
			STA DLISTL
			LDA #$35
			STA DLISTH
			LDA #$C0
			STA NMIEN
			STA HITCLR
			LDA #$40
			STA IRQEN
			LDX #$05
			JSR WAIT1
EXIT		;
			
			PLA
			TAY
			PLA
			TAX
			PLA
			CLI
			RTI

While I can enter the pause routine and exit it using the fire button, the interrupt will fire again immediately.

 

Is there anything else I need to do to reset the keyboard interrupt?

 

As no other IRQs are required I run this directly through VIMIRQ at $217/8, not through VKEYBD.

Edited by slx
Link to comment
Share on other sites

I'd get rid of the CLI before RTI - the RTI pulls P off the stack so it's not needed.

 

By storing 00 in IRQEN that clears the keyboard IRQ. It could be the case that you're suffering a debounce IRQ, though I think that while the key IRQ is disabled they shouldn't be able to become pending (need to read Altirra HW reference to clarify there).

 

The other precaution for your coding - not a good idea to store into the DLIST address pointers direct in Antic just any old time. On real hardware you'd probably get occasional glitches. In emulation I think the KB IRQ will always occur at the same place (?) so such things mightn't become apparent.

Link to comment
Share on other sites

I'd get rid of the CLI before RTI - the RTI pulls P off the stack so it's not needed.

Thanks, didn't think of that.

 

By storing 00 in IRQEN that clears the keyboard IRQ. It could be the case that you're suffering a debounce IRQ, though I think that while the key IRQ is disabled they shouldn't be able to become pending (need to read Altirra HW reference to clarify there).

I do store $00 to IRQEN (line 17 above) but nevertheless the IRQ keeps firing again a bit after the reset and RTI. Not tested on real hardware yet. (Or did you mean that the $40 to IRQEN is a problem - I would not know how to re-enable keyboard IRQs otherwise, however?)

 

The other precaution for your coding - not a good idea to store into the DLIST address pointers direct in Antic just any old time. On real hardware you'd probably get occasional glitches. In emulation I think the KB IRQ will always occur at the same place (?) so such things mightn't become apparent.

I do that because system VBI routines are not in use and IIRC I would need those not to write to ANTIC directly. Is there an inherent problem to writing to ANTIC or just the risk of writing only half the address and be interrupted by a VBI? As I understand the system this would cause a corrupted display, i.e. some flicker when restoring from the pause screen to the game screen for one frame which seems tolerable.
Link to comment
Share on other sites

Just writing the DList address to Antic anytime has potential for screen corruption or unwanted behaviour.

 

Think the case of 3 x 8 blank lines then 24 text/coloured mode as many games use.

Write the DList address when it's halfway down the screen - Antic will process the blank lines then you'll get part of the window displayed for the remainder of the frame.

The Jump + wait for VBlank won't be processed. Without VBlank storing the shadow register the DList will continue to run into the next frame.

So next frame you'll get second half of the window shown right at the top of the active display. JVB will be read and you'll get a large blank portion for the remainder of frame.

 

Then next frame, things back to normal.

At best you get that sort of glitch. At worst unwanted program behaviour or even a crash if there's DLIs active and they go out of sequence or some are missed.

Also, PM graphics won't be affected but will be out of place relative to the playfield. Potential for unwanted collisions.

 

Best practice with storing that DList pointer for pause/resume would be to wait on VCOUNT <4 or >128.

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.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   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.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...