• Please review our updated Terms and Rules here

Altair BASIC VER 2.0?

ef1j95

Experienced Member
Joined
Oct 10, 2013
Messages
145
Location
Philly, Yo
I recently had Altair BASIC VER 1.0 loading from paper tape on an IMSAI 8080. The binary came from Mike Douglas' DeRamp.com site. (Details at https://ef1j.org/wiki/index.php?n=Main.Version1). Here's a shot of the cold start routine messages:

d71e7b003e18286e.jpeg


My question is: Does anyone know if a copy of Altair BASIC Version 2 has ever been found or is available? This was the first version released by MITS (in both 4K and 8K) in late June or early July 1975. The other earlier Altair BASICs that are available currently are Version 3 (8K 3.0 on bitsavers, Mike has 3.2 for both 4K and 8K available on his site.) Those would have come out in the fall of 1975.

Eric
 
I've just found this in a bunch of other Altair & IMSAI tapes. I guess I should get it backed up!
Does anybody know which loader is needed for version 2.0?

Cheers,
Dave

IMG_20250705_115757316~2.jpg
 
Great find! Most definitely load and save the content of that tape. We can figure out the loader by examining the tape data.

Mike D
 
That's great! Thanks for finding this for the Altair community. I have posted your .tap file and made some notes for it here (see 8K BASIC Ver 2-0.tap and .txt):


I updated the bootstrap loader files for the SIO and the Cassette to reflect the fact that the 3.0 loader can be used for 2.0 as well.

Great fun to see this running on my machine this morning. Thanks again!

Mike D
 
Glad you got it running too! I ran a couple of programs on it (Primes & Mandelbrot) and it's noticeably slower than later versions.

Thanks for hosting it. Your site has been a lifesaver over the past few years when I've been working on my Altairs & IMSAI :)

Cheers,
Dave
 
If you want, send me your last name by email and I'll be glad to give you credit in the .txt file for 8K BASIC ver 2.0

deramp5113 followed by ASCII 0x40 followed by the yahoo domain

Mike
 
I downloaded the 8K_BASIC_2.zip file (available above) to try to poke around in the code to see what's there. After some confusion over the "program load records", I was able to have the actual program code make sense to me .... almost. Seems the first program load record gives the proper load address for the following block of code, but every other one of those records in the file doesn't point to the load address of the next block, but rather the last load address of the previous block. It is entirely possible that I screwed something up, but I've cross checked everything, including assembling the entire file from the .zip file and comparing the assembly output to the tape image in the .zip file. The compare was clean. I downloaded the .zip file again to check if it matched what I first downloaded. It does. I think that somebody said that they were able to load, and run, the "tape" on an actual Altair (I don't have one), and it worked. So, I gather that it is a correct representation. I'm wondering what gives? I also found that the attribution for the authors (Gates, Allen, Davidiff(sic)) misspells Monte Davidoff's name. So, I'm puzzled. Are there "glitches" in that tape image? Anybody know anything about this?

Roger
 
Thanks Mike. I grabbed a copy of Martin's write-up. It answered a lot of questions that I had, but still doesn't explain some of the contradictions I've found.

In case the disassembled code might be of interest to somebody (or if somebody wants to check my work <grin>), here is what I have. I've checked some of the CALLs and JPs and the addresses seem to be internally consistent, so far. I found that there is at least one instance of self-modifying code (at about 1092h). The comments that contain "addr." show the supposed load address from the program load records in the program image.

Roger
 

Attachments

You got the block structure wrong, it's "3C len lo hi (data) ckhsum". You had the checksum byte before the data rather than after it.
It was simple enough that I just hand-edited a hex dump to extract the binary.

And of course the loader is in reverse order in the tape, to make the boot loader just a little shorter.

Here's a simple disassembly of the loader and BASIC. Now I'm going to take some time to make a better disassembly by adding labels where I can.
 

Attachments

>>You got the block structure wrong, it's "3C len lo hi (data) ckhsum".
>> You had the checksum byte before the data rather than after it.

I found the "program load records" just as you described them. The assembler for them would be:

db 3ch
db length (always ffh except for the last block)
dw load address
db checksum.

I'll have to go back and see where I got out of sync.

Are you looking at the paper tape image posted by @Moonferret earlier in this thread?

Roger
 
Ahhh ... I see where I slipped up. The checksum for the 3rd "program load record" (which is zero) got lost in a block of zero's, so it got included in the program. Everything past that point was 1 byte too long.

Roger
 
Are you looking at the paper tape image posted by @Moonferret earlier in this thread?
Yep, and I verified the block structure by reading the loader code. (there's a commented disassembly in my uploaded zip) Your listing tosses the first data byte of each block and includes the checksum byte at the end as data, so every block is off by one. It misses the F3 (DI) at address zero of the first block, and puts a 'B' after SPC that should be a '('. I also know this is correct because INIT later writes over the jump address at 0002-0003 to change it into a warm start.

For what it's worth, the 1.0 tape dump does not do the blocks thing. After a 6A header byte it's a straight binary dump. (It also does not start with DI.) I was able to just offset my disassembler to the first byte of code, no muss no fuss.

So anyhow I'm deep into trying to relate this 2.0 code to the 3.0 code.

The non-math code is mostly recognizable compared to later versions. I had little trouble matching labels with the Bill Gates 3.0 listing.

But the floating point code is significantly different. I've seen nothing else like it, except of course in the Altair 1.0 version. It might as well be from another planet. In particular, representation of 0.5 (FHALF) is "80 40 00 00", but in 3.0 and later it is "00 00 00 80". Not only has the byte order changed, the mantissa was changed to start with an implicit "1." bit. It's also freer with self-modifying code. While the 3.0 math mostly limits itself to one block of code with four poked data bytes for FDIV (important later for ROM versions like TRS-80), the 1.0/2.0 math loves to poke opcodes. It also doesn't... do things... in the same way as the later code. It's just weird.

I found an archive link ( https://web.archive.org/web/20020102173701/http://www.rjh.org.uk/altair/ian.htm ) about an old version being discovered back in 2000, which was a printout from April 1975. It has the "STRING SPACE" text which is in 2.0 but not in 1.0. So that means that this 2.0 version would be from early 1975. The recent Bill Gates 3.0 listings are from August and September 1975. EDIT: the link says that it was a version "1.1".

So apparently they changed the floating point format between 2.0 and 3.0, sometime in mid-1975.
 
Last edited:
I can believe it. The newer code just looks more well thought out. It also tries to keep a number entirely in B,C,D,E whenever possible, so that's a big speed-up right there. This was definitely a case where starting over was a good idea. This old code also loves to use the stack, which has to be worse than just using global variables. It has a RST macro that picks up an in-line subroutine address, and then pushes the return address four bytes down the caller's stack, before going to the subroutine. Parameters on the stack is not the road to performant 8080 code.

Also I checked the 1.0 disassembly again, and noticed that 1.0 didn't use an excess-128 exponent. So that's two major differences (including the hidden mantissa bit) from what they would eventually settle upon for years. And the endian change too. I guess the 6800/6502 stayed big-endian because the 6800 was already such, and the 6502 didn't have word operands for data, only addresses, so it didn't care.
 
Back
Top