robus Posted September 11, 2022 Share Posted September 11, 2022 Hoping for a bit of help grokking this bit of code: ; TRANSMIT DONE INTERRUPT SERVICE ROUTINE ; ISRTD: LDA CHKSNT BEQ FOOEY ;BRANCH IF CHECKSUM NOT YET SENT ;OTHERWISE SET TRANSMISSION DONE FLAG ;DISABLE TRANSMIT DONE INTERRUPT ;RETURN FROM INTERRUPT ; ; STA XMTDON LDA POKMSK AND #$F7 STA POKMSK STA IRQEN ; FOOEY: PLA RTI The OS has tried to send a byte to a Disk device (which of course is not present) and the SEND: block is currently looping on this: NOTDON: LDA BRKKEY BNE NTBRKO JMP BROKE ;JUMP IF BREAK KEY PRESSED NTBRKO: LDA XMTDON ;LOOP UNTIL TRANSMISSION IS DONE BEQ NOTDON JSR SENDDS ;DISABLE SENDING RTS RETURN My question is how is a timeout supposed to be handled in this situation? What is POKEY expected to do with a byte it can't send? And how does XMTDON get a value that breaks the loop? Quote Link to comment Share on other sites More sharing options...
phaeron Posted September 11, 2022 Share Posted September 11, 2022 No timeout is needed as the duration is strictly bounded based on the output bit clock. POKEY asserts the serial output ready IRQ whenever it has loaded the output shift register and is ready for another byte to be queued. At this point, SIO can do one of two things: write another byte into SEROUT, or wait for the serial output complete IRQ. The latter is the case for the code above and is guaranteed to complete, as the duration solely depends on the fixed rate that POKEY shifts out bits based on AUDCTL/AUDF3/AUDF4/SKCTL. As there is no per-byte handshaking on the SIO bus, it doesn't matter what the devices on the SIO bus are doing -- POKEY will send the bits out regardless of whether any device is ready to receive. Waiting for the serial output complete IRQ is needed because it takes time for POKEY to shift out the last byte after it has been loaded into the shift register from SEROUT, and the serial port parameters can't be changed until all bits have sent. As for the serial output complete IRQ itself, it is special in that it is not a latched IRQ. Instead, it's simply asserted whenever the serial output shift register is idle. Thus, its state in IRQST bit 3 is not dependent upon whether it is enabled in IRQEN, and if the output shift register is already idle it will assert an IRQ as soon as it is enabled. 1 1 Quote Link to comment Share on other sites More sharing options...
robus Posted September 12, 2022 Author Share Posted September 12, 2022 Thanks, that helps and now I'm sending those IRQs to the CPU as my POKEY blindly shoves the bits out. However the SYIRQ: handler is quite a puzzle. SYIRQ: PHA ;SAVE ACCUMULATOR LDA IRQST ; CHECK FOR SERIAL IN AND #$20 BNE SYIRQ2 LDA #$DF ; MASK ALL OTHERS STA IRQEN LDA POKMSK STA IRQEN JMP (VSERIN) SYIRQ2: TXA ;PUT X INTO ACC PHA ;SAVE K ONTO STACK LDX #$6 ;START WITH SIX OFFSET LOOPM: LDA CMPTAB,X ;LOAD MASK CPX #5 ;CHECK TO SEE IF COMPLETE IS SET BNE LOOPM2 AND POKMSK ;IS THIS INTERUPT ENABLED? BEQ LL Specifically the LOOPM: section. I see X is loaded with 6 then A is loaded from the mask table (offset by X), and then X is compared to 5, but we know 6 won't ever equal 5 so what is the deal with that bit of logic?! However I think that "CHECK TO SEE IF COMPLETE IS SET" is not related to Transmission complete. That I believe is handled by ISRTD: ; TRANSMIT DONE INTERRUPT SERVICE ROUTINE ; ISRTD: LDA CHKSNT BEQ FOOEY ;BRANCH IF CHECKSUM NOT YET SENT STA XMTDON ;OTHERWISE SET TRANSMISSION DONE FLAG LDA POKMSK ;DISABLE TRANSMIT DONE INTERRUPT AND #$F7 STA POKMSK STA IRQEN FOOEY: PLA RTI ;RETURN FROM INTERRUPT Could someone give me the address of ISRTD? I'd like to set a "breakpoint" there to see if it gets called in my simulator. At the moment I believe it isn't. (I wonder if there is a listing of all the subroutine addresses in this ROM?) Quote Link to comment Share on other sites More sharing options...
robus Posted September 12, 2022 Author Share Posted September 12, 2022 Ah I do see that LL: does DEX and loops around so at least X is changed, though the logic is quite convoluted seeming! Anyway, I also see that the Transmission Finished IRQ is not enabled until there's some other IRQ first, (like Output Data Needed). However I'm still not getting out of that loop, going to do some further stepping/debugging. (And I now see that Mapping the Atari has a number of routine addresses listed). Quote Link to comment Share on other sites More sharing options...
robus Posted September 12, 2022 Author Share Posted September 12, 2022 Hmm, I think my problem is that both Output Data Needed and Transmission Finished are both set and, because of the order of testing which IRQs are ready (in the CMPTABLE), the Output Data Needed JMP is taken. It seems like Output Data Needed would always be available (if the flag is set in IRQEN?) but then ISRTD would never be called, which is obviously not the case. Hoping for some clarity on that? Quote Link to comment Share on other sites More sharing options...
robus Posted September 12, 2022 Author Share Posted September 12, 2022 (edited) This is my POKEY IRQ status when the Interrupt is handled timer1 uint8 '\x01' timer2 uint8 '\x01' timer4 uint8 '\x01' serialOutputDone uint8 '\0' serialOutputDataNeeded uint8 '\0' serialInputReady uint8 '\x01' keyPressed uint8 '\x01' breakPressed uint8 '\x01' I see that setting bits to 0 in IRQEN is meant to reset the status of some bits (excluding serialOutputDone) and I'm now handling that. I expected it to turn off the serialOutputDataNeeded, but it didn't Edited September 12, 2022 by robus Quote Link to comment Share on other sites More sharing options...
robus Posted September 12, 2022 Author Share Posted September 12, 2022 Hmm - IRQs are supposed to be queued, that might help! (not sure how that's done in hardware, but easy enough in software) Quote Link to comment Share on other sites More sharing options...
phaeron Posted September 12, 2022 Share Posted September 12, 2022 Yes, POKEY will hold /IRQ asserted as long as there is still an enabled IRQ pending in IRQST. This will cause the 6502 to re-enter the IRQ routine after the RTI until all IRQs are acknowledged. This does mean that if the 6502 fails to handle an IRQ properly, it will get stuck in an interrupt loop, which does occasionally happen. There is no queuing beyond that though -- POKEY doesn't record that it should call the same IRQ twice, nor will the 6502 run the IRQ handler if an unmasked IRQ isn't currently active. As for the interrupt state, you shouldn't have serial output ready and serial output complete both asserted during normal SIO operation unless there is a gap in transmission. That shouldn't happen as the SIO routines will keep one byte queued ahead in SEROUT. Serial output ready only triggers when the output shift register is loaded from SEROUT and won't assert at the end of the last byte. Quote Link to comment Share on other sites More sharing options...
phaeron Posted September 12, 2022 Share Posted September 12, 2022 4 hours ago, robus said: Specifically the LOOPM: section. I see X is loaded with 6 then A is loaded from the mask table (offset by X), and then X is compared to 5, but we know 6 won't ever equal 5 so what is the deal with that bit of logic?! However I think that "CHECK TO SEE IF COMPLETE IS SET" is not related to Transmission complete. This branch is related to the special nature of the serial output complete IRQ. All other IRQs are defined to be negated when disabled -- if bit 6 of IRQEN is cleared, the serial output ready IRQ is disabled. Any existing pending IRQ for it is cleared, bit 6 of IRQST is locked to 1, and it cannot recur until re-enabled. However, the serial output complete IRQ is special and will show an active status in IRQST bit 3 even if it is disabled. For this reason, the OS checks if the serial output complete IRQ is actually enabled before trying to handle it. It can't read back from the write-only IRQEN register, so it uses the shadow variable POKMSK instead. Quote Link to comment Share on other sites More sharing options...
robus Posted September 12, 2022 Author Share Posted September 12, 2022 (edited) 1 hour ago, phaeron said: Serial output ready only triggers when the output shift register is loaded from SEROUT and won't assert at the end of the last byte. Thanks for all the help, it is very much appreciated! How does POKEY know it's seen the last byte? Currently, I just set raise the output ready IRQ after POKEY has loaded its "shift register" - so it always thinks there could be another byte (if the IRQ is enabled of course, so I guess the answer is the IRQ is disabled when the last byte is written!) Edited September 12, 2022 by robus Quote Link to comment Share on other sites More sharing options...
robus Posted September 12, 2022 Author Share Posted September 12, 2022 I have to admit that I'm really not grokking this test: LOOPM2: BIT IRQST ; IS IT THE INTERUPT? BEQ JMPP Bits in IRQST are at zero when they have triggered, so how does BIT testing against a mask address that? The mask has $08 for the COMPLETE test, but POKEY sets COMPLETE bit to zero? Quote Link to comment Share on other sites More sharing options...
robus Posted September 12, 2022 Author Share Posted September 12, 2022 I slowed down my POKEY clock (currently it's on a separate timer from the CPU - definitely not ideal but baby steps), actually got the complete IRQ handled and a miracle happened! Quote Link to comment Share on other sites More sharing options...
robus Posted September 12, 2022 Author Share Posted September 12, 2022 (edited) Not only that I can type in it too! Thanks so much for your patient help @phaeron, you've been a lifesaver! Edited September 12, 2022 by robus 1 Quote Link to comment Share on other sites More sharing options...
phaeron Posted September 13, 2022 Share Posted September 13, 2022 4 hours ago, robus said: How does POKEY know it's seen the last byte? Currently, I just set raise the output ready IRQ after POKEY has loaded its "shift register" - so it always thinks there could be another byte (if the IRQ is enabled of course, so I guess the answer is the IRQ is disabled when the last byte is written!) It doesn't. It's just that if there isn't a new byte available in SEROUT, there's nothing to load into the shift register, and thus serial output ready doesn't get triggered. If the 6502 does write a new byte, POKEY loads it on the next serial tick and then triggers serial output ready. This does mean that you need to track an additional boolean state if you haven't already: whether SEROUT holds an unsent byte. 3 hours ago, robus said: I have to admit that I'm really not grokking this test: LOOPM2: BIT IRQST ; IS IT THE INTERUPT? BEQ JMPP Bits in IRQST are at zero when they have triggered, so how does BIT testing against a mask address that? The mask has $08 for the COMPLETE test, but POKEY sets COMPLETE bit to zero? At this point, the A register holds the IRQ bit to be tested. For the serial output complete IRQ, it is skipped if the POKMSK test fails. The BIT instruction then masks off the value of IRQST to only the pertinent bit by computing the bitwise AND of the IRQ state from IRQST and the bit in the A register. If the bit is cleared, Z=1 and the BEQ is taken to dispatch to the IRQ handler. The loop continues until either it finds an IRQ that is asserted (0 bit) or nothing is found (spurious or non-POKEY IRQ). 1 Quote Link to comment Share on other sites More sharing options...
robus Posted September 13, 2022 Author Share Posted September 13, 2022 2 hours ago, phaeron said: If the bit is cleared, Z=1 and the BEQ is taken to dispatch to the IRQ handler. Ah, of course. It’s been far too long since I’ve touched assembler. Using AND to test a zero result is just opposite to what I’d expect 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.