From 080976fc48b03683f3ad121939ab1e1414020b05 Mon Sep 17 00:00:00 2001 From: Denis Molony Date: Sat, 8 Feb 2020 09:20:56 +1000 Subject: [PATCH] split DoubleScrunch into two --- .../diskbrowser/applefile/DoubleScrunch.java | 249 +----------------- .../applefile/DoubleScrunchCPU.java | 246 +++++++++++++++++ 2 files changed, 259 insertions(+), 236 deletions(-) create mode 100644 src/com/bytezone/diskbrowser/applefile/DoubleScrunchCPU.java diff --git a/src/com/bytezone/diskbrowser/applefile/DoubleScrunch.java b/src/com/bytezone/diskbrowser/applefile/DoubleScrunch.java index bc627ef..d25bd60 100644 --- a/src/com/bytezone/diskbrowser/applefile/DoubleScrunch.java +++ b/src/com/bytezone/diskbrowser/applefile/DoubleScrunch.java @@ -1,39 +1,21 @@ package com.bytezone.diskbrowser.applefile; -import com.bytezone.diskbrowser.utilities.CPU; - -public class DoubleScrunch extends CPU +// -----------------------------------------------------------------------------------// +public class DoubleScrunch +// -----------------------------------------------------------------------------------// { - private byte mem_71D0; // varies 1/0/1/0 ... - private byte mem_71D2; // column index * 2 (00-4F) increments every C0 bytes - private byte mem_71D3; // byte to repeat - private byte mem_71D4; // repetition counter - - private int src; // base address of packed buffer - private int dst; // base address of main/aux memory - - private byte zp_00; // input buffer offset - private byte zp_01; - - private byte zp_26; // output buffer offset - private byte zp_27; - - private byte zp_E6; // hi-res page ($20 or $40) - - // final byte[] auxBuffer = new byte[0x2000]; - // final byte[] primaryBuffer = new byte[0x2000]; final byte[][] memory = new byte[2][0x2000]; private byte[] packedBuffer; - // private final boolean debug = false; - private int count; private final int[] rows = new int[192]; private int ptr; private int bank; private int outPtr; private int column; - public DoubleScrunch () + // ---------------------------------------------------------------------------------// + public DoubleScrunch (byte[] buffer) + // ---------------------------------------------------------------------------------// { int row = 0; @@ -42,34 +24,33 @@ public class DoubleScrunch extends CPU for (int c = 0; c < 0x400; c += 0x80) for (int d = 0; d < 0x2000; d += 0x800) rows[row++] = a + b + c + d; - } - void unscrunch (byte[] buffer) - { packedBuffer = buffer; while (true) { - int rep = packedBuffer[ptr++] & 0xFF; + int repeat = packedBuffer[ptr++] & 0xFF; - if ((rep & 0x80) == 0) // repeat same byte + if ((repeat & 0x80) == 0) // repeat same byte { byte val = packedBuffer[ptr++]; - while (rep-- > 0) + while (repeat-- > 0) if (move (val)) return; } else // copy bytes { - rep &= 0x7F; - while (rep-- > 0) + repeat &= 0x7F; + while (repeat-- > 0) if (move (packedBuffer[ptr++])) return; } } } + // ---------------------------------------------------------------------------------// private boolean move (byte val) + // ---------------------------------------------------------------------------------// { memory[bank][rows[outPtr++] + column] = val; @@ -85,208 +66,4 @@ public class DoubleScrunch extends CPU } return false; } - - // no longer needed, it was used to decipher the Beagle Bros routine - void oldUnscrunch (byte[] buffer) - { - packedBuffer = buffer; - - src = 0x4000; // packed picture data - dst = 0x2000; // main/aux picture data - - zp_00 = 0x00; // load address of packed buffer - zp_01 = 0x40; - - zp_E6 = 0x20; // hi-res page 1 - - lda (zp_E6); - ora ((byte) 0x04); - zp_27 = sta (); - - ldx ((byte) 0x01); - mem_71D0 = stx (); // X and 71D0 are both set to 1 - - ldy ((byte) 0x00); - mem_71D2 = sty (); // column index = 0 - zp_26 = sty (); // output index = 0 - - while (true) - { - // get the repetition counter (hi-bit is a flag to indicate copy/repeat) - lda (packedBuffer, indirectY (src, zp_00, zp_01)); // LDA ($00),Y) - - php (); - - // increment address to get next transfer byte (done in copy/repeat routine) - zp_00 = inc (zp_00); - if (zero) - zp_01 = inc (zp_01); - - and ((byte) 0x7F); // remove copy/repeat flag - mem_71D4 = sta (); // save repetition counter (RC) - plp (); - - // copy or repeat RC bytes - if (negative ? copyBytes () : repeatBytes ()) - break; - - // increment address to get next repetition counter - zp_00 = inc (zp_00); - if (zero) - zp_01 = inc (zp_01); - } - } - - // copy a single byte RC times - private boolean repeatBytes () - { - // get the byte to store - lda (packedBuffer, indirectY (src, zp_00, zp_01)); // LDA ($00),Y) - mem_71D3 = sta (); - - while (true) - { - lda (mem_71D3); // get the byte to store - - storeByte (); // store it and decrement repetition counter - - calculateScreenColumn (); - if (carry) - return true; // completely finished - - calculateNextScreenAddress (); - - ldy (mem_71D4); // check the repetition counter - if (zero) - return false; // not finished - } - } - - // copy the next RC bytes - private boolean copyBytes () - { - while (true) - { - // get the byte to store - ldy ((byte) 0x00); - lda (packedBuffer, indirectY (src, zp_00, zp_01)); // LDA ($00),Y) - - storeByte (); // store it and decrement repetition counter - - calculateScreenColumn (); - if (carry) - return true; // completely finished - - calculateNextScreenAddress (); - - ldy (mem_71D4); // check the repetition counter - if (zero) - return false; // not finished - - // prepare address for next read - zp_00 = inc (zp_00); - if (zero) - zp_01 = inc (zp_01); - } - } - - // store the byte currently in Acc - private void storeByte () - { - mem_71D4 = dec (mem_71D4); // decrement repetition counter (RC) - ldy (mem_71D2); // column index (times 2) - - php (); - // sei (); - pha (); - tya (); - lsr (); // divide by 2, put odd/even value in carry (bank) - tay (); - pla (); - - // store byte - if (false) - System.out.printf ( - "%04X D0: %02X D2: %02X xReg: %02X bank: %d %02X -> %02X %02X + %02X%n", - count++, mem_71D0, mem_71D2, stx (), carry ? 0 : 1, sta (), zp_27, zp_26, - sty ()); - sta (memory[carry ? 1 : 0], indirectY (dst, zp_26, zp_27)); - - plp (); - } - - // $71B1 - private void calculateScreenColumn () - { - // increment X by 2 - X varies 01, 03, 05 -> BF, then 00, 02, 04 -> BE - inx (); - inx (); - cpx ((byte) 0xC0); // # screen lines - if (!carry) // X < $C0 - return; // continue current phase - - // carry is now set, current phase is finished - - // change phase - mem_71D0 = dec (mem_71D0); // either 1 -> 0, or 0 -> -1 - if (!negative) // - { - assert mem_71D0 == 0; - // start second phase of screen column - ldx ((byte) 0x00); // start X at 0 - // mem_71D0 = stx (); // phase 2 (not necessary, was already 0) - clc (); - return; // start phase 2 - } - - // start a new screen column (and start phase 1) - mem_71D2 = inc (mem_71D2); // increment column index - ldy (mem_71D2); - cpy ((byte) 0x50); // test for end of line (2 x 0x28) - if (carry) // Y >= $50 - return; // program finished - - ldx ((byte) 0x01); // start X at 1 - mem_71D0 = stx (); // start phase 1 - clc (); - } - - // set locations $26-27 (address of first location in screen line) - private void calculateNextScreenAddress () - { - txa (); - and ((byte) 0xC0); // get 2 hi bits - 00/40/80 - zp_26 = sta (); - - lsr (); - lsr (); - ora (zp_26); // graphics page ($20 or $40) - zp_26 = sta (); - - txa (); - zp_27 = sta (); - - asl (); - asl (); - asl (); - zp_27 = rol (zp_27); - - asl (); - zp_27 = rol (zp_27); - - asl (); - zp_26 = ror (zp_26); - - lda (zp_27); - and ((byte) 0x1F); // clear bits 7-5 - ora (zp_E6); // graphics page ($20 or $40) - zp_27 = sta (); - } - - @Override - protected String debugString () - { - return String.format ("0: %02X %02X 26: %02X %02X %02X %02X %02X %02X", zp_00, - zp_01, zp_26, zp_27, mem_71D0, mem_71D2, mem_71D3, mem_71D4); - } } \ No newline at end of file diff --git a/src/com/bytezone/diskbrowser/applefile/DoubleScrunchCPU.java b/src/com/bytezone/diskbrowser/applefile/DoubleScrunchCPU.java new file mode 100644 index 0000000..eb3f4d6 --- /dev/null +++ b/src/com/bytezone/diskbrowser/applefile/DoubleScrunchCPU.java @@ -0,0 +1,246 @@ +package com.bytezone.diskbrowser.applefile; + +import com.bytezone.diskbrowser.utilities.CPU; + +// -----------------------------------------------------------------------------------// +public class DoubleScrunchCPU extends CPU +// -----------------------------------------------------------------------------------// +{ + private byte mem_71D0; // varies 1/0/1/0 ... + private byte mem_71D2; // column index * 2 (00-4F) increments every C0 bytes + private byte mem_71D3; // byte to repeat + private byte mem_71D4; // repetition counter + + private int src; // base address of packed buffer + private int dst; // base address of main/aux memory + + private byte zp_00; // input buffer offset + private byte zp_01; + + private byte zp_26; // output buffer offset + private byte zp_27; + + private byte zp_E6; // hi-res page ($20 or $40) + + final byte[][] memory = new byte[2][0x2000]; + private byte[] packedBuffer; + + private int count; + + // ---------------------------------------------------------------------------------// + void unscrunch (byte[] buffer) + // ---------------------------------------------------------------------------------// + { + packedBuffer = buffer; + + src = 0x4000; // packed picture data + dst = 0x2000; // main/aux picture data + + zp_00 = 0x00; // load address of packed buffer + zp_01 = 0x40; + + zp_E6 = 0x20; // hi-res page 1 + + lda (zp_E6); + ora ((byte) 0x04); + zp_27 = sta (); + + ldx ((byte) 0x01); + mem_71D0 = stx (); // X and 71D0 are both set to 1 + + ldy ((byte) 0x00); + mem_71D2 = sty (); // column index = 0 + zp_26 = sty (); // output index = 0 + + while (true) + { + // get the repetition counter (hi-bit is a flag to indicate copy/repeat) + lda (packedBuffer, indirectY (src, zp_00, zp_01)); // LDA ($00),Y) + + php (); + + // increment address to get next transfer byte (done in copy/repeat routine) + zp_00 = inc (zp_00); + if (zero) + zp_01 = inc (zp_01); + + and ((byte) 0x7F); // remove copy/repeat flag + mem_71D4 = sta (); // save repetition counter (RC) + plp (); + + // copy or repeat RC bytes + if (negative ? copyBytes () : repeatBytes ()) + break; + + // increment address to get next repetition counter + zp_00 = inc (zp_00); + if (zero) + zp_01 = inc (zp_01); + } + } + + // copy a single byte RC times + // ---------------------------------------------------------------------------------// + private boolean repeatBytes () + // ---------------------------------------------------------------------------------// + { + // get the byte to store + lda (packedBuffer, indirectY (src, zp_00, zp_01)); // LDA ($00),Y) + mem_71D3 = sta (); + + while (true) + { + lda (mem_71D3); // get the byte to store + + storeByte (); // store it and decrement repetition counter + + calculateScreenColumn (); + if (carry) + return true; // completely finished + + calculateNextScreenAddress (); + + ldy (mem_71D4); // check the repetition counter + if (zero) + return false; // not finished + } + } + + // copy the next RC bytes + // ---------------------------------------------------------------------------------// + private boolean copyBytes () + // ---------------------------------------------------------------------------------// + { + while (true) + { + // get the byte to store + ldy ((byte) 0x00); + lda (packedBuffer, indirectY (src, zp_00, zp_01)); // LDA ($00),Y) + + storeByte (); // store it and decrement repetition counter + + calculateScreenColumn (); + if (carry) + return true; // completely finished + + calculateNextScreenAddress (); + + ldy (mem_71D4); // check the repetition counter + if (zero) + return false; // not finished + + // prepare address for next read + zp_00 = inc (zp_00); + if (zero) + zp_01 = inc (zp_01); + } + } + + // store the byte currently in Acc + // ---------------------------------------------------------------------------------// + private void storeByte () + // ---------------------------------------------------------------------------------// + { + mem_71D4 = dec (mem_71D4); // decrement repetition counter (RC) + ldy (mem_71D2); // column index (times 2) + + php (); + // sei (); + pha (); + tya (); + lsr (); // divide by 2, put odd/even value in carry (bank) + tay (); + pla (); + + if (false) + System.out.printf ( + "%04X D0: %02X D2: %02X xReg: %02X bank: %d %02X -> %02X %02X + %02X%n", + count++, mem_71D0, mem_71D2, stx (), carry ? 0 : 1, sta (), zp_27, zp_26, + sty ()); + + // store byte + sta (memory[carry ? 1 : 0], indirectY (dst, zp_26, zp_27)); + plp (); + } + + // $71B1 + // ---------------------------------------------------------------------------------// + private void calculateScreenColumn () + // ---------------------------------------------------------------------------------// + { + // increment X by 2 - X varies 01, 03, 05 -> BF, then 00, 02, 04 -> BE + inx (); + inx (); + cpx ((byte) 0xC0); // # screen lines + if (!carry) // X < $C0 + return; // continue current phase + + // carry is now set, current phase is finished + + // change phase + mem_71D0 = dec (mem_71D0); // either 1 -> 0, or 0 -> -1 + if (!negative) // + { + assert mem_71D0 == 0; + // start second phase of screen column + ldx ((byte) 0x00); // start X at 0 + // mem_71D0 = stx (); // phase 2 (not necessary, was already 0) + clc (); + return; // start phase 2 + } + + // start a new screen column (and start phase 1) + mem_71D2 = inc (mem_71D2); // increment column index + ldy (mem_71D2); + cpy ((byte) 0x50); // test for end of line (2 x 0x28) + if (carry) // Y >= $50 + return; // program finished + + ldx ((byte) 0x01); // start X at 1 + mem_71D0 = stx (); // start phase 1 + clc (); + } + + // set locations $26-27 (address of first location in screen line) + // ---------------------------------------------------------------------------------// + private void calculateNextScreenAddress () + // ---------------------------------------------------------------------------------// + { + txa (); + and ((byte) 0xC0); // get 2 hi bits - 00/40/80 + zp_26 = sta (); + + lsr (); + lsr (); + ora (zp_26); // graphics page ($20 or $40) + zp_26 = sta (); + + txa (); + zp_27 = sta (); + + asl (); + asl (); + asl (); + zp_27 = rol (zp_27); + + asl (); + zp_27 = rol (zp_27); + + asl (); + zp_26 = ror (zp_26); + + lda (zp_27); + and ((byte) 0x1F); // clear bits 7-5 + ora (zp_E6); // graphics page ($20 or $40) + zp_27 = sta (); + } + + // ---------------------------------------------------------------------------------// + @Override + protected String debugString () + // ---------------------------------------------------------------------------------// + { + return String.format ("0: %02X %02X 26: %02X %02X %02X %02X %02X %02X", zp_00, + zp_01, zp_26, zp_27, mem_71D0, mem_71D2, mem_71D3, mem_71D4); + } +}