Jump to content
IGNORED

Faster Interrupts?


Tursi

Recommended Posts

I haven't really put this to the test, but while playing with the F18A's horizontal interrupt, I dug in to see whether faster interrupt response was possible on the 4A than using the user interrupt link.. and I think it is, slightly. I figured I'd just post something for discussion and consideration.

 

So this is the normal code path, using the user interrupt hook and setting the flags to disable all console functions:

 

0900 0300 LIMI >0000 Disable interrupt 16
0902 0000
0904 02E0 LWPI >83E0 Load GPLWS! 10
0906 83E0
0908 04CC CLR 12 Clear CRU 10
090A 23A0 COC @>0032,14 Cassette interrupt? 14+8
090C 0032
090E 1602 JNE >0914 No, jump 8
0914 1F02 TB >0002 12
0916 1619 JNE >094A Jump, if VDP interrupt 10
094A 1D02 SBO >0002 Clear VDP interrupt 12
094C D060 MOVB @>83C2,1 Fetch interrupt flag byte 14+8
094E 83C2
0950 0A11 SLA 1,1 No interrupt permitted 12+2
0952 1702 JNC >0958 8
0954 0460 B @>0A84 Then jump 8+8
0956 0A84
0A84 D82F MOVB @>FC00(15),@>837B VDP status in copy RAM 14+8+4+8
0A86 FC00
0A88 837B
0A8A 02E0 LWPI >83C0 INTWS 10
0A8C 83C0
0A8E 05CB INCT 11 Screen timeout counter 10
0A90 160B JNE >0AA8 Not 0 10
0AA8 02E0 LWPI >83E0 GPLWS 10
0AAA 83E0
0AAC B80E AB 14,@>8379 VDP interrupt timer 14+8
0AAE 8379
0AB0 C320 MOV @>83C4,12 User defined interrupt 14+8
0AB2 83C4
0AB4 1301 JEQ >0AB8 None, then jump 8
0AB6 069C BL *12 Otherwise execute 12+4

 

Using this path, the console executes 21 instructions (30 words) and takes about 294 cycles to get to your code. In addition:

-VDP interrupt is cleared for you

-Peripheral and other interrupts are also handled

-Screen blanking may occur unless the counter variable is changed

 

Registers used if it's a VDP interrupt:

>8379: VDP system flags

>837B: VDP Status copy

>83C0: R1, R2, R11

>83E0: R1, R12, R14, R15

 

The alternative is to use the little hack discovered by Jeff Brown to get other interrupts running. Basically, you configure the system to expect cassette timer interrupts then take over. It takes a little setup (see below), but this is the code path taken in that case:

 

0900 0300  LIMI >0000   Disable interrupt  16
0902 0000
0904 02E0  LWPI >83E0   Load GPLWS!	10
0906 83E0
0908 04CC  CLR 12    Clear CRU	10
090A 23A0  COC @>0032,14  Cassette interrupt?  14+8
090C 0032
090E 1602  JNE >0914   Yes, don't jump 8
0910 0460  B @>1404		8+8
0912 1404
1404 1E00  SBZ >0000   Control 9901 set  12
1406 1D03  SBO >0003   Timer interrupt reset 12
1408 C041  MOV 1,1   R1 Negative?   14
140A 1107  JLT >141A		10
141A 02E0  LWPI >83C0		10
141C 83C0
141E C3A0  MOV @>83EC,14  R6 GPLWS becomes new R14 14+8
1420 83EC
1422 10FA  JMP >1418		10
1418 0380  RTWP    End	  14

 

This time, only 14 instructions (20 words) are executed, and it's about 178 cycles to get control (versus 294). However, there are some important differences:

-VDP registers are NOT read on this path, we get them

-To clear VDP interrupts, we need at least two more instructions:

-- read status register

0A84 D82F MOVB @>FC00(15),@>837B VDP status in copy RAM

-- clear 9901 interrupt

094A 1D02 SBO >0002 Clear VDP interrupt

-16 is still faster than 21. (24 words versus 30 - including the tests and clears, it's 242 cycles)

-The above also does not account for peripheral interrupts

-Also, 9901 timer mode can not be used because every interrupt will disable it

-And, of course, the true return address is lost, so you have to know where to jump back to

-Finally, the interrupt function is called with the host program's workspace!

 

To set up requires some messing with the scratchpad -- but this disables all

the rest of the scratchpad usage:

 

LWPI >83E0  GPLWS
  SETO R14  Everything's a cassette interrupt!
  SETO R1   Make R1 negative
  LI R6,INTERR Load R6 with the address you want interrupts to call

 

(It would also be a very good idea to disable peripheral interrupts in the 9901

if you do not plan on servicing them, otherwise a spurious card interrupt

will lock up your program.)

 

So, reserved values:

>83DA old workspace pointer

>83DC overwritten with address of interrupt routine

>83DE old STatus register

 

>83E2 'R1' flag byte

>83EC Interrupt function pointer (you fill this in, MUST BE VALID)

>83F8 GPLWS CRU pointer (overwritten)

>83FC scratch register

 

Maybe 20% faster overall, and frees 2 bytes of scratchpad (or so).

 

Worth it? Hard to say. Maybe in some cases. Probably not most of the time. But, it was interesting to dig through the paths.

Link to comment
Share on other sites

Been thinking about the load interrupt. Suppose you'd have a little device plugged in the sideport with a programmable timer that triggers the load interrupt. You would not have the hassle having to go through the console ISR. Dunno if you can trigger multiple load interrupts without resetting the console. Would have been cool if the CF7+ / nanopeb would have had such feature.

 

Another thing that comes too mind; with the available space constraints in the console ROM, would be possible to replace the ISR, perhaps removing the cassette functionality in favour of a faster ISR? Ofcourse the nice thing about your documented setup is that no hardware mods are required.

Edited by retroclouds
Link to comment
Share on other sites

The alternative to using the ISR is to just poll. You can check the status of the VDP interrupt once per program loop and call your pseudo ISR if it is set. Also, using the timer in the F18A you could set up some other interval by checking the counter value once per loop. I realize polling is not as convenient as the interrupt mechanism, but it is probably more efficient in the 99/4A unless you are using a lot of the services that the console ISR processes.

Link to comment
Share on other sites

Yeah, the load interrupt is much faster, since it will jump directly to your vector, but neither hte VDP nor the 9901 can trigger it without hardware mods.

 

As for replacing the console ROMs.. well, yeah, you could do whatever you like there. Most of the cassette DSR is actually in the GROM though, you don't get as much space as you might think (but the main purpose of such a replacement is probably to take advantage of the code that the cassette DSR forces anyway.)

 

Polling works more or less as well if you're limiting interrupts to one place in your code with LIMI 2/LIMI 0 anyway, yeah. Takes a little more code though, but it probably comes out to a wash overall.

Link to comment
Share on other sites

Polling worked fine for the stuff I did sofar. But was toying with the idea of creating a little scheduler for doing preemptive multitasking.

The thing with the ISR is that it expects scratchpad memory to be setup as required.

In my spectra2 library I use scratchpad memory in a different way. And it seems quite an overhead swapping values back and forth or if this

would even be possible when running without the 32K.

 

I think I read somewhere that there was a hack for UCSD Pascal on the TI-99/4A for implementing a preemptive multitasking scheduler.

I dunno how this was done and if it involved some extra piece of hardware.

Edited by retroclouds
Link to comment
Share on other sites

How are the ROMs organised in the console? Is it two 8 bit 8K ROMs?

 

I'd be interested in fitting an alternative ROM that simply jumps over the interrupt code in the console (the part that determines where the interrupt came from, does the sprites, sound etc). It would be interesting to see if it increased interrupt performance by a lot... Quite a few carts would cease to work I imagine, but a simple switch on the chip selects would allow one to select the original ROM or the modified ROM.

Link to comment
Share on other sites

How are the ROMs organised in the console? Is it two 8 bit 8K ROMs?

 

I'd be interested in fitting an alternative ROM that simply jumps over the interrupt code in the console (the part that determines where the interrupt came from, does the sprites, sound etc). It would be interesting to see if it increased interrupt performance by a lot... Quite a few carts would cease to work I imagine, but a simple switch on the chip selects would allow one to select the original ROM or the modified ROM.

 

See Thierry's site here---more specifically, here.

 

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

Have you seen Thierry's page on his multitasking implementation?

Interesting. That's very similar to what I tried to accomplish within the UCSD p-system context. The UCSD Pascal implementation on the TI already supports cooperative multitasking, so some things were already there, but no pre-emptive support. My attempt worked, but it turned out that the system doesn't protect dynamic memory allocations from being interrupted, and without the source code for unit HEAPOPS, it was in reality impossible to fix.
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...