• Please review our updated Terms and Rules here

POLY-88 emulator now available (Intel 8080 based system from 1976)

I just created a repo of my own converted tapes. I believe this may be useful in case or bit flips from various sources.

I'll keep my copies here: https://github.com/powool/poly88_software

@voidstar78 a good copy of LANDER is here: https://github.com/powool/poly88_software/blob/main/basic/LANDER.CAS

I'm looking for a clean copy of ASM G02 - I have multiple copies, but all are corrupted. I put together the best I could get, and at least it runs and lets me edit.

Let me know if you want help converting polyphase tapes. I've had pretty good luck with my setup, so far. Next I'm going to try my reel to reel tapes.
 
I remember my Dad and I fixed this - the big life has a bug where if there is working RAM just below F800H, it gets confused. I fixed my emulator to prevent writing from F000H-F800H and it works fine.
 
Quick announcement:

In the upcoming April 2026 Compute Gazette issue, there will be an article that covers parts of the POLY-88

Digital issues went out April 9th, and physical issues should be going out soon.





Neat stuff on the PolyPhase! My physical POLY-88 is at another location, so will be awhile before I can get back to it and try out on-hardware things. I do recall a couple of the tapes being labeled as Assemblers of some variety. There is an "official" TinyC tape as well (which I'm not sure how that works without a disk drive), haven't read through its manual yet.
 
I'm looking for a clean copy of ASM G02 - I have multiple copies, but all are corrupted. I put together the best I could get, and at least it runs and lets me edit.

@powool Did you disassemble the entire binary for each and compare the code?
 
@Istarian - excellent timing!

I got my ASM G02 assembler/editor working. Turns out, I had a vague memory from 50 years ago that was correct - the assembler was not tested with more than 32K of RAM in the system, so it fails to correctly detect how much memory it has. This is not surprising to me, because at the time, 8K or 16K was a lot.

So I modified the emulator to have only 32K of RAM, and the assembler can load/save/assemble small test programs just fine. I'll have to start disassembling and figure out how we patched it for >32K.

Also @voidstar78 - do you want me to convert the big life binary to a CAS file for you?
 
That's an interesting historical detail, especially considering that at least some versions versions of Microsoft BASIC appear to also limit themselves to 32K.

Imposing that sort of limit makes perfect sense if they weren't really expecting anyone to have more than that.
 
Tonight, I got a pretty clean disassembly of ASM G02 - I should be able to fix it.

Here's likely the offending code:

$3452 j3452: LHLD var_buf_end
$3455 XCHG
$3456 CALL j33d1
$3459 XCHG
$345a JNZ j3497
$345d XCHG
$345e LHLD var_mem_top
$3461 CALL cmp_hl_de
$3464 JP j348b

The JP j348b prints the error "uh oh... memory full! (you lose...)" (this is the error I get when trying to load a file when RAM goes beyond 8000H).
 
Also @voidstar78 - do you want me to convert the big life binary to a CAS file for you?


Yeah! Next weekend I should get time to try something like that. And for LANDER?



Neat you solved that ASM issue! Yea i've seen a few cases of "too much RAM" causing issues over the year. But for reference, two ASM tapes I have are (with Poly Microsystems labels):
ASM 800001 (labeled as 8K, 4.6) [ on the back is labeled DATASYST but no idea what that is yet ]
ASM 800104 (labeled as 8K 4.0 Monitor, G03 - PolyPhase format, oh the other side is labeled Byte format)

Also
BASIC SAMPLE PROGRAMS - A00, 16K (will need to load A00 BASIC first, the "Byte" version I have takes a few minutes; these are different than the Game Tape #1/#2, so no idea what these samples might be)

800102 CASHFLOW 24K, A00 BASIC (this one is labeled as being in PolyPhase format)


24K for CASHFLOW, yea that's quite a bit for 1977-ish (plus having to load it after loading A00). Not sure if it's a simulation type thing, or a more serious accounting thing.


Then also Tiny-C and PPS (Program Preparation System), which I'm not sure I can pull off. The manual talks about two version: V1 being interpreted, and V2 being compiled. I saw a demo once of running a C compiler on a C64, and that looked painful enough (plus used a disk drive). Without any "mass storage", I'm not even sure if I'll be able to do the interpreted version. But for ref, as an example of Tiny-C syntax from 1976:

- no #include, pl and gn (get number) are built in functions
- one line /* comments is odd (versus // )
- no braces (my poly-88 keyboard has braces, but maybe some other early 8080-system ddn't)
- no function prototype, so can call random before declared

1776066882123.png
 
Last edited:
Well that would pre-date the standardization of C (C89/ANSI C)!

:D

pl looks like a statement you might expect from BASIC or any other imperative programming language. No idea why they didn't just call it print, printline, or println though.

gn seems kind of strange, though. It must be a function call that takes no parameters, but still returns something (an integer?).

E.g.

Code:
guess = gn()

I guess it saves space, but imho calling it getnum would have been wise...

Without the original compiler, looking at a first edition of "The C Programming Language" (Kernighan & Ritchie, 1978?) might be helpful in comprehending any oddities.

As long as the code doesn't use arrays or has a different array syntax [ and ] could be treated as though they were { and }.

P.S.

No semicolons to terminate statements in there, either. And the function parameters are free of parentheses just like the function call.

I think back then you might have gotten some sort of implicit/default function declaration applied if one wasn't provided.

I.e. If you called random beforehand you might have gotten the following from the compiler... After all the call format provides a small amount of information.

Code:
int random(int a, int b) {
    return 0;
}
 
Last edited:
@voidstar78 - check out https://github.com/powool/poly88_software/blob/main/asm/LIFE.CAS and https://github.com/powool/poly88_software/blob/main/basic/LANDER.CAS

BASIC SAMPLE PROGRAMS is a set of games with some overlap with the game tape #1 and #2. https://github.com/powool/poly88_software/tree/main/basic/DEMO_TAPE_1 contains what I was able to get from my copy. Several of the checksums are bad, so they need more work.

I don't have a copy of CASHFLOW in front of me, but I think Bob got that converted. Don't throw away your excel just yet.
 
Well that would pre-date the standardization of C (C89/ANSI C)!

Here is a 1976 transcription of the tiny-C language

The image I have is from my 1980 printing of tiny-C, and for the most part (glancing through various pages) it seems identical to that 1976 document linked above. It has this guess-number example and the paragraphs after it explain each time. In these two cases of pl and gn, I wonder if they just wrap the existing ROM calls to do what BASIC does.

It's tough imagining the work flow of a high level language without the benefit of any mass storage. Basically your entire precious 16KB RAM (which even that was generous back then) you had to treat as a RAM drive. Every feature you add into an editor or compiler is one less byte for your user content (and takes longer to reload, and that time adds up since it probably gets unloaded after each step in the process).
 
It's tough imagining the work flow of a high level language without the benefit of any mass storage. Basically your entire precious 16KB RAM (which even that was generous back then) you had to treat as a RAM drive. Every feature you add into an editor or compiler is one less byte for your user content (and takes longer to reload, and that time adds up since it probably gets unloaded after each step in the process).

Yep. You really wouldn't be able to do that much without some form of external storage.

I would imagine that you could (at least in principle) use cassettes to store both source code and object files (OBJ) created by the compiler. The final linking phase would probably be quite tricky to accomplish without a ton of RAM or some other form of storage, though, since magnetic tape tended to be linear access only. Writing out or reading in the intermediate stuff would likely work okay (subject to storage space limitations), but anything you're modifying in real-time needs to be in ram.

The linked document you provided is for Tiny C for an ATARI 8-bit home computer and states that you need at least 48K of memory and a disk drive.
 
Hmm section 1.2.7 end of paragraph mentions "on an 8080 or PDP-11" (for tiny-c). The cassette I have is marked 1980, but I see now the printed manual I have is 1978. The ACKNOWLEDGEMENTS and INTRO 1-1 track the same, and "Paranha Fish" game (4-5) match. I'm not seeing yet a specific memory requirement (but there is a price sheet in the sleeve: $250 for tiny-c two {compiler version} and $100 for tiny-c one {interpreted version{).

The source code printing I have goes from 2000 to 30F6 (so ~4.3KB?).
 
@voidstar78 The source code in the github rep:


Appears to be a simple 'compiler' that largely reads the C source code and spits out an equivalent (hopefully) program in assembly language. Presumably you would compile it using your own assembler or maybe one they provided.

I spent some time tweaking it and trying to get it to compile under gcc (standard C89 or C99), no luck yet. And who knows what it will produce when compiled/executed as a 64-bit executable...

There are some typos present, thought which might explain the difficulty @powool had compiling it back then. But they may also have come from issues reading in his cassettes.

Lots of 'fun' examples of old C syntax and ways of doing things too. The sort of things that cause any modern compiler to complain about ad nauseam. And the obligatory inclusion of a file not in the repo folder, 'stdio.s'.

'#defin' instead of '#define'
'miltidef(...)' instead of 'multidef(...)'

No definition for wqtabsz...

Fixing up those typos in the git repo is probably a few ninutes.

Less historical authenticity, but also less compiler errors if someone want to play around with it.

---

Thankfully the Internet Archive has lots of old material, so I can go see what it wants to be using, as my playing around involved just replacing the include directive with ones that get stdint.h and stdio.h in case I got things working.

P.S.

Fun time with typographical errors (typos) back then too:

"... the compiler evaluates it with a simple 8-bit load intruciton"
DDJ - Number 48 / September 1980 / Volume 5, Issue 8 (page 5)

P.P.S

At a glance, I think this will only support a tiny subset of C without substantial extension. I suppose that explains why he called it 'Tiny C' (or 'Small C').
 
Last edited:

Ok I got the physical POLY-88 set back up. Took me awhile to re-learn which cables and such to load in from audio tape, and read in from WAV playback on another PC (took better notes this time around).

Of the ~40 tapes I have, most of them are PolyPhase format, which so far I've not been successful at loading. For regular BYTE mode, I'm using a Volume on the tape of like 4.9 (but on the WAV playback, I have to set the playback at full volume -- and it does make a difference, at 85% it wouldn't load or list any filenames while trying to load).

So your LIFE.CAS, might as well remove it - doesn't work as-is. I re-studied the script and realized, if you use .CAS I think it assumes a BASIC A00 stored format. Otherwise ("not a .CAS") it assumes a raw-binary - which case, I just needed to toss the original LIFE.BIN into the script, and it did produce a viable WAV recording. Just despite using -e it didn't autoexecute, so I still had to use the monitor to SPJC2000 (set PC to 2000) then G to run. On real hardware, each life iteration interval was ~3 seconds.


I'll try LANDER when I get more time later in the week - I have to load BASIC A00 first.


The majority of inherited tapes I have are all PolyPhase format - there is a Chess 51, Acey Ducey, Blockad, FITE, POLYSIAN, and a version of Spacewar. But ran out of time for today, will explore more later.
 
@powool


The above item on IA aggregates the articles (?) of volume 5. Number 45 (Volume 5, Issue 5) begins on pg. 188.

My impression is that it might omit cover art and other bits deemed less relevant, but it does contain the relevant article and source code.

Your uploaded file ( TINY-C.txt ) appears to be missing an entire chunk of the follow code...

Namely it has the initial comment but not the first set of defines or the following comment, while the latter set of defines is present.

Code:
/*    Define the "while" statement queue    */

#define    wqtabsz    100
#define    wqsiz      4
#define    wqmax      wq*wqtabsz-wqsiz

/*    Define entry offsets in while queue    */

#define    wqsym    0
#define    wqsp     1
#define    wqloop   2
#define    wqlab    3
 
@Istarian

I think I was never able to make it compile - I know I did try compiling it on a C compiler on an IBM-370, as I have some fragments of line printer listings from that. But it isn't clear to me I was ever able to run it. My memory around this is not great because my hobby interest in C moved quickly from Tiny-C to Small-C (CPM/80 product), to real C on an Apollo workstation (Unix like 68020) not long after that.

If I get my Bigboard CPM/80 machine going, I might find that I got tiny-c running on that. Although I'm not sure why I would have done that.

If the DDJ archive copy looks complete - that's surely the right place to start.
 
@powool So I had forgotten, the serial interface needs some physical switches to support PolyPhase (mode change - basically 300 to 2400 baud I think, and a phase-setting that has to match however the files were saved). My switches for that aren't hooked up, but it's just some simple jumpers. Should be easy to test on the weekend.


But quick update for today - the WAV conversion I have is working for raw-binary loads (like raw 8080 machine code, like the LIFE.BIN {and TETRIS, which was done in 8080 asm}).

But for the BASIC A00, I see PONG.CAS and LANDER.CAS are working in the emulator (after B BASIC at startup, LOAD A00, then "LOAD,PONG,B" then specify the PONG.CAS file). i.e. per the emulator, these .CAS files seem understood and loadable.

But the converter I have from .CAS to .WAV isn't converting and loading these .CAS files on the real hardware. BASIC A00 loads (from WAV), then after that the "LOAD,PONG,B" starts to load (it seems to find the start of the file), but it cancels not far into it (probably checksum error). From the header of those CAS files, the address offset seems to be 0000 (which would make sense, BASIC A00 will load the tokenized code into whatever makes sense for it) - and I made the WAVs to match that.


So - I tried dissecting the CAS itself. I believe the "8D" in the example attached is the correct 8-bit checksum for the data payload - except that doesn't match the checksum 47 value in the prior header (so it's unclear to me what the BYTE mode per packet header is including in its checksum).

Another irregularity, is all the docs I'm seeing say the SYNC block (E6's) should be 31 bytes, instead of 16. But as a sync, maybe the exact length doesn't matter (as long as it is at least 16 byte?).


Another interesting thing learned is how in this BASIC, the tokenized form of BASIC isn't using pointers to the next line. Instead each line is preceded by a number-of-bytes offset to the next line. And each tokenized BASIC ends with 0D (CR).


Again, despite the issues, these CAS archives are loading in the emulator - but after converting them to WAV, the WAV versions aren't loading on hardware.
 

Attachments

  • CAS_dissect1.jpg
    CAS_dissect1.jpg
    153.8 KB · Views: 4
  • CAS_dissect2.jpg
    CAS_dissect2.jpg
    247.5 KB · Views: 4
  • cas_p88_breakdown.txt
    cas_p88_breakdown.txt
    3.2 KB · Views: 1
Last edited:
@voidstar78 you're really into it now! One reason I haven't started up my actual hardware is that my Dad custom made a cassette tape junction board with tuning circuits, potentiometers, cables, switches and who knows what else. It's going to be a whole process to figure that out again. Now this is mostly related to our polyphase tapes, since as you (re)discovered, they are phase sensitive. In our case, we ran them at 4800BPS, which required even more fussy tuning on top of the normal fussy tuning. It's those files I'm working to recover.

Anyway, let me see...

The header is 14 bytes plus a checksum - that checksum byte is the negative sum of the preceding bytes. This means the code loading it just sums all 15 values, and if they add up to zero, the checksum is good!

The header is different every record, since it has a record number in it - this means you want to see (99% of the time) a different checksum byte for the header.

The data is the same - there is a one byte length (0 means 256 bytes in length). That many bytes are written, then a data checksum that is handled the same way as above.

The 0xE6 header byte is there to allow the tape loader code to keep resetting the UART until it sees the correct byte.

The poly 4.0 monitor reads and re-syncs until it sees an 0xE6 - once it sees that, it searches for an SOH (0x01) start of header byte. So the monitor only needs to correctly read one 0xE6 byte followed by the 0x01 byte to start loading a record. See Poly Monitor 4.0 tape header loading code

In my tape recovery code, I wait until I see 4 0xE6 bytes.

Poly seems to write 16 bytes, but I think I've seen it be longer, too. It all depends on whether you're using BASIC, ASM, SMD or something else to write the data out to tape.

Tonight (EST US Midwest), I'll see if I can try both the python script you have and my C++ code to generate a WAV file for, say, LIFE.CAS. The only thing I can do here is to use the program sox to generate a spectrum analysis - that might tell us something about what is going on.

Oh!! I can use your CAS->WAV converter and see if my tape recovery code can recover it - that'll tell me something too.

Which emulator are you using, out of curiosity?
 
Back
Top