Jump to content
IGNORED

Writing to VDP in user ISR


ralphb

Recommended Posts

I've been playing around with user ISRs, and I'm somewhat puzzled by the result of this program:

.

main:
       lwpi ws
       li   r0, handler
       mov  r0, @>83c4   ; set user ISR
       limi 2
       jmp  $

position:
       data 0
       
handler:
       mov  r11, r10
       mov  @position, r0
       li   r1, '# '
       bl   @vsbw       ; standard implementation
       inc  r0
       andi r0, >1ff
       mov  r0, @position
       b    *r10

.

This does not fill 2/3 of the screen, but simply displays two chars. Even more bizarely, the second char only appears after a couple of seconds.

 

post-35214-0-42096300-1445179749_thumb.png

 

Now I realize that you probably wouldn't want to write to the VDP in the handler itself. In fact, I wouldn't enable interrupts in the first place but use vsync polling in my game instead.

 

But can someone explain to me what is happening here? Is access to the VDP triggering another interrupt?! And what is causing the delay? (This is all in MESS, BTW.)

 

Link to comment
Share on other sites

This works fine for me:

	   def  main

VDPRD  EQU  >8800               * VDP read data
VDPSTA EQU  >8802               * VDP status
VDPWD  EQU  >8C00               * VDP write data
VDPWA  EQU  >8C02               * VDP set read/write address

ws     EQU  >8300

       AORG >A000
main:
       lwpi ws
       li   r0, handler
       mov  r0, @>83c4   ; set user ISR
       limi 2
       jmp  $

position:
       data 0
       
handler:
       mov  r11, r10
       mov  @position, r0
       li   r1, '# '
       bl   @vsbw       ; standard implementation
       inc  r0
       andi r0, >1ff
       mov  r0, @position
       b    *r10
	   
***************************************************************************
*
* VDP Single Byte Write
*
* R0   Write address in VDP RAM
* R1   MSB of R1 sent to VDP RAM
*
* R0 is modified, but can be restored with: ANDI R0,>3FFF
*
VSBW   SWPB R0
       MOVB R0,@VDPWA           * Send low byte of VDP RAM write address
       SWPB R0
       ORI  R0,>4000            * Set read/write bits 14 and 15 to write (01)
       MOVB R0,@VDPWA           * Send high byte of VDP RAM write address
       MOVB R1,@VDPWD           * Write byte to VDP RAM
       B    *R11
*// VSBW

	   end main

It takes 512/60=8.5 seconds to draw the screen.

post-35226-0-59270800-1445181598_thumb.png

  • Like 1
Link to comment
Share on other sites

This works fine for me

 

Ah, I think I've figured it out. Sorry for not posting the entire code and for the misleading comment about VSBW; by "standard implementation" I meant "what everybody else is doing." Here's the missing part of my code:

 

ws:
       equ  >8300
ws_r0lb:
       equ  ws + 1
       
vsbw:
       movb @ws_r0lb, @vdpwa
       ori  r0, >4000
       movb r0, @vdpwa
       movb r1, @vdpwd

       rt
Since the SWPB version is working fine I conclude that the user ISR is using a different WS than the one I set upfront! I'll check what the console ISR is using with the debugger ... But would it be safe to alter the WS and not restore it prior to returning from the user ISR (which, of course, would have to be a B @whatever instead of RT)?
Link to comment
Share on other sites

We do not have a stack management for subroutines, accordingly, the least desirable event is being interrupted while handling an interrupt. I'm not sure, however, if the interrupts are not already masked when entering the ISR, anyway. I'm currently not at my desk, so I cannot check "TI Intern" right now, but maybe you can look it up. Check locations >0900.

Link to comment
Share on other sites

Since the SWPB version is working fine I conclude that the user ISR is using a different WS than the one I set upfront! I'll check what the console ISR is using with the debugger ... But would it be safe to alter the WS and not restore it prior to returning from the user ISR (which, of course, would have to be a B @whatever instead of RT)?

That is the point. Your user ISR is called with a fixed WS (either 83C0 or 83E0, need to check). If you want to change the WS you have to use LWPI in your handler. In that case you must restore the WS pointer prior to returning.

 

Accordingly, the reaction of your program is quite clear. Your INC R0 does not affect 8301 which you use as the low byte of the address. The high byte is correctly fetched from R0, and this one increases every 256 iterations, so you get those 3 positions on the screen.

 

[Edit: OK, back at the desk, browsing TI Intern. See page 34, address 0AB6 - this is the branch and link to the user ISR. Shortly before, the workspace pointer is set to GPLWS. At address 0900, LIMI 0 is executed, as expected, so you don't need a LIMI 0 in your code.]

Edited by mizapf
  • Like 1
Link to comment
Share on other sites

Accordingly, the reaction of your program is quite clear. Your INC R0 does not affect 8301 which you use as the low byte of the address. The high byte is correctly fetched from R0, and this one increases every 256 iterations, so you get those 3 positions on the screen.

 

[Edit: OK, back at the desk, browsing TI Intern. See page 34, address 0AB6 - this is the branch and link to the user ISR. Shortly before, the workspace pointer is set to GPLWS. At address 0900, LIMI 0 is executed, as expected, so you don't need a LIMI 0 in your code.]

 

Yes, I figured as much ... It's kind of satisfying to see how seemingly erratic code suddenly makes perfect sense! And thanks for the Intern pointer, I'll take a look.

 

We do not have a stack management for subroutines, accordingly, the least desirable event is being interrupted while handling an interrupt.

 

Well, on a modern system I would agree, but for the TI I could imagine using the interrupt as some kind of "time boxing" for certain use cases -- I guess that the important stuff has already been done by the console ISR, so never mind how far the user ISR will get ... I don't see how this would trip up the caller, assuming that the user ISR will not change the workspace. This would be different if the ISR was called by BLWP instead of a BL. (But then, I'll really check TI Intern on this one before making any further bold assumptions.) :)

Link to comment
Share on other sites

If you are running an interrupt hook and you turn interrupts back on, when you're interrupted again you don't get to resume - you'll be called again from the beginning of your hook. You might be able to maintain some form of stage inside your own code for picking up again. :) But it won't hurt anything - except that the main program will never get a chance to run. :)

 

Running your main program, of course, when the interrupt finishes you get your original workspace back and pick up where you left off -- assuming nothing that happened during the interrupt corrupted your data. :)

Link to comment
Share on other sites

You get a surprising amount of work done on the VDP interrupt. My machine code version of manic miner (un-finished) runs entirely off of the VDP interrupt. The main thread is just a JMP $ instruction!

 

I do it by splitting up the work across multiple frames. Frame 0 - updates sprite positions, frame 1, animate floors, frame 2, animate oxygen level bar etc. The nature of that game means 60 fps are simply not required!

Edited by Willsy
  • Like 2
Link to comment
Share on other sites

  • 3 weeks later...

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