Jump to content
IGNORED

Can an emulator write .wav cassette files (higher baudrate)?


globeron

Recommended Posts

Can the emulators (Classic99, V9T9, MAME, etc.) write to a cassette file (.wav format?)

(or CS1 or TAPE99 programs?)

 

Note: the sound file is different (1200 Baud), see the tool of Tonnie Brouwer below !

 

 

Mike Hull is making 32K consoles, but I also believe there are people with only 32K built-in consoles

only (and have a cassette interface only).

(also read this article about the cassette interface TI and PC line-out: https://www.disavowed.jp/)

 

 

Now I am wondering how to get this type of .wav files to a mobile phone or mp3 player, so then people with

a 32K only built-in, can use the cassette interface to load assembly programs.

 

(it was written by Tonnie Brouwer of the TI-GG-Netherlands (Regional group in the South that time)

I used it a lot when i was a kid (but it required someone with a PEB+32K+Disk+Cassette player to help

to make those cassette tapes). https://www.facebook.com/groups/2209774843/permalink/10153373311169844/

 

Now if we can make these .wav files (for assembly programs), then a MP3 player or mobile phone can be used

(probably with the different cassette cable).

 

It need to write the sound to a cassette tape (higher baud-rates, etc):

Software: www.globeron.com/freedownload/services/TI99/TapeLoader.zip

 

If this works, then someone can use an emulator on his PC and save the higher baudrate .wav to a file and load it to his real TI using a smartphone

Edited by globeron
  • Like 1
Link to comment
Share on other sites

I just tried it on MESS, but the problem is that the cassette motor does not start, which means that the control line is not operated. When it already runs (because it has been turned on before), it is stopped with "REWIND CASSETTE TAPE", but then I only get "WORKING", and the motor stays off.

Link to comment
Share on other sites

Has anyone tried to make some similar to C64 Turbo Tape for the TI?

Apparently someone in the Netherlands did just that about twenty-five years ago.

 

I'm looking at the source code, trying to work out the protocol. Assembly language guys: how is "10 FF" (i.e., "HERE JMP HERE" supposed to work as a delay loop?

Link to comment
Share on other sites

An endless loop, which may be interrupted by a VDP interrupt, thus synchronising to the interrupt. Is there a LIMI 2 somewhere?

No, but there is a LIMI 1 in the execution path prior to the infinite loop. Path looks like this:

 

LIMI 1

L1 SETO R4 * EENEN UITGEVEN

BL @BITWR *

 

(and let's treat BITWR as if it were inline, so:)

 

BITWR DATA >10FF * IDLE

X R8 * execute >1E19

XOR @>135C,R8 * SBO

ANDI R4,>0001

JNE LA1

DATA >10FF * DATABIT = 0, VERLENG PERIODE

LA1 DATA >10FF *

X R8 * execute >1E19

XOR @>135C,R8

ANDI R4,>0001

JNE LA2

DATA >10FF

RT

LA2 DATA >10FF * DATABIT = 1, TWEEDE PERIODE

X R8 * execute >1E19

XOR @>135C,R8

DATA >10FF

X R8 * execute >1E19

XOR @>135C,R8

RT

 

(so end inline there)

 

DEC R2 * AFTELLEN

JNE L1

 

 

 

DEC R2 * AFTELLEN

JNE L1

 

Google Translate and a thirty-year-old German elective gets me through the Dutch (Dutch == Deutsch if shouted loud enough icon_smile.gif )

 

What I'm looking for is the frequency for 1 and 0. I can work it out from there. Ultimately this will be folded into my bin->tape .wav generator, I think, but Ron just wants to see it working in any way possible icon_smile.gif

Link to comment
Share on other sites

LIMI 1 is the same as LIMI 2 in the TI console. All interrupts are hard-wired to level 1.

Understood, thanks.

 

Further dumb question (I come from a 6502 and ARM background): with other architectures, an interrupt passes control through a vector set up beforehand (hence the term "interrupt handler"). On these beasties, does an interrupt just tell it to continue execution from the next instruction?

Link to comment
Share on other sites

The interrupt vectors for the TMS9900 are found at addresses 0000 + 4*level. So you have

 

 

0000: 83E0 0024
0004: 83C0 0900
0008: 83C0 0A92
...

 

The NMI (aka LOAD interrupt) has its vector at FFFC.

 

When an interrupt occurs, a context switch is performed with the given vector (new workspace pointer, new program counter). Then, the interrupt mask in the status register is decremented by 1 (which means that another interrupt may occur with a higher priority) unless it is already 0. As we don't have a way to raise level 2 interrupts, the vector at 0008 is useless, I'd say.

 

Apart from the NMI, all vectors are in ROM.

 

The interrupt context switch is the same as the one from BLWP, so you return with RTWP.

 

Ähm ... what was the question?

Link to comment
Share on other sites

Understood, thanks.

 

Further dumb question (I come from a 6502 and ARM background): with other architectures, an interrupt passes control through a vector set up beforehand (hence the term "interrupt handler"). On these beasties, does an interrupt just tell it to continue execution from the next instruction?

No, the interrupt vectors are at the beginning of ROM (level 0 reset at >000, level 1 at >0004 and level 2 at >0008). The vectors consist of a workspace address and then a code address, so the main interrupt routine runs at >0900. (And as noted, level 2 doesn't ever happen. There are 16 levels on the 9900 but the TI ROM only has those three set to anything).

 

The console interrupt routine has a lot in it, but when it decides that it was an interrupt meant for the cassette routine, it adds 2 to the return address before returning, thus breaking out of the infinite loop.

  • Like 1
Link to comment
Share on other sites

(snip)

 

Ähm ... what was the question?

"Given that code fragment, what needs to happen on the console to break that infinite loop and continue to the next instruction?"

 

(the next instruction in all cases is "X R8", with R8 being set elsewhere to >1E19, which I think is "put +5VDC into the cassette output circuitry" ROM routine)

Link to comment
Share on other sites

The console interrupt routine has a lot in it, but when it decides that it was an interrupt meant for the cassette routine, it adds 2 to the return address before returning, thus breaking out of the infinite loop.

*ding* That was exactly the answer I needed, sir. You're possibly an officer and definitely a gentleman icon_smile.gif

 

So now I need to track down what causes a cassette interrupt. Lucky for me all of the ROM routines are disassembled and commented icon_smile.gif

Link to comment
Share on other sites

*ding* That was exactly the answer I needed, sir. You're possibly an officer and definitely a gentleman

Reg force, never went past Corporal. ;)

 

which I think is "put +5VDC into the cassette output circuitry"

The output of the 9901 is not TTL compatible, so if the voltage matters as you go through this, keep in mind. My notes tell me that high off the 9901 is only 2v - I learned this after releasing a 128k mod that worked "sometimes". ;)

 

I can't seem to back that up right now, I seem to remember settling it for myself by finding the datasheet, but my local archives are far from organized.

  • Like 1
Link to comment
Share on other sites

*chuckle* I salute you anyway, even though I would theoretically outrank you based on last-held-paygrade at EAOS. That and six bucks will get me a cup of coffee ...

 

... I'm not surprised that logic 0/1 aren't at TTL levels on the TMS. It's a weird beast. SAMS schematic says voltage at mike out is 4V peak-to-peak. Close enough to TTL for Navy work icon_smile.gif

 

Edit: no it's not. Peak-to-peak, so your 2V is about right on. Needs amplification, but tape decks of the time were expecting low voltage in and had a 741-alike to compensate.

Edited by ckoba
  • Like 1
Link to comment
Share on other sites

"Given that code fragment, what needs to happen on the console to break that infinite loop and continue to the next instruction?"

 

Ah, OK, I was not quite sure about the question - yes, as Tursi explained, the interrupt routine explicitly breaks out of that infinite loop. If you have a copy of TI Intern, have a look at addresses 1404 - 1422.

  • Like 1
Link to comment
Share on other sites

Thanks so much for the replies. So far I have not been able to find Tonny Brouwer (author of DISK-->TAPE)

on the internet (we used to be in the same TI-GG Netherlands regional group many years ago, but I meet Berry Harmsen

next week maybe he knows).

 

The source code (VAR) are in the Tapeloader.dsk file (I can translate the Dutch comments if needed).

 

This solution would help people with a TI-99/4a and 32K only (e.g. built-in, or a 32K sidecar, etc.)

(and no diskdrives, no nano-PEB, no Lotharek, etc.). Not too sure how many there are there, but this topic has 165 views I just saw now.

 

Also from the Source code I saw that the special 1200 Baud is the Basicode format.

Details: http://www.sigord.co.uk/miscl/bc/basicode.htm

Background: Now I also remember that Tonny was on a radio broadcast where the standardized Basicode was

transmitted (so people could tape it from the radio and then run it on their system, e.g. MSX, etc.)

 

But the person need to have a tool (e.g. on a PC or laptop) to create this 1200 baud file into a .wav file?

(my view is that it should work in MAME/MESS and emulators, etc. as the objective is to have an emulator

which works the same as a TI-99/4a ?), but ckoba mentioned to me that is not efficient and maybe a dedicated tool is better ?

 

Tonnie used the same 1200 baud format for this tool (so that we can run Assembly programs, games, etc. on the bare TI-99+32K !)

I can video it this Wednesday when I am in Netherlands, but last August I tested it and also when I met Schmitzi we tested it again,

it all works on the real systems. Even all cassette tapes/player had no issues at all.

 

I hope I am not creating too much work here to see how to get it to work, but it brings back good memories as it opened up a whole

new world then been able to run assembly and I think it can help the community picking up the TI-99/4a again after a long time

(but they need 32K).

  • Like 1
Link to comment
Share on other sites

I just tried it on MESS, but the problem is that the cassette motor does not start, which means that the control line is not operated. When it already runs (because it has been turned on before), it is stopped with "REWIND CASSETTE TAPE", but then I only get "WORKING", and the motor stays off.

RXB has a subroutine that gives total control over CASSETTE Input and Output.

 

CALL IO(type,length,vdp-address) ! single Input/Output of Cassette.

optional

CALL IO(type,length,vdp-address,type,length,vdp-address,...) !

 

Can be used from command line or XB programs so you can from XB make your own menus and Cassette that work with any module or custom ones.

See RXB Manual IO subsection.

 

type address specifications
~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
0 ---------- GROM sound list address.
1 ---------- VDP sound list address.
2 ---------- CRU input.
3 ---------- CRU output.
4 ---------- VDP address of Cassette write list.
5 ---------- VDP address of Cassette read list.
6 ---------- VDP address of Cassette verify list.
Using CALL IO CRU input/output and Cassette motor controls from XB pretty much want ever you want is possible.
  • Like 2
Link to comment
Share on other sites

Oh, and the interrupt itself is a timer interrupt from the 9901. ;) It's assumed used only by the cassette routine, which makes it difficult-to-useless to use in our own code. ;)

 

I "liked" this. Not because I like the fact, but I like that you remind us of this.

 

I would like to stomp on the foot of the engineer or manager who came up with this idea, then kick him in the shin, the lift him back up by his booger holes. That and wiring all interrupts to level 1. What a damn sloppy messy thing to do. I would love if we could find some way to break out of the TI console ISR to use our own. Perhaps this is the next sandbox to break?

 

I think I mentioned in another thread, coming from programming the IRQ and NMI in the Commodore 64 and 128 where it is so very easy to do, this is incredibly irritating. :mad:

Link to comment
Share on other sites

The level 1 thing I /believe/ has been attributed to the original processor design having just one interrupt pin. As for the locking up of the timer interrupt... I'll lock the door while you're working on the engineer responsible. ;)

 

it /is/ possible to use it.. there are gotchas though.

 

Thierry describes two approaches here: http://www.unige.ch/medecine/nouspikel/ti99/tms9901.htm

 

For the first, he notes: "The problem is that the ISR on the TI-99/4A is written in stone, I mean in ROM. When it sees that an interrupt does not come from the VDP, it assumes (and does not check) that it comes from a peripheral card. Thus, when our timer fires, the ISR will call all interrupt routines on peripheral cards, but NOT the ISR hook at >83C4. Now, if you have an Horizon Ramdisk, or any card with RAM at >4000, this is an ideal way to simulate peripheral interrupts and/or to use the timer."

 

For the second, Jeff Brown found a trick: "This 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."

 

There's sample code for that one... and to be honest, I had forgotten about that approach. The overhead is not TOO bad, if you turn off most of the ISR processing it's just a handful of instructions before you get control. You do lose REAL VDP interrupts, but you do gain a timer... ;)

Link to comment
Share on other sites

As for the interrupt levels, 16 may have been an overkill, and obviously TI realized that. The 9995 only has five levels and only two are external, but the Geneve may indeed make use of them:

 

Level 0: RESET, NMI (aka LOAD)

Level 1: CPU pin INT1* (wired to TMS9901)

Level 2: Overflow (usually disabled), MID (macro instruction detect, or illegal operation)

Level 3: Decrementer

Level 4: CPU pin INT4*, connected to INTA* (from PEB; INTA* is also connected to the 9901)

Edited by mizapf
Link to comment
Share on other sites

Thierry describes how you can replace the system ROMs with a switchable EEPROM. Has anyone taken this one step further and made an alternative cartridge port for 'system ROM cartridges' on the outside of the console? It would be cool to able to program a game cartridge with 8K 16-bit ROM and its very own interrupt routine, or perhaps even to use the entire memory space (except for the memory mapped >8000 region).

Link to comment
Share on other sites

No, but there is a LIMI 1 in the execution path prior to the infinite loop. Path looks like this:

 

LIMI 1

L1 SETO R4 * EENEN UITGEVEN

BL @BITWR *

 

(and let's treat BITWR as if it were inline, so:)

 

BITWR DATA >10FF * IDLE

X R8 * execute >1E19

XOR @>135C,R8 * SBO

ANDI R4,>0001

JNE LA1

DATA >10FF * DATABIT = 0, VERLENG PERIODE

LA1 DATA >10FF *

X R8 * execute >1E19

XOR @>135C,R8

ANDI R4,>0001

JNE LA2

DATA >10FF

RT

LA2 DATA >10FF * DATABIT = 1, TWEEDE PERIODE

X R8 * execute >1E19

XOR @>135C,R8

DATA >10FF

X R8 * execute >1E19

XOR @>135C,R8

RT

 

(so end inline there)

 

DEC R2 * AFTELLEN

JNE L1

 

 

 

DEC R2 * AFTELLEN

JNE L1

 

Google Translate and a thirty-year-old German elective gets me through the Dutch (Dutch == Deutsch if shouted loud enough icon_smile.gif )

 

What I'm looking for is the frequency for 1 and 0. I can work it out from there. Ultimately this will be folded into my bin->tape .wav generator, I think, but Ron just wants to see it working in any way possible icon_smile.gif

 

Guys, I remember writing this! Stumbled upon this forum by accident. What do you want to know... ;-)

 

When I first started experimenting with the CRU inputs to read "the beeps from the cassette tape", I figured the format for basicode out at some point. It's pretty straightforward, with two frequencies, startbit, stopbit etc. I then applied the very same knowledge to create AFSK telex decoder, ZX-Spectrum loader, and turbo loader for the 4A. The latter was just the basicode format with less delay.

 

My friend Ton Damen (yeah, same first name) at the same time figured out the opposite direction, ie., writing to tape. What you're looking at is some highly optimized subroutine to write one bit. R8 contains the statement SBO or SBZ (set bit to one or to zero) and I use the XOR trick to convert one command into the other on the fly. The JMP statement was actually the NOP instruction. Since there doesn't seem to be any external timing, you will find that this code will generate a higher pitch on systems running at higher speed (I remember I had two crystals in my computer...).

 

Anyway, nice memory lane this is. Damn this is long ago!!

Link to comment
Share on other sites

Hi Tonny!

Luckily you found the forum, I have been trying to find you online for some time!

 

Really good memories when at the TI-GG Regio Zeeland group, remember when

Ton, David and you helped to built-in the 32K that time in 198x ?

(so many people pick up the TI-99/4A again and several with 32K built-in, but no disk drives)

 

Coincidentally I am in Netherlands this week and just taped/videod the process 3 days ago:

(very DRAFT video) http://www.globeron.com/freedownload/services/TI99/TapeStreamer.mp4

 

I have had no chance yet to load via a mobile phone or mp3 player (prob. because of the cable / headset out vs line out)

 

P.S. Saturday I am meeting Berry Harmsen in Amsterdam.

 

Ronald

  • Like 1
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...