Jump to content

Disassembling the Educational System Master Cartridge

Recommended Posts

I want to open up a small thread, deconstructing the Educational Master System cartridge, AKA the Dorsett Talk&Teach Master Cartridge.


It's definitely an interesting chunk of code, thus far. The cartridge itself is a 4K cartridge, that loads into $B800 ... very interesting, actually, as this definitely checks out to the earlier design of Colleen managing everything including cartridges in 4K banks.


$B800, some basic initialization code, clearing console switches, clearing and setting P/M registers based on rom table values, and setting up POKEY values (starting at AUDF1) based again on ROM table values...more to look at here.. The OS is most definitely bypassed, and POKEY is being bit-banged manually to decode the data coming in off the tape...

  • Like 1
Link to comment
Share on other sites

$B800 would be 2K... the memory management by hw inside the computer is such that 8K of system Ram still drops off the memory map.

Exception of course is the likes of Mac-65 with the bankswitching that allows selectively deselecting the entire cart if the setting + requested address is right.


Often it'll be the case that smaller than 8K Roms will replicate across the cart address space. I remember getting Gridrunner as an 8K file then looked into it and found identical 4K copies, so I just chopped the executable in half.


Strange that a cart such as this would bitbang and not utilize the OS... stuff like that lends to the theory that some software might have been developed before the OS was ready.

Link to comment
Share on other sites

Yes, 2K, derp! It's very compact, not much more than a Pokey IRQ handler, some tables, and some initialization code.


It doesn't use the OS because the OS tape routines are block oriented. The Dorsett tapes were stream oriented, very similar to MODEM transmission, where the text/commands and voice are synchronized together. Listen to the raw tape data (e.g. on Atariwiki), and you'll hear it's fairly continuous, with intermittent gaps. The effective transmission speed is about 450 bits per second, from what I'm seeing...


The original Dorsett tapes were Kansas City Standard at 300 bps.

Link to comment
Share on other sites

Interesting, I see a bit of code at $B820, which writes $69 to POTGO... Is the POT counter being used as a cycle timer, here?


And wtf? They turn right around, grab a value from the table, and write it to VCOUNT. WTF?


CHBASE seems to sit at $0C00 after initialization.

PMBASE seems to sit at $0800 after initialization.


It looks like, we have four tables, which put info into GTIA (2), POKEY, and ANTIC respectively:



$BD6D both set GTIA registers


$BD79 sets POKEY registers


$BD82 sets ANTIC registers


(yes, there is overlap, byte saving feature it looks like)


Tables are read backwards.



VIMIRQ is set to $B99C . I suspect the majority of the tape decoding is happening here.


$B840 sets up vectors to copy the system character set at $E000 to $0C00, ultimately executed by a pair of recursive subroutine calls which copy the data.


Immediately after the copy, it looks like certain characters are patched according to another table in ROM (probably for descenders, the edu cartridge uses IRG mode 3)


(it never ceases to amaze me, while I step through code in a debugger, some of the crazy weird tricks used...)



Link to comment
Share on other sites

Traced through where the display starts to show the initial screen, display list is in ROM, and a wee bit funky:



Altirra> .dumpdlist
  BD0B:      mode F @ 0700
  BD0E:      mode F
  BD0F:      mode 2 @ 0820
  BD12:      mode F @ 0700
  BD15:      mode F
  BD16:      mode 2 @ 0840
  BD19:      mode F @ 0700
  BD1C:      mode F
  BD1D:      mode 2 @ 0860
  BD20:      mode F @ 0700
  BD23:      mode F
  BD24:      mode 2 @ 0880
  BD27:      mode F @ 0700
  BD2A:      mode F
  BD2B:      mode 2 @ 08A0
  BD2E:      mode F @ 0700
  BD31:      mode F
  BD32:      mode 2 @ 08C0
  BD35:      mode F @ 0700
  BD38:      mode F
  BD39:      mode 2 @ 08E0
  BD3C:      mode F @ 0700
  BD3F:      mode F
  BD40:      mode 2 @ 0900
  BD43:      mode F @ 0700
  BD46:      mode F
  BD47:      mode 2 @ 0920
  BD4A:      mode F @ 0700
  BD4D:      mode F
  BD4E:      mode 2 @ 0940
  BD51:      mode F @ 0700
  BD54:      mode F
  BD55:      mode 2 @ 0960
  BD58:      mode F @ 0700
  BD5B:      mode F
  BD5C:      mode 2 @ 0980
  BD5F:      mode F @ 0700
  BD62:      mode F
  BD63:      mode 2 @ 09A0
  BD66:      mode F @ 0700
  BD69:      waitvbl BD00


ANTIC Status:


Altirra> .antic
DMACTL = 2d  : narrow missiles players 2-line dlist
CHACTL = 00  :
DLIST  = bd0b
NMIEN  = 00  :
NMIST  = 5f  : vbi
PENH/V = 00 00


GTIA status:



Altirra> .gtia
Player  0: color = d4, pos = 40, size=3, data = ff
Player  1: color = d4, pos = 60, size=3, data = ff
Player  2: color = d4, pos = 80, size=3, data = ff
Player  3: color = d4, pos = a0, size=3, data = ff
Missile 0: color = d4, pos = 00, size=0, data = 00
Missile 1: color = d4, pos = 00, size=0, data = 00
Missile 2: color = d4, pos = 00, size=0, data = 00
Missile 3: color = d4, pos = 00, size=0, data = 00
Playfield colors: 84 | 84 0a 84 00
PRIOR:  08 (pri= 8 , normal)
GRACTL: 03, player DMA, missile DMA
CONSOL: 08 set <-> 0f input, speaker
collision registers omitted


and finally, POKEY:



Altirra> .pokey
AUDF1: a0  AUDC1: a0  Output: 1  (228 cycles until fire) (passive: 256 cycles)
AUDF2: 0b  AUDC2: a0  Output: 1  (767 cycles until fire) (passive: 2983 cycles)
AUDF3: ce  AUDC3: a0  Output: 1
AUDF4: 05  AUDC4: a0  Output: 0
AUDCTL: 78, 17-bit poly, 1.79 ch1, 1.79 ch3, ch1+ch2, ch3+ch4, 64KHz
SEROUT: ff (done)
        shift register ff (0: done)
IRQEN:  c0, break key, keyboard
IRQST:  b7, keyboard, sertrans
Command line: negated
Link to comment
Share on other sites

and they do..so.. ok.


Looks like the IRQ routine set up is where the data decoding happens. The data is read from SERIN when ready (thanks to SKSTAT) and is subsequently EOR'ed $FF, to invert the bits. I assume as a primitive form of obfusication, but it does check out with the engineering notes that specified that Dorsett tapes must have $FF's written immediately from the leader...



Link to comment
Share on other sites

Yeah, but I wonder why? Is it to keep the number of cycles stolen somewhat consistent? Why not use blank instructions? maybe less color register messing needed when changing screens?


Yes, and what FJC said... Probably to space out the text while keeping the text and gaps color consistent. Mode F and mode 2 use the same color registers for border (COLBAK) vs the "background" of the playfield (COLPF2). Most other text and map modes and the blank line instructions use COLBAK for the playfield background, so if it used one of those mode instructions then the spacer gaps between mode 2 lines would have a different "background" than the text lines.

Link to comment
Share on other sites

It just hit me like a ton of bricks. I could write a routine to read data streamed off the tape, BUT...


(1) due to the initialization required to get POKEY into a usable state to bit bang the data, I am concerned that there would be conflicts trying to utilize CIO at the same time to write out the serialized data to disk. Am I too paranoid?


(2) There isn't enough RAM to put an entire side of a tape into memory. In fact, it would probably be just over the limit, and stopping the tape to flush a part of memory out of disk, in the middle of a flurry of data would undoubtedly introduce jitter into the output (this format _literally_ has no error correction! it's akin to a streamed MODEM transmission at about 450 baud)


decisions, decisions... nonetheless, I will try to write something that can decode the data off the tape.



Link to comment
Share on other sites

dealing with ram expansions will be a sticky point. the code inside the pokey IRQ is very tricky, and bytes need to be serviced as quickly as possible to avoid overrun. Having to juggle a bank switching mechanism in there may blow the cycle count right out of the water.



Link to comment
Share on other sites

Leader and IRG tone is all 1 on tape, possibly EOR #$FF is just to turn that to zero which would make program logic easier. Though a trail of leader won't generate SERIN data.


A write to VCOUNT is sort of strange, but might just be test code inadvertantly left in the program.

I've used such dummy writes before, it can be handy in a Ram based program - to turn the write off you just point to an unused register location.


An easier way to capture all the data might be just get the audio track into an editor. Then split it into chunks you know will fit in memory, ensuring you do the cut at a gap in the data.

Though doing bankswitching to fit in a larger Ram machine shouldn't be a problem. Tape is so slow that even bit-banging you're still receiving bits at about 1/3rd the rate a byte comes in over standard disk.

Edited by Rybags
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.

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.

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...