Jump to content
IGNORED

CS1 support in JS99er.net (was: Question about 9901 timer)


Asmusr

Recommended Posts

I'm working on emulating cassette tape in JS99er.net.

 

My question is, once the 9901 timer has generated and interrupt, what does it take to re-enable the countdown to generate another?

 

According to Nouspikel, you need to to enter and leave timer mode, perhaps even write at least one bit to the clock register, but the cassette save routine only seems to be using SBZ 0 to restart the timer, even though the TMS9901 is already in I/O mode.

 

Thanks,

Rasmus

Link to comment
Share on other sites

TMS9901 specification (found on Whtech), pages 5 and 8

 

The clock functions as an interval timer by decrementing to zero, issuing an interrupt, and restarting at the programmed start value. When the clock interrupt is active, the clock mask (mask bit 3) must be written into (with either a "1" or a "0") to clear the interrupt.

If a value other than the initially programmed is required, a new 14-bit clock start value is similarly programmed by executing a CRU write operation to the same locations. During programming the decrementer is restarted with the current start value after each start bit is written. A timer restart can be easily implemented by writing a single bit to any of the clock bits.

Link to comment
Share on other sites

 

If a value other than the initially programmed is required. ... A timer restart can be easily implemented by writing a single bit to any of the clock bits.

 

Thanks. The question is what if you don't need a value other than the initially programmed? Do you still need to change something in the clock register or can you just clear the interrupt (SBO 3) and it will generate another one? Nouspikel says "The decrementer will not generate any more interrupts after that one, unless re-enabled by entering and exiting timer mode.", is that correct?

Link to comment
Share on other sites

Maybe write a sample program?

 

[Edit: In MAME's implementation, the timer interrupt is latched. That is, it remains asserted until you clear it. For that reason, there cannot be another interrupt until you clear it. See https://github.com/mamedev/mame/blob/master/src/devices/machine/tms9901.cpp . It's already many years ago that I had a look at that piece of code.]

Edited by mizapf
Link to comment
Share on other sites

The timer will run regardless of what you do. But if you don't clear the interrupt after it happened, you'll not see any action from the 9901. It can't generate a new interrupt until you've cleared the old. But count, it will.

 

Yes that's also my understanding now. So I guess Nouspikel's page is wrong or at least confusing.

Link to comment
Share on other sites

Isn't that difficult since the interrupt is hardwired to the cassette ISR?

 

No, the interrupt is not hardwired, since after the 9901 there is only the INTREQ* line of the 9900, and there you cannot tell where the interrupt came from. But you're partly right ... there is another issue.

 

Have a look at the interrupt handler:

 

 

0900:     LIMI >0000
0904:     LWPI >83E0
0908:     CLR  R12
090A:     COC  @>0032,R14
090E:     JNE  >0914
0910:     B    @>1404
0914:     TB   2
0916:     JNE  >094A
0918:     LI   R12,>0F00
091C:     SBO  1
091E:     SBZ  0
0920:     AI   R12,>0100
0924:     CI   R12,>2000
0928:     JEQ  >0946
092A:     SBO  0
092C:     CB   @>4000,@>000D
0932:     JNE  >091E
0934:     MOV  @>400C,R2
0938:     JEQ  >091E
093A:     MOV  R2,R0
093C:     MOV  @>0002(R2),R2
0940:     BL   *R2
0942:     MOV  *R0,R2
0944:     JMP  >0938
0946:     B    @>0AB8
...
0AB0:     MOV  @>83C4,R12
0AB4:     JEQ  >0AB8
0AB6:     BL   *R12
0AB8:     CLR  R8
0ABA:     LWPI >83C0
0ABE:     RTWP

 

The handler decides that it is a cassette interrupt by checking the flag in R14 (090A). This is set when the cassette routine is initialized. So suppose you trigger the counter interrupt outside of the cassette routine (without setting that bit in R14), then this handler will be called. It finds the bit reset and continues with 0914. There it checks whether it was the VDP. Since it was the decrementer, it continues at 0918 and searches through the DSRs for ISRs. When done, it skips the rest and returns. It won't leave you a chance to call an own interrupt handler (0AB6).

Link to comment
Share on other sites

 

 

It won't leave you a chance to call an own interrupt handler (0AB6).

 

Well, there's this solution on Nouspikel's site, but I haven't tried it:

 

 

 

Jeff Brown's solutionThis solution was suggested to me by Jeff Brown, the man behind the interrupt mod. His idea is very elegant: if we fail to acknowledge VDP interrupts any further interrupt will be considered as VDP, so we could use the "interrupt hook" address >83C4 to branch to our own routine after any interrupt type. Only problem: VDP interrupts are acknowledged by the ISR in the console ROMs, and this is done before it calls our routine. Fortunately, there is a way out: reseting the interrupt is done by reading the VDP status at >8802, which is coded as MOVB @>FC00(R15),@>837B in the console ROMs. R15 in the GPL workspace contains the address of the VDP "read address" port >8C02. So all we need to do is to scramble this value, and the console ISR won't be able to clear interrupts any longer.

Of course, there are unwanted side-effects to this techniques:

  • We won't be able to detect genuine VDP interrupts. So if you need automated sound list processing, sprite automotion, or a functional <quit> key, you'll have to code these within your program.
  • Any routine that expects to find >8C02 in R15 of the GPL workspace won't work properly. This may include some of the routines in the console ROMs (such as the GPL intepreter). Again, you will need to have your own version of these if you need them.
This being said, click here for a complete listing of Jeff's solution.

Link to comment
Share on other sites

Jeff Brown's interrupt solution is the basis for how I implemented TIMXT's RS232 ring buffer. The result was being able to capture incoming data at 38.4K. I haven't used the 9901 timer aspect (yet) but that is on my list for keyboard buffering and some simple sound generation. So yes, the solution is viable (edit: to the extent that I have tested and used it with the external bus interrupts)

 

For Disk IO, I restore R15 and make a few adjustments to DSRLNK before calling the DSR.

Edited by InsaneMultitasker
Link to comment
Share on other sites

JS99er.net version 5.12 now has support for loading from and saving to CS1. The file format is audio 'wav' files that should be compatible with real hardware. Loading of files from other sources works best if the background noise level is low. I have not tried it with lots of files yet, but it works with many of the files from ftp://ftp.whtech.com/Cassettes/rawWAVfilesincluding the attached.

 

I have tried to implement this without cheating too much. The original ROM routines are used for saving and loading but I had to patch a few bytes to control the timing. I'm also doing some processing of audio samples in order to implement the CRU interface for reading from and writing to the tape. While the audio you hear is provided in real time the CRU read interface is only making bits (or flux changes) available on demand, so the TI may finish loading before the audio has ended and vice versa.

 

 

3DLABY.wav

  • Like 5
Link to comment
Share on other sites

I tried to load a wav file into a real TI from the ear plug of a PC, but even though I turned the volume up to 100% there was no audio on the TI. I think I managed to do this a few years ago, but I don't remember if there was some trick to make it work?

 

the pc plug is stereo, the ti is mono, you may have to pull it out "a bit" to get audio.. or use a stereo to mono adapter .. I use a stereo to rca adapter then rca to mono on one channel to ensure one signal

Link to comment
Share on other sites

 

the pc plug is stereo, the ti is mono, you may have to pull it out "a bit" to get audio.. or use a stereo to mono adapter .. I use a stereo to rca adapter then rca to mono on one channel to ensure one signal

I wonder if the radio shack cassette adaptor I have does that on its own. I just used my cell phone to load up a cassette game "Dealer" from the other topic and it worked, I heard the audio also. Or possibly that my VLC player plays mono through both channels by default, I dunno but that would have thrown me for a loop as well if it didn't work.

  • Like 2
Link to comment
Share on other sites

Using alligator clips, if I connect the audio output from the PC to the tip of the jack on the white cable and the ground on the red cable I hear audio on the TI. Likewise if I connect to the red tip and white ground or to the two tips. But if i connect to the white tip and the white ground I don't hear anything. The audio is not very load in any case and I'm getting read errors. Could there be a problem with my cable? It looks like a genuine TI cable.

Link to comment
Share on other sites

do you have a cassette tape player to test with? I've found some soundcards put out lousy sound/volume

 

No I don't have a cassette player, but I have just ordered one from ebay.

 

I do believe the output volume from my PC is too low, but I'm more confused about why I need to swap the connections to get any audio?

 

I would really like to be able to load my 4K game into a real TI from cassette, it's so authentic. :)

Link to comment
Share on other sites

 

No I don't have a cassette player, but I have just ordered one from ebay.

 

I do believe the output volume from my PC is too low, but I'm more confused about why I need to swap the connections to get any audio?

 

I would really like to be able to load my 4K game into a real TI from cassette, it's so authentic. :)

 

I seem to remember a thread where this was discussed and ISTR a problem with the grounds.

 

...lee

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