Tuesday, 19 November 2024

The Mythical Mac 256K

Introduction

This MacGUI blog post covers the boot process for the early System Software on a Mac 512K (or Mac 128K). In part of it, he talks about the Mythical Mac 256K.

At the beginning of the boot blocks are several stored parameters. The version number is two bytes. Another two bytes hold flags for the secondary sound and video pages. Then come a series of seven, 16-byte long file names. These are the names of the System resource file, Finder (or shell), debugger, disassembler, startup screen, initial application to run, and clipboard.

Following the names is a value for how many open files there may be at once, and the event queue size. Then come three, 4-byte values which are system heap size for a Mac with 128K of RAM, 256K, and 512K of RAM, respectively. If you could find me a Mac with 256K of RAM, I'd sure be impressed.  Wink

<snip>

If you landed from planet Krypton with a Mac 256K, your system heap size would be $8000 (decimal 32,768).

Disappointingly, as he also covers in this blog post, the 64K ROM only checks for the 128K or 512K Mac models and the 128kB model memory size is defined explicitly by the line:

4002E4: LEA $0001FFFC,A1 ;128K RAM

The tests work by exploiting incomplete memory decoding on early Macs. A Mac 128K's memory appears to be duplicated 4 times (actually it's duplicated 32 times all the way up to 4MB); whereas a Mac 256K is duplicated twice and a Mac 512K's memory doesn't get duplicated at all (up to 512K).

First (Failed) Attempt

I took a 64K Mac ROM and changed it to $0003FFFC, then added 2 to the 3rd byte of the ROM checksum to adjust it, which is in the first long word of the ROM. Then I added a miniVMac option for a Mac 256K, hacking about with a few scripts and some of the source code. I thought I'd correctly achieved a 256kB Mac, but I hadn't - for my 19kB MacWrite test document I had misread the MacWrite splash screen, which says how much memory is free, and used. I'd mistaken 'free' and 'used' for each other, because the values were fairly plausible for a Mac 256K.



PICO-Mac

I left the problem for quite a while after that, not knowing how to test it, but also because I lost the HDMI cable adapter for the Raspberry Pi 5 I was developing it on. Then Matt Evans referenced my post on his Axio.ms blog when creating a Raspberry Pi Pico based Mac emulator. I myself have another design for a PICO-based Mac, which would be able to fit the entire 68K emulator in its 16kB of SPI flash cache and still run at full-speed, allowing for a full 256kB of RAM on a standard PICO. This is for the future, if ever.

PCE-Mac Emulator

The key to being able to solve the problem is to use the PCE-Mac emulator, which has a step-time debugger, allowing me to figure out what really went wrong. 

What it looks like is this: Apple originally wanted to be able to support a 128KB, 512KB Mac, or a 256KB Mac at least for development purposes. Perhaps some of the engineers wanted to be able to bolt on another 128KB just for a bit more space. That made sense in 1983, because 256kBit RAM chips didn't yet exist and a 512kB Mac would need 64 RAM chips; whereas a 256kB Mac would only need 32. 

However, either they made a mistake in the ROM, which they tried, but failed to correct in the disk Boot block, which prevented them from doing that. The ROM itself is at fault, because a 256kB Mac will look like a 512kB Mac to the ROM. Here's the ROM code that works it out:

FindMemSize:;
4002DE:LEA $7FFFC,A0; 512K RAM
4002E4:LEA $1FFFC,A1; 128K RAM
4002EA:CLR.L (A0)+
4002EC:TST.L (A1)+
4002EE:BNE.S 4002F2; branch if 512K
4002F0:MOVE.L A1,A0; this is a 128K machine
4002F2:MOVE.L A0,$0108; set MemTop

A0 is set to point to the last word of a Mac 512K and A1, the last word of a Mac 128K. Initially all the RAM is set to $ffffffff. At $4002EA, the last word of a 512K machine is cleared and then the last word of the Mac 128K is tested. On a Mac 512K it won't be clear, so it won't be 0, so it'll branch and A0 will be used as is to define MemTop. On a Mac 128K it will be clear so it will be 0. It won't branch and so A1 (=128K) will be copied to A0 and then used for MemTop.

However, on a Mac 256K, the long word at $1FFFC also won't be cleared, so the ROM will think it's a Mac 512K. Nevertheless, it won't work to hack the ROM to make line 4002E4 LEA $3FFFC,A1 for a 256kB Mac, because:
  • It would mess up the ROM test for a 128KB Mac.
  • It turns out the Boot block on the Floppy Disk does its own test, explicitly for a Mac 256K and does the wrong thing if MemTop is set to 256K.
This is the critical part of the boot block:

0001008A:2238 0108MOVE.L $0108, D1
0001008E:4841SWAP D1
00010090:0C41 0004CMPI.W #$0004, D1
00010094:6E2CBGT.S $000100C2
00010096:7200MOVEQ #$00000000, D1
00010098:50F9 0001 FFF0ST $0001FFF0
0001009E:42B9 0003 FFF0CLR.L $0003FFF0
000100A4:4AB9 0001 FFF0TST.L $0001FFF0
000100AA:6716BEQ.S $000100C2
000100AC:7002MOVEQ #$00000002, D0
000100AE:4840SWAP D0
000100B0:D1B8 0108ADD.L D0, $0108
000100B4:D1B8 0824ADD.L D0, $0824
000100B8:D1B8 0266ADD.L D0, $0266
000100BC:D1B8 010CADD.L D0, $010C
000100C0:7204MOVEQ #$00000004, D1

Initially it checks for a 512kB Mac at $10090 and if it isn't falls through to the clever, but weird section at $10098 to $100A4. This code sets the top of RAM for a 128KB Mac to -1, then explicitly clears the top of RAM for a 256KB Mac and if the address at the top of a 128kB Mac has become 0, then it knows that the address range from $20000 to $3FFFF mirrored $00000 to $1FFFF and therefore it's a 128KB Mac. It will then execute the BEQ skipping the underlined code which adds $20000 to all the key system variables, starting with MemTop.

The upshot is that the boot block expects a Mac 256 to be set up as a Mac 128 in the ROM; and then the system variables are adjusted. And of course the ROM won't do that: a Mac 256 is set up as a Mac 512 in the ROM so the BGT instruction at $10094 skips the whole routine. They therefore could have fixed the boot block to check MemTop for a 512kB Mac and if it's really a Mac 256, subtract 256K from all the system variables.

Because they didn't do that, the ROM has to be changed.

A Correct ROM Fix

The answer is to save bytes on the LEA instructions. It's possible in some cases to generate large values in data registers by using the sequence MOVEQ, then SWAP. It takes just 2 words instead of 3 and because 128kB, 256kB and 512kB all have 0s in the bottom 16-bits, we can use this technique (the boot block uses this technique to test for 256kB too!). However, we need a data register to do this and I can't be sure it won't corrupt a useful data register value unless the execution path later overwrites a data register.

Fortunately, it does. At $322, there's a MOVEQ #2,d1. So, now we know we can use D1. The trick then is to set up both A1 and A0 to point to 256kB and 512kB respectively. My sequence is 1 word shorter than the original. Then, instead of clearing and testing the last words and post-incrementing to get the sizes; we pre-decrement from the sizes to get to the last words of RAM and test them. This will return the same result for both 128kB and 256kB Macs, but a different result for the 512kB Mac.

We don't need A0 and A1 now, because the actual size (for a 512kB Mac) is already in D1 so we can use our word of ROM space saved to move D1 to A0. And for the 256kB or 128kB cases, we can take the 512kB value; divide by 4 (by shifting right twice) to get 128kB, which is also a 1 word instruction substituting the MOVEA A1,A0 in the original code. This means that ROM routine now looks like this:

000002DE:7204MOVEQ #$00000004, D1
000002E0:4841SWAP D1
000002E2:2241MOVEA.L D1, A1
000002E4:D281ADD.L D1, D1
000002E6:2041MOVEA.L D1, A0
000002E8:42A0CLR.L -(A0)
000002EA:4AA1TST.L -(A1)
000002EC:6602BNE.S $000002F0
000002EE:E489LSR.L #$2, D1
000002F0:2041MOVEA.L D1, A0

We also need to make a change to the checksum again, which is a sum of the 16-bit words in the ROM. It now needs to be $28BA8FB5 instead of $28BA61CE.

Results

My 19kB MacWrite document now reports a reasonable value for a 256KB Mac:
On a Mac 512K it'd be 95%:5%. For testing purposes I wrote another program called FreeMem, which allocates 1kB blocks until it runs out of memory. The app itself uses about 260 bytes. There is a proper API for this, but I found that it wasn't reporting the value I was expecting. On a Mac 128 Freemen goes up to 75kB and on a Mac 512 it's about 430kB or more. On this Mac 256 it's 188kB:

This is only possible for a Mac 256K

In Matt Evans' blog post he said that it wasn't possible to run MacPaint on a Mac 256 disk, because it writes data to the boot blocks. I have tested this out and found that in fact it does run OK. Here's a screenshot, even though it's not actual proof since MacPaint can't tell you how much RAM is free AFAIK.

Conclusion

The Mythical Mac 256K has been talked about for a number of years and perhaps a few even existed during the early Macintosh development period. I tried, but failed to create one under the miniVmac emulator in December 2023, but after it was mentioned in Matt Evans' Pico-Mac blog and a couple more times on the 68KMLA when discussing a Pico-Mac based on the new Raspberry Pi PICO 2, I decided to explore it again. It turns out it really is possible and as far as I know, this is the first Mac 256 that actually runs, albeit in emulation!

But what's the point? Well, there's a real digital archeological purpose behind the Mac 256K, simply because the floppy disk Boot block code for System 1 up to (I believe) System 4.1 contains code for it. It seems unlikely, that someone would make the effort to create such an arcane hack if no-one considered the possibility of a Mac 256K. Nevertheless, the ROM won't allow a Mac 256K to boot properly. It is possible that a Mac 256K could have been built though, all an engineer would have to do is build a toggle-switch logically OR'd to address line A17; start up a Mac with the toggle switch connected to 5V (the Mac would then look like a Mac 128K); then flip the switch (which would enable A17, which would enable the second bank of 128K RAM) and insert a boot disk: The Boot disk would then see 256K and adjust the system variables.

The second reason is that in the 1983 to 1985 period, microcomputers with 256K of RAM were at the upper end of the market and the Mac was intended to be released in 1983 (and even before if it had been possible). The IBM PC/AT, for example was released in 1984 with 256kB as standard. A few early Atari ST's were sold with 256kB of RAM in 1985.

The third reason is that Apple already knew that the Mac 128K's RAM was limited to the point of near impracticality. MacWrite could only store a document with a few pages on it. However, a Mac 256K is far more usable. The extra 128kB of RAM can store between 16,000 to 18,000 more words in a document; enough for about 32 to 36 pages, and easily enough to store an undergraduate dissertation or a whole chapter of a book. 256K is big enough for a proper, small Pascal compiler (note: MacPascal was an interpreter); making development much more feasible.

On the downside, a Mac 256K would have needed 32 of the 64kBit chips the Mac was supplied with and this would have made the motherboard bigger, more costly and perhaps affected the shape and design of the Mac itself. The Mac 512K on the other hand, still only needed 16 RAM chips - in fact the motherboard was designed to accommodate them by simply fitting the new chips and cutting a track.

Next Steps

The 64K ROM for the Mac 256K can be downloaded from the 68KMLA thread. The next two major steps really are to use it with PICO-Mac running on a Raspberry Pi PICO 2 (which gets it closer to the hardware); and perhaps at the same time, get someone to burn the ROM and install it on a genuine Mac 128K, fitted with 256K of RAM (this is a big ask).

In the meantime I'll see if can get it to work with miniVMac and continue to work on M0̸Bius, my super-fast 68K emulator in M0+ assembler.

No comments: