marc.hull Posted July 24, 2013 Share Posted July 24, 2013 Further news: I played Lock&Chase on my Colecovision for one hour, then before putting again in its place I tried again the test 2, incredibly the VDP changed its behavior. 1. bit 5 = collision bit starts to lose collisions at same rate that interrupt bit. 2. bit 6 = 5th bit starts to lose collisions at double rate that interrupt bit. Because the chip is now hot or somehow voltage drop slightly? I cannot explain it . Anyway, this finally settles matters for me about why my poor little game failed so many years ago. Recipe: No polling, use interrupt if you want to use collisions. Better, handle collision with your own code and stop worrying about possible VDP misbehavior. I don't think your recipe is correct....... The VDP is doing what the VDP does..... Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted July 24, 2013 Share Posted July 24, 2013 The discussion was about running without the ISR and subsequently with out the copy.... H-m-m...nice to know. I didn't realize the copy of the VDP status byte was only updated when interrupts were enabled. ...lee 1 Quote Link to comment Share on other sites More sharing options...
matthew180 Posted July 24, 2013 Share Posted July 24, 2013 H-m-m...nice to know. I didn't realize the copy of the VDP status byte was only updated when interrupts were enabled. It is the ISR that makes the copy. No ISR enabled, no copy of the VDP status byte. Quote Link to comment Share on other sites More sharing options...
matthew180 Posted July 24, 2013 Share Posted July 24, 2013 I email Karl Guttag (one of the designers of the 9918A VDP at TI back in the day) and he had this to say: I'm not sure I can be much help. I don't have the schematics and I did not work directly on that section of the 9918. It was my first design at TI and I know that it was not robust in terms of dealing with asynchronous events (on my next project, the 9995, I remember spending some considerable effort on asynchronous hazards). To get the design to fit we did all the logic as minimally as possible. So it is possible that the designer did not worry about someone reading and resetting at the same time so long as it did not cause the chip to melt. Somewhere deep in my mind, I think there might have been an issue with polling (but I really don't remember). Sorry I couldn't be of more help. Based on that, I would say there is no 100% reliable way to poll the status register without first getting the interrupt from the VDP. For the 99/4A, that means letting the console ISR run (but disable as much of it as possible) and hooking into the user subroutine. On other systems I don't know what it means. If you do poll, be prepared to have some misses from time to time. Or do what Tim suggested. I'll have to look into that one. It might be an interesting alternative. Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted July 24, 2013 Share Posted July 24, 2013 Uh.... cause we are ignorant of that. So with interrups disabled in the CPU the vdp will pass it's. Interrupt signal to the 9901 at CRU 2? Does the 9901 maintain this output until it's read? Thanks T. Here's salt water I'm your eye . Reading the CRU bit does not clear the output. However, you will need to reset the interrupt bit so that your routine does not get caught in an endless service loop. To answer your first question yes, the VDP will present its interrupt signal even when the mask is 0 so long as the VDP chip's interrupts are enabled. The mask does not inhibit the VDP or other devices from presenting their interrupts to the system but it does play into whether or not they are serviced by the ISR. You can use these characteristices to your advantage, especially when you roll your own code and do not require the ISR. 1 Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted July 24, 2013 Share Posted July 24, 2013 (edited) I do a "LIMI 0" in the very beginning of my code, and then never issuing a "LIMI 2". No console ISR will run. When all my game logic/whatever is done, or sliced so it's done within 1/60th of a sec, then the following waits for the interrupt. The routine will return immediately if a frame has already been displayed since the last run/read. Call it twice to run at 30 frames a sec. wait1 movb @>8802,r0 ; wait for end of VDP displaying frame (reading it will reset it) andi r0,>8000 ; isolate bit 0 (set when end of frame) jeq wait1 rt Here is a snippet that should perform the same assuming the interrupt mask is 0 (LIMI 0) and the VDP interrupts are enabled. I sometimes get the TB and SBO/SBZ conditions mixed up and unfortunately, I do not have the ability to test at the moment. This should adhere to the 9918s comments regarding reading the status following detection of an interrupt. wait1 clr r12 wait2 tb 2 *VDP interrupt (poll 9901) jeq wait2 *no, keep waiting sbo 2 *yes, clear 9901 bit/VDP interrupt movb @8802,r0 *read status from VPD rt [Edit: See posts 173-175 for proper interpretation of the CRU bit settings for the 9901] Edited July 28, 2013 by InsaneMultitasker 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted July 24, 2013 Share Posted July 24, 2013 Here is a snippet that should perform the same assuming the interrupt mask is 0 (LIMI 0) and the VDP interrupts are enabled. I sometimes get the TB and SBO/SBZ conditions mixed up and unfortunately, I do not have the ability to test at the moment. This should adhere to the 9918s comments regarding reading the status following detection of an interrupt. wait1 clr r12 wait2 tb 2..........*VDP interrupt (poll 9901) jeq wait2.....*no, keep waiting sbo 2.........*yes, clear 9901 bit/VDP interrupt movb @8802,r0 *read status from VPD rt This method will not work with CPU interrupts enabled, correct? If so, would it work by disabling interrupts (LIMI 0) at wait1 and enabling them (LIMI 2) just before rt? ...lee Quote Link to comment Share on other sites More sharing options...
Tursi Posted July 24, 2013 Share Posted July 24, 2013 Very nice to get some detail study on this issue, and thanks to Marc for reporting it in the first place way back when. Agreed, that it seems it is not safe to read the status register during active screen generation due to the chance of a race condition losing a bit. Seems the odds of the race vary some from system to system, run to run. None of the bits can theoretically be set during vertical blank, so reading then should be safe. Damn. Quote Link to comment Share on other sites More sharing options...
Asmusr Posted July 24, 2013 Author Share Posted July 24, 2013 I think I gave an example in my assembly thread of efficient interrupt usage. I can dig it up if you want some code to look over Yes, please. I don't remember having seen this. Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted July 24, 2013 Share Posted July 24, 2013 So to summarize – I’d like you opinions ... The advantage of the LIMI 2 opposed to the LIMI 0 method then becomes better overall availability of CPU time at the expense or readiness of a few bytes in ScrathPad. Is that about right ? Quote Link to comment Share on other sites More sharing options...
+mizapf Posted July 24, 2013 Share Posted July 24, 2013 If you are writing programs or making use of interrupt-controlled processing, LIMI 2 is mandatory. You can turn off interrupts, gaining speed, but also losing features like automotion of sprites, sound processing, or QUIT key processing. I found it interesting to see that with TI's most advanced CPUs of the 99er family, the TMS99000 series, LIMI is taken away from the user processes. Only the operating system should have the right to disable interrupts. Calling LIMI within the user mode will cause a trap. Well, our 99/4A is not really a multiprocessing machine... 2 Quote Link to comment Share on other sites More sharing options...
Asmusr Posted July 24, 2013 Author Share Posted July 24, 2013 If you are writing programs or making use of interrupt-controlled processing, LIMI 2 is mandatory. You can turn off interrupts, gaining speed, but also losing features like automotion of sprites, sound processing, or QUIT key processing. In my programming I consider those features (auto-motion of sprites, sound processing, or QUIT key processing) undesirable, but the interrupt itself without those features would be nice to have. Quote Link to comment Share on other sites More sharing options...
+mizapf Posted July 24, 2013 Share Posted July 24, 2013 You have a flag byte for that purpose (83C2). Have a look at http://www.ninerpedia.org/index.php/Programming#Useful_CALL_LOADs, a bit down the page. This flag byte is checked by the interrupt handler. Quote Link to comment Share on other sites More sharing options...
marc.hull Posted July 24, 2013 Share Posted July 24, 2013 Polling the CRU seems to solve the issue entirely. When your finished with your processing.... Test CRU bit 2(please verify this) until it is set. When it is set then read the status bit, update your sprite info and RESET bit 2. Exit your ISR... Much better method. I'll update my strategy post Hast.... 1 Quote Link to comment Share on other sites More sharing options...
matthew180 Posted July 24, 2013 Share Posted July 24, 2013 Yes, please. I don't remember having seen this. I could not find it either, but I did find some related information I had written earlier (pg2 about post #38 in the link below). I added a new post to the Assembly thread about hooking the console ISR: http://atariage.com/forums/topic/162941-assembly-on-the-994a/page__st__225#entry2797433 I'll have to see about using the CRU for polling the VPD too. Maybe Marc will do it first and post an example. I wonder if polling the 9901 will cause *it* to start to fail in strange ways? Doh. On some consoles I have seen the 9901 with its own heat sink like the VDP... Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted July 24, 2013 Share Posted July 24, 2013 Polling the CRU seems to solve the issue entirely. When your finished with your processing.... Test CRU bit 2(please verify this) until it is set. When it is set then read the status bit, update your sprite info and RESET bit 2. Exit your ISR... Much better method. I'll update my strategy post Hast.... I'm not sure I got it all. Could probably try and read it (all) again. Could you eventually post code that works on the TI ? Please. Hopefully Classic99 and MESS will work too. We'll see. Quote Link to comment Share on other sites More sharing options...
marc.hull Posted July 24, 2013 Share Posted July 24, 2013 (edited) I'm not sure I got it all. Could probably try and read it (all) again. Could you eventually post code that works on the TI ? Please. Hopefully Classic99 and MESS will work too. We'll see. I'm out of town and won't be able to get to some particulars so others correct the mistakes please.... This is generated per Tim's info so if it doesn't work then it's his fault ... ISR1 CLR R12 BASE 0 OF CRU ISR ENTRY POINT ISR2 TB 2 TEST CRU BIT 0002 JEQ ISR2 IF ZERO THEN NO INTERUPT HAS OCCURRED (ZERO ???) MOVB @VDPSTA,R0 GET STATUS REGISTER NOT PAD COPY.... SBZ 2 RESET CRU BIT RT Status byte will be contained in MSB or R0... Can't test this till next week so if someone can then please do. Edited July 24, 2013 by marc.hull 1 Quote Link to comment Share on other sites More sharing options...
Asmusr Posted July 24, 2013 Author Share Posted July 24, 2013 I could not find it either, but I did find some related information I had written earlier (pg2 about post #38 in the link below). I added a new post to the Assembly thread about hooking the console ISR: Thanks Matthew. I think I will stick to the polling. Firstly I only have 6 unused bytes left in scratch pad! Secondly I'm writing to the VDP RAM pretty much all of the time, so I don't know when I could enable interrupts. For the interrupt to be useful for me it would have to break into my CPU RAM to VDP RAM copying routine, execute the sprite moving/joystick reading/sound playing routines and then return to the execution of the VDP RAM copying routine. That would ensure that no CPU cycles are wasted, but it doesn't sound like that would be possible. Quote Link to comment Share on other sites More sharing options...
matthew180 Posted July 24, 2013 Share Posted July 24, 2013 Well, if you are only using the ISR to set up a known timing, or as an indicator as to when to sample user input or update sounds, then only enable the interrupt during the loop where you wait: VSYNC LIMI 2 VWAIT MOV @INTFLG,@INTFLG JEQ VWAIT LIMI 0 CLR @INTFLG Of course you still have to worry about what the ISR does with the scratchpad. Otherwise, Tim's example of polling via the 9901 is probably the best way. Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted July 27, 2013 Share Posted July 27, 2013 (edited) I'm out of town and won't be able to get to some particulars so others correct the mistakes please.... This is generated per Tim's info so if it doesn't work then it's his fault ... ISR1 CLR R12 BASE 0 OF CRU ISR ENTRY POINT ISR2 TB 2 TEST CRU BIT 0002 JEQ ISR2 IF ZERO THEN NO INTERUPT HAS OCCURRED (ZERO ???) MOVB @VDPSTA,R0 GET STATUS REGISTER NOT PAD COPY.... SBZ 2 RESET CRU BIT RT Status byte will be contained in MSB or R0... Can't test this till next week so if someone can then please do. I included a code segment similar to yours in my email reply to Sometimes99er a few days ago, but it looks like the AA forum inserted a whole bunch of formatting codes into the CODE section. One thing you need to do is turn off the CRU bit so that the next time through your loop you don't encounter the past interrupt. This can be done immediately before reading the VDP status byte. [Edit: See posts 173-175 for proper interpretation of the CRU bit settings for the 9901] Edited July 28, 2013 by InsaneMultitasker 1 Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted July 27, 2013 Share Posted July 27, 2013 I'll have to see about using the CRU for polling the VPD too. Maybe Marc will do it first and post an example. I wonder if polling the 9901 will cause *it* to start to fail in strange ways? Doh. On some consoles I have seen the 9901 with its own heat sink like the VDP... Interesting thought. Marc would need to chime in as I seem to recall his issue was either with the timer mode or changing the 9901 input/output modes very rapidly. I am not aware of any maximum polling frequency limits for an output line but it certainly wouldn't hurt to look into it. Quote Link to comment Share on other sites More sharing options...
marc.hull Posted July 28, 2013 Share Posted July 28, 2013 I included a code segment similar to yours in my email reply to Sometimes99er a few days ago, but it looks like the AA forum inserted a whole bunch of formatting codes into the CODE section. One thing you need to do is turn off the CRU bit so that the next time through your loop you don't encounter the past interrupt. This can be done immediately before reading the VDP status byte. 7:15 pm.... Your code did indeed get mangled. I follow the logic but could use an explanation as to why you use SBO instead of SBZ to turn off the bit? Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted July 28, 2013 Share Posted July 28, 2013 (edited) I follow the logic but could use an explanation as to why you use SBO instead of SBZ to turn off the bit? I hope I don't get into trouble with this explanation attempt. I also apologize for the formatting, I still can't get AA's code sections to work properly. From what I understand, the interrupt signal originating from the 9918 is active low, meaning that when the 9918 signals an interrupt it is presented to the 9901 as output state "0"; conversely, when there is no interrupt pending the output state is "1". When we test the 9901 CRU bit, there are two interrupt states (see the 9918 manual, sections 2.3 and 2.3.1, for interrupt and status flag information). 0 = VDP Interrupt occured 1 = VDP Interrupt has not yet occured (since the last frame). But wait - there's more. We must also contend with the EQual status bit. Recall that instructions like MOV can be used to compare the contents of a register (or memory location) to zero. Testing the EQual status bit tells you whether or not the value is zero. MOV R1,R1 * move value of R1 into R1. JEQ ZERO * If R1 is zero, the EQ bit is set (1) and we jump to ZERO * conversely: JNE NOTZERO * If R1 is not zero, the EQ bit is reset (0), and we jump to NOTZERO Here the EQ status bit is set (EQ=1) when the register content is zero and reset (EQ=0) when the register content is not zero. However, when we test a CRU bit, the EQ status bit matches the logic level of the output being tested. While this may be more intuitive, the EQ status bit usage has the opposite effect: CLR R12 * set our CRU Base TB 2 * test CRU bit 2 JEQ NOTZERO * If CRU bit is "1" or "set", then EQ is set and we jump to NOTZERO * Conversely: JNE ZERO * if CRU bit is "0" or "reset", then the EQ bit is reset (0) and we jump to zero Let's combine the interrupt states with the above knowledge using the earlier code suggestion based on Sometime99er's VDP Status test code: wait1 clr r12 wait2 tb 2 * test the VDP interrupt line, active LOW, presented to the 9901 by the 9918 jeq wait2 * If EQ is set (1) then we are still waiting for an interrupt to occur. * * To get here, the EQ bit is now reset (0) which means there was a VDP interrupt * "Clear" the interrupt condition by setting the 9901 bit to "1" * Edit: Incorrect - SBO 2 simply ensures this line of the 9901 can generate * an interrupt for the system. Probably not needed since we assume interrupts * are turned off with LIMI 0 and no ISR usage. * sbo 2 *yes, clear 9901 bit/VDP interrupt Enable 9901 interrupt for this line. movb @8802,r0 *read status from VPD, clear VDP interrupt rt One additional thought: I have always cleared the interrupt condition with "SBO 2". [Edit: upon review of some of my old code, I re-discovered I read the VDP status byte to clear the VDP interrupt condition similar to the example above. I use the SBO 2 in some programs to ensure this interrupt line is enabled. Unlike the TI, with the Geneve one can modify the interrupt vector and eliminate or intercept the ISR. Shame on me for mixing up the two systems.] However, since the 9918 VIDINT is an output, I surmise the SBO 2 may simply turn the 9901 line into an input until the next pending VDP interrupt (at which time the 9918 sets the interrupt and returns the line to an output condition) or until the next CRU test of the 9901 line. Reading the status register (which clears the pending interrupt condition) might be the only true way to clear the 9918 output. Maybe someone here can give a more definitive answer. [Edit: My interpretation of the 9901 interrupt line usage was incorrect. See Michael's reference in post #174. Writing to this 9901 CRU bit either enables or disables the 9901 interrupt mask. It may be more appropriate, though probably not necessary, to disable the interrupt mask for this bit (SBZ 2) during program setup. Then polling this CRU line would be done as a true input.] Tim Edited July 28, 2013 by InsaneMultitasker Quote Link to comment Share on other sites More sharing options...
+mizapf Posted July 28, 2013 Share Posted July 28, 2013 I surmise the SBO 2 may simply turn the 9901 line into an input until the next pending VDP interrupt (at which time the 9918 sets the interrupt and returns the line to an output condition) or until the next CRU test of the 9901 line. Reading the status register (which clears the pending interrupt condition) might be the only true way to clear the 9918 output. Maybe someone here can give a more definitive answer. Within the first 16 lines of the TMS9901 you have only inputs, and when you set the bit to 1 you enable the interrupt for this line. Zero disables the interrupt for this line. When you do a SBZ, the state of the line can still be read with LDCR or TB, but it does not trigger an interrupt. See the TMS9901 manual on WhTech, page 6 (of the PDF). 1 Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted July 28, 2013 Share Posted July 28, 2013 Within the first 16 lines of the TMS9901 you have only inputs, and when you set the bit to 1 you enable the interrupt for this line. Zero disables the interrupt for this line. When you do a SBZ, the state of the line can still be read with LDCR or TB, but it does not trigger an interrupt. See the TMS9901 manual on WhTech, page 6 (of the PDF). Ah yes, the first 16 are not programmable IO. I have edited my earlier posts to correct my mistake. Thank you! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.