Re: [stella] Intelligent Job-System idea

Subject: Re: [stella] Intelligent Job-System idea
From: Christopher Tumber <christophertumber@xxxxxxxxxx>
Date: Sat, 04 Jan 2003 17:38:12 -0500
>Well, I have to carefully consider this. A great deal of routines I do are really required every frame.

Yeh, the ideal situation is to be calling every routine every time, and considering the generally limited AI needed for arcade-type games this is usually not a problem, even with classic consoles. But it does happen (now that I think of it, Big Dig will probably benefit from this discussion too, right now I just have a very basic set of branches that 
run a certain section of code on FrameA and a different set on FrameB and another set on FrameC but this is probably a much better way to handle it...) if you think about it, there are a lot of routines that aren't really needed every frame. For example, you probably don't need collision detection every frame (unless stuff is moving very fast and/or you have very detailed sprites) you can usually get away with only doing half (or even less) of your collision detections each frame and the other half the next frame...


Actually, if you have RAM to spare (ha!) and don't mind sacrificing the stack (ha!) you could almost eliminate the extra CPU cycle overhead completely.

Just use the stack as your subroutine pointer list and when you want to call your next subroutine you'd do so with an RTS. And then turn the stack into a circular stack by having your last routine reset the stack pointer to the top of the list.

(Hehe, I really like the idea of calling sub-routines with an RTS!)

Like....


;Put this in your game initialisation
  ldx #$ff   ;Make sure stack is at begining
  txs
  ldy NumberOfLowPriorityRoutinesTimesTwo ;#Routines * 2 because each address is a word
next_address_byte:
  lda LowPriorityRoutineTable,y   ;I think table needs to be reverse-byte ordered? So they go on the stack in corect order
  pha
  dey
  bne next_address_byte
;Put this in your game initialisation



;...Buncha Code here....



;Down in your main loop

low_priority_routine_handler:
  LDA INTIM
  CMP #$05       ; more than 6*64 cycles left?
  BCS end_VBLANK

  rts  ;Calls next routine in the list

end_VBLANK:


;...Buncha Code here....





LastLowPriorityRoutine:
;Some code here
;Some code here
;Some code here
  ldx #$FF-NumberOfLowPriorityRoutinesTimesTwo  ;Reset stack back to begining of list
  txs
  jmp low_priority_routine_handler




If you need to use the stack, then you can just have that LastLowPriorityRoutine reset the stack as per the initialisation but you loose most of the CPU overhead advantage...



>So one of the first not so trivial issues is finding the 
>proper XX here:
>
>>     LDA INTIM
>>     CMP #$XX       ; more than X*64 cycles left?

Yeah, that's the trick. You'd be trying to make your routines all of about the same cycle length...


>Remember I have a scenario like this:
>(Pseudo C code)

Okay, what if we used the above example with the stack, but made it more dynamic?

For example:

for(i=0;i<10;i++)
{
    if (IDObject(i)==METEOR)
    {
        put dothis1 address on stack
        put dothis2 address on stack
        put dothis3 address on stack
        put dothis4 address on stack
	   continue;
    }


And then we just treat it all as before, once these new routines are done we'll be back to the "normal" sequence of routines. In this case we will have to reset the stack list of routines once we get to the bottom, but there's a tremendous amount of flexibility available here (provided to can have a big enough stack...)

In effect, we're queueing all JSR/RTS so that they only get executed when we know there's enough time left in VBLANK (or Overscan).



Taking this all one step further - if we incorperated this kind of job handling throughout the main loop of the program, we could simulate the setup of later consoles/computers. Where the hardware and video RAM takes care of the tv output automatically, and the program itself is essentially run whenever there's time away from the video output (That's a real oversimplication, but I hope you take my meaning - On something like a Commodore 64, once you write to the video RAM you 
can forget about it and the hardware will automatically execute the video output on time, regardless of what you are doing the video output is going to be 100% and the only kind of glitch you can cause is if you change registers/RAM while the screen is being drawn (ie: Moving a sprite while it's being drawn and creating a shear) but otherwise it's foolproof.

So we could have a program template that looks something like this:


VBLANK start

Subroutine Handler

VBLANK end

Display Kernal

Overscan start

Subroutine Handler

Overscan end

<repeat>


If we did this right, we could never have to worry about taking too long in the VBLANK/Overscan, or having to decide what to put in the VBLANK/Overscan.

The downside is that we'd want to try to make routines all of consistent length and we'd still be subject to "slowdown" (ie: If our movement routines don't get called frequently enough), it just wouldn't affect the display.

(Really, it's just a work-around to create an interrupt driven kernal)


Chris...

----------------------------------------------------------------------------------------------
Archives (includes files) at http://www.biglist.com/lists/stella/archives/
Unsub & more at http://www.biglist.com/lists/stella/


Current Thread