CREATING THE 6-SIDE 16-SECTOR VERSION OF TOY SHOP ON THE APPLE II. (October 2014) from http://pferrie.host22.com/misc/lowlevel/lowlevel15.htm INTRODUCTION They said that it couldn't be done. It only took 28 years to achieve (not least because no-one tried(*)). Finally, we have the first ever 16-sector version, and without requiring more disks! This one was interesting in a completely different way to Prince of Persia. It seemed trivial at first, based on master side A, but became more difficult with master side B, and seemed impossible for the four sides of the two data disks. It came to my attention in November of 2013, and I started work on it in January of 2014. Work on the master disk took about two months to complete, and a complete rewrite of the read routines. No 0-days here. After a couple of months break, another month was spent on the data disks. THE EASY PART We start with Master Side A. It is loaded into memory this way: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 T00 08 68 69 6A 6B 6C T01 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 T02 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F T03 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 T04 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F ... T1C 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 T1D 1A 1B 1C 1D 1E 1F 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 T1E A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 T1F B7 B8 B9 BA BB BC BD BE BF D0 T20 E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 T21 F2 F3 F4 F5 F6 F7 F8 F9 FA T21.5 F2 F3 F4 F5 F6 F7 F8 F9 FA T22 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF Track 00 is the 18-sector loader. Tracks 01-04 are the title page. The code that is loaded to page $D0 is the Master side A copy protection. It reads track 21, track 21.5, and track 22. Any failure to read will result in a hang. To make it all fit, I had to move some sectors. There are multiple possibilities, but I did it this way: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F T00 08 68 69 6A 6B 6C T01 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F T02 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F T03 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F T04 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F ... T1C 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 T1D 18 19 1A 1B 1C 1D 1E 1F 9A 9B 9C 9D 9E 9F A0 T1E A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 T1F B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF D0 T20 E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF T21 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF That allowed me to keep the 18-sector interface code, and only the read addresses had to be changed ($32 -> $30, $52 -> $50, etc). Nothing was added. Even the copy protection at page $D0 is loaded and run, but altered to not engage the phases, leaving track $22 unused. The 18-sector tracks on master side A were probably used just for faster loading. As you can see, there was plenty of room to convert them to 16-sector tracks. THE HARD PART Now we move to Master Side B. It is the interesting one. The first two tracks are the fonts. There are four fonts, in different styles. This is the layout: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 T00 F0 F0 F0 F0 F0 F0 F0 F1 F1 F1 F1 F1 F1 F1 F1 F1 F2 F2 T01 F2 F2 F2 F2 F2 F3 F3 F3 F3 F3 F3 F3 That became 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F T00 F0 F0 F0 F0 F0 F0 F0 F1 F1 F1 F1 F1 F1 F1 F1 F1 T01 F2 F2 F2 F2 F2 F2 F2 F3 F3 F3 F3 F3 F3 F3 Toy Shop contains both a regular DOS 3.3 with RWTS, VTOC, and the 18-sector tracks. The VTOC contains a fake catalog which lists the credits, and a hidden catalog with real files that are used. One of the files is named TEDIT. TEDIT is the Text EDITor, and is the one that makes use of the fonts. This is the code that constructs the read from 18-sector tracks. The code supports reading fonts that span tracks. 5B75 A0 00 LDY #0 5B77 loc_5B77: 5B77 B9 00 DE LDA $DE00,Y 5B7A 99 9D 5B STA byte_5B9D,Y 5B7D C8 INY 5B7E C0 12 CPY #$12 5B80 90 F5 BCC loc_5B77 5B82 loc_5B82: 5B82 B9 00 DE LDA $DE00,Y 5B85 99 A3 5B STA byte_5BA3,Y 5B88 C8 INY 5B89 C0 24 CPY #$24 5B8B 90 F5 BCC loc_5B82 Since our tracks are only 16 sectors large, we only need to support 32 slots, instead of 36. 5B75 A0 00 LDY #0 5B77 loc_5B77: 5B77 B9 00 DE LDA $DE00,Y 5B7A 99 9D 5B STA byte_5B9D,Y 5B7D C8 INY 5B7E C0 12 CPY #$10 5B80 90 F5 BCC loc_5B77 5B82 loc_5B82: 5B82 B9 00 DE LDA $DE00,Y 5B85 99 A3 5B STA byte_5BA5,Y 5B88 C8 INY 5B89 C0 24 CPY #$20 5B8B 90 F5 BCC loc_5B82 Then we just add our sector read routine in place of the 18-sector read routine, and the calling convention remains the same. That was the easy one. In fact, since there's a DOS 3.3 RWTS, I just called it directly. Tracks $16+ are models and decals. They are stored in an overlapped format, such that the start of a model or decal might be inside a block that holds another model or decal. Since the sizes of the models and decals are not constant, it was too hard to separate them and move only some data to other tracks. Further hampering the effort to understand what was going on is the fact that the program is a mix of interpreted code and native code. Instead, I had to move the entire data to lower tracks. The objects are loaded via a table of track/sector pairs: 5E65 .BYTE $1F, 8 .BYTE $1F, $B .BYTE $1F, $E .BYTE $20, 0 .BYTE $20, 8 .BYTE $20, $10 .BYTE $21, 5 .BYTE $21, 8 .BYTE $21, $C 5E77 .BYTE $19, $10 .BYTE $19, $11 .BYTE $1A, 1 5E7D .BYTE $16, 9 .BYTE $16, $D .BYTE $16, $10 5E83 .BYTE $1C, $A .BYTE $1D, 0 .BYTE $1D, 8 .BYTE $1D, $E .BYTE $1E, 2 .BYTE $1E, 9 5E8F .BYTE 0 5E90 .BYTE 0 5E91 .BYTE $19, 8 .BYTE $19, $B .BYTE $19, $E 5E97 .BYTE $18, $A .BYTE $18, $D .BYTE $18, $11 .BYTE $19, 3 .BYTE $19, 4 .BYTE $19, 6 5EA3 .BYTE $16, 0 .BYTE $16, 3 .BYTE $16, 6 5EA9 .BYTE $17, 5 .BYTE $17, 9 .BYTE $17, 1 5EAF .BYTE $1A, 2 .BYTE $1A, 3 .BYTE $1A, 4 .BYTE $1A, 5 .BYTE $1A, 6 .BYTE $1A, 7 5EBB .BYTE 0 5EBC .BYTE $1A, $E .BYTE $1B, 0 .BYTE $1B, 4 5EC2 .BYTE $1B, $C .BYTE $1B, $A .BYTE $1B, 8 5EC8 .BYTE $1B, $E .BYTE $1B, $11 .BYTE $1C, 2 5ECE .BYTE $1C, 3 .BYTE $1C, 6 .BYTE $1C, 8 5ED4 .BYTE $1A, 9 .BYTE $1A, $B .BYTE $1A, $D 5EDA .BYTE $1E, $11 .BYTE $1F, 2 .BYTE $1F, 5 5EE0 .BYTE $17, $D .BYTE $18, 0 .BYTE $18, 5 5EE6 .BYTE $21, $10 .BYTE $22, 1 .BYTE $22, 4 That's a lot of extra sectors - two entire tracks worth - that are needed in order to map the result to 16 sectors... but where do we find two extra tracks? It turns out that tracks 2-8 are not referenced by anything. Even though they are in 18-sector format, it seems that they were originally intended for the models and decals during early development (at a time when SELECT was on side B, and GEDIT was on side A. We know the original location of these files because the deleted entries remain in the VTOC). After the disk layout was finalized, the tracks were left in 18-sector format. I moved the DOS files down by two tracks, overwriting some of the unused data, to make room for the new content. The resulting track/sector translation for the models and decals looks like this: 1600->1400 1601->1401 1602->1402 1603->1403 ... 160D->140D 160E->140E 160F->140F 1610->1500 1611->1501 ... 2208->2200 2209->2201 220A->2202 220B->2203 220C->2204 220D->2205 220E->2206 220F->2207 2210->2208 2211->2209 The translation table in both GENTOY (GENerate TOY, the renderer from side A) and GEDIT (Graphics EDITor, from side B) had to be changed. The tables are identical in both files, only their load address in memory is different. So we end up with a table that looks like this: 5E65 .BYTE $1E, $A .BYTE $1E, $D .BYTE $1F, 0 .BYTE $1F, 4 .BYTE $1F, $C .BYTE $20, 4 .BYTE $20, $B .BYTE $20, $E .BYTE $21, 2 5E77 .BYTE $18, 6 .BYTE $18, 7 .BYTE $18, 9 5E7D .BYTE $14, 9 .BYTE $14, $D .BYTE $15, 0 5E83 .BYTE $1B, 6 .BYTE $1B, $E .BYTE $1C, 6 .BYTE $1C, $C .BYTE $1D, 2 .BYTE $1D, 9 5E8F .BYTE 0 5E90 .BYTE 0 5E91 .BYTE $17, $E .BYTE $18, 1 .BYTE $18, 4 5E97 .BYTE $16, $E .BYTE $17, 1 .BYTE $17, 5 .BYTE $17, 9 .BYTE $18, $A .BYTE $17, $C 5EA3 .BYTE $14, 0 .BYTE $14, 3 .BYTE $14, 6 5EA9 .BYTE $15, 7 .BYTE $15, $B .BYTE $15, 3 5EAF .BYTE $18, $A .BYTE $18, $B .BYTE $18, $C .BYTE $18, $D .BYTE $18, $E .BYTE $18, $F 5EBB .BYTE 0 5EBC .BYTE $19, 6 .BYTE $19, $A .BYTE $19, $E 5EC2 .BYTE $1A, 6 .BYTE $1A, 4 .BYTE $1A, 2 5EC8 .BYTE $1A, 8 .BYTE $1A, $B .BYTE $1A, $E 5ECE .BYTE $1A, $F .BYTE $1B, 2 .BYTE $1B, 4 5ED4 .BYTE $19, 1 .BYTE $19, 3 .BYTE $19, 5 5EDA .BYTE $1E, 1 .BYTE $1E, 4 .BYTE $1E, 7 5EE0 .BYTE $15, $F .BYTE $16, 4 .BYTE $16, 9 5EE6 .BYTE $21, 6 .BYTE $21, 9 .BYTE $21, $C Then we insert the 16-sector read routines, just like for TEDIT. THE DATA DISKS The data disks contain the full-size bitmapped versions of the models, so they are really necessary. They are fully 18 sector format, and completely full. That 157kb of data per side, that need to be crammed into a 140kb format. They needed to be compressed. Fortunately, the bitmaps are read in chunks of 9 sectors at a time. It was simply a matter of compressing the content enough to convert 9x2 sectors to 8x2 sectors, and then decompressing them on demand. And there you have it. (*) in the 80s, when disk space was severely limited, and transmission costs were expensive, no-one wanted anything except games on their boards. Certainly, no-one was going to accept a graphics program for printing toys, which would have required more than three entire disks to hold the data, and several hours to download. That meant that most of the educational and graphics software were left untouched, and possibly lost forever. What a sad situation. Copyright (c) 2014 Peter Ferrie All rights reserved