dmolony-DiskBrowser/src/com/bytezone/diskbrowser/applefile/DoubleScrunch.java

292 lines
7.7 KiB
Java
Raw Normal View History

2017-01-08 23:36:10 +00:00
package com.bytezone.diskbrowser.applefile;
import com.bytezone.diskbrowser.utilities.CPU;
public class DoubleScrunch extends CPU
{
private byte mem_71D0; // varies 1/0/1/0 ...
private byte mem_71D2; // column index * 2 (00-4F) increments every C0 bytes
2017-01-09 09:21:02 +00:00
private byte mem_71D3; // byte to repeat
private byte mem_71D4; // repetition counter
2017-01-08 23:36:10 +00:00
private int src; // base address of packed buffer
private int dst; // base address of main/aux memory
2017-01-09 09:21:02 +00:00
private byte zp_00; // input buffer offset
2017-01-08 23:36:10 +00:00
private byte zp_01;
2017-01-09 09:21:02 +00:00
private byte zp_26; // output buffer offset
2017-01-08 23:36:10 +00:00
private byte zp_27;
2017-01-09 09:21:02 +00:00
private byte zp_E6; // hi-res page ($20 or $40)
2017-01-08 23:36:10 +00:00
// final byte[] auxBuffer = new byte[0x2000];
// final byte[] primaryBuffer = new byte[0x2000];
final byte[][] memory = new byte[2][0x2000];
2017-01-08 23:36:10 +00:00
private byte[] packedBuffer;
2018-04-25 20:41:03 +00:00
// 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;
2017-01-08 23:36:10 +00:00
public DoubleScrunch ()
{
int row = 0;
for (int a = 0x400; a >= 0; a -= 0x400) // reversed!
for (int b = 0; b < 0x78; b += 0x28)
for (int c = 0; c < 0x400; c += 0x80)
for (int d = 0; d < 0x2000; d += 0x800)
rows[row++] = a + b + c + d;
2017-01-08 23:36:10 +00:00
}
void unscrunch (byte[] buffer)
{
packedBuffer = buffer;
while (true)
{
int rep = packedBuffer[ptr++] & 0xFF;
if ((rep & 0x80) == 0) // repeat same byte
{
byte val = packedBuffer[ptr++];
while (rep-- > 0)
if (move (val))
return;
}
else // copy bytes
{
rep &= 0x7F;
while (rep-- > 0)
if (move (packedBuffer[ptr++]))
return;
}
}
}
private boolean move (byte val)
{
memory[bank][rows[outPtr++] + column] = val;
if (outPtr % 192 == 0) // screen column for this bank is finished
{
outPtr = 0;
if (++bank > 1) // both banks are finished
{
bank = 0;
if (++column >= 40) // whole screen is finished
return true;
}
}
return false;
}
// no longer needed, it was used to decipher the Beagle Bros routine
void oldUnscrunch (byte[] buffer)
{
packedBuffer = buffer;
2017-01-08 23:36:10 +00:00
src = 0x4000; // packed picture data
dst = 0x2000; // main/aux picture data
2017-01-09 09:21:02 +00:00
zp_00 = 0x00; // load address of packed buffer
2017-01-08 23:36:10 +00:00
zp_01 = 0x40;
2017-01-09 09:21:02 +00:00
2017-01-08 23:36:10 +00:00
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
2017-01-08 23:36:10 +00:00
ldy ((byte) 0x00);
mem_71D2 = sty (); // column index = 0
2017-01-09 09:21:02 +00:00
zp_26 = sty (); // output index = 0
2017-01-08 23:36:10 +00:00
while (true)
{
2017-01-09 09:21:02 +00:00
// get the repetition counter (hi-bit is a flag to indicate copy/repeat)
2017-01-08 23:36:10 +00:00
lda (packedBuffer, indirectY (src, zp_00, zp_01)); // LDA ($00),Y)
php ();
2017-01-09 09:21:02 +00:00
// increment address to get next transfer byte (done in copy/repeat routine)
2017-01-08 23:36:10 +00:00
zp_00 = inc (zp_00);
if (zero)
zp_01 = inc (zp_01);
2017-01-09 09:21:02 +00:00
and ((byte) 0x7F); // remove copy/repeat flag
mem_71D4 = sta (); // save repetition counter (RC)
2017-01-08 23:36:10 +00:00
plp ();
// copy or repeat RC bytes
2017-01-09 09:21:02 +00:00
if (negative ? copyBytes () : repeatBytes ())
2017-01-09 06:24:53 +00:00
break;
2017-01-08 23:36:10 +00:00
// increment address to get next repetition counter
2017-01-08 23:36:10 +00:00
zp_00 = inc (zp_00);
if (zero)
zp_01 = inc (zp_01);
}
}
// copy a single byte RC times
2017-01-09 09:21:02 +00:00
private boolean repeatBytes ()
2017-01-08 23:36:10 +00:00
{
2017-01-09 09:21:02 +00:00
// get the byte to store
2017-01-08 23:36:10 +00:00
lda (packedBuffer, indirectY (src, zp_00, zp_01)); // LDA ($00),Y)
mem_71D3 = sta ();
2017-01-09 09:21:02 +00:00
while (true)
2017-01-08 23:36:10 +00:00
{
2017-01-09 09:21:02 +00:00
lda (mem_71D3); // get the byte to store
2017-01-08 23:36:10 +00:00
2017-01-09 09:21:02 +00:00
storeByte (); // store it and decrement repetition counter
2017-01-08 23:36:10 +00:00
calculateScreenColumn ();
2017-01-08 23:36:10 +00:00
if (carry)
2017-01-09 09:21:02 +00:00
return true; // completely finished
2017-01-08 23:36:10 +00:00
2017-01-09 09:21:02 +00:00
calculateNextScreenAddress ();
2017-01-08 23:36:10 +00:00
2017-01-09 09:21:02 +00:00
ldy (mem_71D4); // check the repetition counter
if (zero)
return false; // not finished
}
2017-01-08 23:36:10 +00:00
}
// copy the next RC bytes
2017-01-09 09:21:02 +00:00
private boolean copyBytes ()
2017-01-08 23:36:10 +00:00
{
while (true)
{
2017-01-09 09:21:02 +00:00
// get the byte to store
2017-01-08 23:36:10 +00:00
ldy ((byte) 0x00);
lda (packedBuffer, indirectY (src, zp_00, zp_01)); // LDA ($00),Y)
2017-01-09 09:21:02 +00:00
storeByte (); // store it and decrement repetition counter
2017-01-08 23:36:10 +00:00
calculateScreenColumn ();
2017-01-08 23:36:10 +00:00
if (carry)
2017-01-09 09:21:02 +00:00
return true; // completely finished
2017-01-08 23:36:10 +00:00
2017-01-09 09:21:02 +00:00
calculateNextScreenAddress ();
2017-01-08 23:36:10 +00:00
2017-01-09 09:21:02 +00:00
ldy (mem_71D4); // check the repetition counter
2017-01-08 23:36:10 +00:00
if (zero)
2017-01-09 09:21:02 +00:00
return false; // not finished
2017-01-08 23:36:10 +00:00
2017-01-09 09:21:02 +00:00
// prepare address for next read
2017-01-08 23:36:10 +00:00
zp_00 = inc (zp_00);
if (zero)
zp_01 = inc (zp_01);
}
}
// store the byte currently in Acc
2017-01-08 23:36:10 +00:00
private void storeByte ()
{
mem_71D4 = dec (mem_71D4); // decrement repetition counter (RC)
ldy (mem_71D2); // column index (times 2)
2017-01-08 23:36:10 +00:00
php ();
// sei ();
2017-01-08 23:36:10 +00:00
pha ();
tya ();
lsr (); // divide by 2, put odd/even value in carry (bank)
2017-01-08 23:36:10 +00:00
tay ();
pla ();
2017-01-09 06:24:53 +00:00
// 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));
2017-01-08 23:36:10 +00:00
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)
2017-01-09 09:21:02 +00:00
private void calculateNextScreenAddress ()
2017-01-08 23:36:10 +00:00
{
txa ();
and ((byte) 0xC0); // get 2 hi bits - 00/40/80
2017-01-08 23:36:10 +00:00
zp_26 = sta ();
lsr ();
lsr ();
2017-01-09 06:24:53 +00:00
ora (zp_26); // graphics page ($20 or $40)
2017-01-08 23:36:10 +00:00
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
2017-01-09 06:24:53 +00:00
ora (zp_E6); // graphics page ($20 or $40)
2017-01-08 23:36:10 +00:00
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);
}
}