mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2024-11-26 23:51:57 +00:00
CPU emulator
This commit is contained in:
parent
abdaa41060
commit
e74e2f4a11
@ -3,6 +3,8 @@ package com.bytezone.diskbrowser.applefile;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBuffer;
|
||||
|
||||
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
||||
|
||||
public class DoubleHiResImage extends HiResImage
|
||||
{
|
||||
private static final int BLACK = 0x000000;
|
||||
@ -26,6 +28,8 @@ public class DoubleHiResImage extends HiResImage
|
||||
GRAY, PINK, MEDIUM_BLUE, LIGHT_BLUE, AQUA, WHITE };
|
||||
|
||||
private final byte[] auxBuffer;
|
||||
private DoubleScrunch doubleScrunch;
|
||||
byte[] packedBuffer;
|
||||
|
||||
public DoubleHiResImage (String name, byte[] buffer, byte[] auxBuffer)
|
||||
{
|
||||
@ -36,6 +40,44 @@ public class DoubleHiResImage extends HiResImage
|
||||
createImage ();
|
||||
}
|
||||
|
||||
public DoubleHiResImage (String name, byte[] buffer)
|
||||
{
|
||||
super (name, buffer);
|
||||
|
||||
assert name.endsWith (".PAC");
|
||||
|
||||
packedBuffer = buffer;
|
||||
doubleScrunch = new DoubleScrunch ();
|
||||
doubleScrunch.unscrunch (buffer);
|
||||
auxBuffer = doubleScrunch.auxBuffer;
|
||||
this.buffer = doubleScrunch.primaryBuffer;
|
||||
|
||||
createImage ();
|
||||
|
||||
// testes
|
||||
if (false)
|
||||
{
|
||||
byte b = -1;
|
||||
System.out.printf ("%02X %d%n", b, b);
|
||||
if (b < 0)
|
||||
System.out.println ("negative");
|
||||
b = -122;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
--b;
|
||||
System.out.printf ("%4d %02X%n", b, b);
|
||||
}
|
||||
System.out.println ();
|
||||
|
||||
b = (byte) 250;
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
++b;
|
||||
System.out.printf ("%4d %02X%n", b, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createMonochromeImage ()
|
||||
{
|
||||
@ -95,4 +137,22 @@ public class DoubleHiResImage extends HiResImage
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHexDump ()
|
||||
{
|
||||
StringBuilder text = new StringBuilder ();
|
||||
|
||||
if (packedBuffer != null)
|
||||
{
|
||||
text.append ("Packed buffer:\n\n");
|
||||
text.append (HexFormatter.format (packedBuffer));
|
||||
}
|
||||
text.append ("\n\nAuxilliary buffer:\n\n");
|
||||
text.append (HexFormatter.format (auxBuffer));
|
||||
text.append ("\n\nPrimary buffer:\n\n");
|
||||
text.append (HexFormatter.format (buffer));
|
||||
|
||||
return text.toString ();
|
||||
}
|
||||
}
|
237
src/com/bytezone/diskbrowser/applefile/DoubleScrunch.java
Normal file
237
src/com/bytezone/diskbrowser/applefile/DoubleScrunch.java
Normal file
@ -0,0 +1,237 @@
|
||||
package com.bytezone.diskbrowser.applefile;
|
||||
|
||||
import com.bytezone.diskbrowser.utilities.CPU;
|
||||
|
||||
public class DoubleScrunch extends CPU
|
||||
{
|
||||
private byte mem_71D0;
|
||||
private byte mem_71D2;
|
||||
private byte mem_71D3;
|
||||
private byte mem_71D4;
|
||||
|
||||
private int src; // base address of packed buffer
|
||||
private int dst; // base address of main/aux memory
|
||||
|
||||
private byte zp_00;
|
||||
private byte zp_01;
|
||||
private byte zp_26;
|
||||
private byte zp_27;
|
||||
private byte zp_E6;
|
||||
|
||||
final byte[] auxBuffer = new byte[0x2000];
|
||||
final byte[] primaryBuffer = new byte[0x2000];
|
||||
private byte[] packedBuffer;
|
||||
|
||||
private final boolean debug = false;
|
||||
|
||||
public DoubleScrunch ()
|
||||
{
|
||||
setDebug (debug);
|
||||
}
|
||||
|
||||
void unscrunch (byte[] buffer)
|
||||
{
|
||||
if (false)
|
||||
{
|
||||
ldx ((byte) 0x81);
|
||||
calculateScreenAddress ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
packedBuffer = buffer;
|
||||
|
||||
src = 0x4000; // packed picture data
|
||||
dst = 0x2000; // main/aux picture data
|
||||
|
||||
zp_00 = 0x00;
|
||||
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 ();
|
||||
ldy ((byte) 0x00);
|
||||
mem_71D2 = sty ();
|
||||
zp_26 = sty ();
|
||||
|
||||
while (true)
|
||||
{
|
||||
lda (packedBuffer, indirectY (src, zp_00, zp_01)); // LDA ($00),Y)
|
||||
|
||||
php ();
|
||||
zp_00 = inc (zp_00);
|
||||
if (zero)
|
||||
zp_01 = inc (zp_01);
|
||||
|
||||
and ((byte) 0x7F);
|
||||
mem_71D4 = sta ();
|
||||
plp ();
|
||||
|
||||
if (negative)
|
||||
{
|
||||
boolean finished = blockB ();
|
||||
if (finished)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
boolean finished = blockA ();
|
||||
if (finished)
|
||||
break;
|
||||
}
|
||||
|
||||
zp_00 = inc (zp_00);
|
||||
if (zero)
|
||||
zp_01 = inc (zp_01);
|
||||
}
|
||||
}
|
||||
|
||||
// $7144
|
||||
// repeat a single byte X times
|
||||
private boolean blockA ()
|
||||
{
|
||||
lda (packedBuffer, indirectY (src, zp_00, zp_01)); // LDA ($00),Y)
|
||||
mem_71D3 = sta ();
|
||||
|
||||
do
|
||||
{
|
||||
lda (mem_71D3);
|
||||
|
||||
storeByte ();
|
||||
|
||||
function_71B1 ();
|
||||
if (carry)
|
||||
return true; // completely finished
|
||||
|
||||
calculateScreenAddress ();
|
||||
ldy (mem_71D4);
|
||||
} while (!zero);
|
||||
|
||||
return false; // not finished
|
||||
}
|
||||
|
||||
// $717D
|
||||
// copy X single bytes
|
||||
private boolean blockB ()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
ldy ((byte) 0x00);
|
||||
lda (packedBuffer, indirectY (src, zp_00, zp_01)); // LDA ($00),Y)
|
||||
|
||||
storeByte ();
|
||||
|
||||
function_71B1 ();
|
||||
if (carry)
|
||||
return true; // completely finished
|
||||
|
||||
calculateScreenAddress ();
|
||||
|
||||
ldy (mem_71D4);
|
||||
if (zero)
|
||||
return false; // not finished
|
||||
|
||||
zp_00 = inc (zp_00);
|
||||
if (zero)
|
||||
zp_01 = inc (zp_01);
|
||||
|
||||
assert !zero;
|
||||
}
|
||||
}
|
||||
|
||||
private void storeByte ()
|
||||
{
|
||||
mem_71D4 = dec (mem_71D4); // decrement counter
|
||||
ldy (mem_71D2); // load byte to store
|
||||
|
||||
php ();
|
||||
sei ();
|
||||
pha ();
|
||||
tya ();
|
||||
lsr (); // divide by 2 ?
|
||||
tay ();
|
||||
pla ();
|
||||
|
||||
// switch page
|
||||
byte[] target = carry ? primaryBuffer : auxBuffer;
|
||||
sta (target, indirectY (dst, zp_26, zp_27));
|
||||
|
||||
plp ();
|
||||
}
|
||||
|
||||
// $70E8
|
||||
private void calculateScreenAddress ()
|
||||
{
|
||||
txa ();
|
||||
and ((byte) 0xC0); // clear bits 5-0
|
||||
zp_26 = sta ();
|
||||
|
||||
lsr ();
|
||||
lsr ();
|
||||
ora (zp_26);
|
||||
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);
|
||||
zp_27 = sta ();
|
||||
}
|
||||
|
||||
// $71B1
|
||||
private void function_71B1 ()
|
||||
{
|
||||
inx ();
|
||||
inx ();
|
||||
cpx ((byte) 0xC0);
|
||||
if (!carry) // BCC $71CE (if X < 0xC0)
|
||||
{
|
||||
clc ();
|
||||
return;
|
||||
}
|
||||
|
||||
mem_71D0 = dec (mem_71D0);
|
||||
if (!negative) // BPL $71C9
|
||||
{
|
||||
ldx ((byte) 0);
|
||||
mem_71D0 = stx ();
|
||||
clc ();
|
||||
return;
|
||||
}
|
||||
|
||||
mem_71D2 = inc (mem_71D2);
|
||||
ldy (mem_71D2);
|
||||
cpy ((byte) 0x50);
|
||||
if (carry) // BCS $71CF
|
||||
return; // program finished
|
||||
|
||||
ldx ((byte) 0x01);
|
||||
// bit ((byte) 0xA2); // ??
|
||||
mem_71D0 = stx ();
|
||||
clc ();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
@ -207,6 +207,8 @@ abstract class AbstractCatalogEntry implements AppleFileSource
|
||||
appleFile = new MerlinSource (name, exactBuffer);
|
||||
else if (HiResImage.isGif (exactBuffer))
|
||||
appleFile = new OriginalHiResImage (name, exactBuffer, loadAddress);
|
||||
else if (name.endsWith (".PAC"))
|
||||
appleFile = new DoubleHiResImage (name, exactBuffer);
|
||||
else if (link != null)
|
||||
{
|
||||
byte[] auxBuffer = link.disk.readSectors (link.dataSectors);
|
||||
|
@ -275,6 +275,8 @@ class FileEntry extends CatalogEntry implements ProdosConstants
|
||||
else
|
||||
file = new DoubleHiResImage (name, exactBuffer, link.getBuffer ());
|
||||
}
|
||||
else if (name.endsWith (".PAC"))
|
||||
file = new DoubleHiResImage (name, exactBuffer);
|
||||
else if ((endOfFile == 0x1FF8 || endOfFile == 0x1FFF || endOfFile == 0x2000
|
||||
|| endOfFile == 0x4000)
|
||||
&& (auxType == 0x1FFF || auxType == 0x2000 || auxType == 0x4000))
|
||||
|
358
src/com/bytezone/diskbrowser/utilities/CPU.java
Normal file
358
src/com/bytezone/diskbrowser/utilities/CPU.java
Normal file
@ -0,0 +1,358 @@
|
||||
package com.bytezone.diskbrowser.utilities;
|
||||
|
||||
public abstract class CPU
|
||||
{
|
||||
// registers
|
||||
private byte xReg;
|
||||
private byte yReg;
|
||||
private byte aReg;
|
||||
|
||||
// status register
|
||||
protected boolean carry;
|
||||
protected boolean zero;
|
||||
protected boolean interrupt;
|
||||
protected boolean decimal;
|
||||
protected boolean breakFlag;
|
||||
protected boolean overflow; // Clancy
|
||||
protected boolean negative;
|
||||
|
||||
// stack
|
||||
private final byte[] stack = new byte[0x100];
|
||||
private int sp = stack.length;
|
||||
|
||||
private boolean debug = false;
|
||||
|
||||
protected void setDebug (boolean value)
|
||||
{
|
||||
debug = value;
|
||||
}
|
||||
|
||||
protected void and (byte mask) // AND
|
||||
{
|
||||
aReg &= mask;
|
||||
zero = aReg == 0;
|
||||
negative = (aReg & 0x80) != 0;
|
||||
debug ("AND");
|
||||
}
|
||||
|
||||
protected void asl () // ASL
|
||||
{
|
||||
carry = (aReg & 0x80) != 0; // move bit 7 into the carry flag
|
||||
aReg = (byte) (aReg << 1); // shift left
|
||||
zero = aReg == 0;
|
||||
negative = (aReg & 0x80) != 0;
|
||||
debug ("ASL");
|
||||
}
|
||||
|
||||
// unfinished
|
||||
protected void bit (byte value) // BIT
|
||||
{
|
||||
byte b = (byte) (aReg & value);
|
||||
zero = b == 0;
|
||||
overflow = (value & 0x40) != 0;
|
||||
negative = (value & 0x80) != 0;
|
||||
debug ("BIT");
|
||||
}
|
||||
|
||||
protected void clc () // CLC
|
||||
{
|
||||
carry = false;
|
||||
debug ("CLC");
|
||||
}
|
||||
|
||||
protected void cli () // CLI
|
||||
{
|
||||
interrupt = false;
|
||||
debug ("CLI");
|
||||
}
|
||||
|
||||
protected void clv () // CLV
|
||||
{
|
||||
overflow = false;
|
||||
debug ("CLV");
|
||||
}
|
||||
|
||||
protected void cmp (byte value) // CMP
|
||||
{
|
||||
int tmp = (aReg & 0xFF) - (value & 0xFF);
|
||||
zero = tmp == 0;
|
||||
negative = (tmp & 0x80) != 0;
|
||||
carry = (aReg & 0xFF) >= (value & 0xFF);
|
||||
debug ("CMP");
|
||||
if (debug)
|
||||
System.out.printf (" cmp a: %02X v: %02X%n", aReg, value);
|
||||
}
|
||||
|
||||
protected void cpx (byte value) // CPX
|
||||
{
|
||||
int tmp = (xReg & 0xFF) - (value & 0xFF);
|
||||
zero = tmp == 0;
|
||||
negative = (tmp & 0x80) != 0;
|
||||
carry = (xReg & 0xFF) >= (value & 0xFF);
|
||||
debug ("CPX");
|
||||
if (debug)
|
||||
System.out.printf (" cpx x: %02X v: %02X%n", xReg, value);
|
||||
}
|
||||
|
||||
protected void cpy (byte value) // CPY
|
||||
{
|
||||
int tmp = (yReg & 0xFF) - (value & 0xFF);
|
||||
zero = tmp == 0;
|
||||
negative = (tmp & 0x80) != 0;
|
||||
carry = (yReg & 0xFF) >= (value & 0xFF);
|
||||
debug ("CPY");
|
||||
if (debug)
|
||||
System.out.printf (" cpy y: %02X v: %02X%n", yReg, value);
|
||||
}
|
||||
|
||||
protected byte dec (byte value) // DEC
|
||||
{
|
||||
value = (byte) ((value & 0xFF) - 1);
|
||||
zero = value == 0;
|
||||
negative = (value & 0x80) != 0;
|
||||
debug ("DEC");
|
||||
return value;
|
||||
}
|
||||
|
||||
protected byte inc (byte value) // INC
|
||||
{
|
||||
value = (byte) ((value & 0xFF) + 1);
|
||||
zero = value == 0;
|
||||
negative = (value & 0x80) != 0;
|
||||
debug ("INC");
|
||||
return value;
|
||||
}
|
||||
|
||||
protected void inx () // INX
|
||||
{
|
||||
xReg = (byte) ((xReg & 0xFF) + 1);
|
||||
xReg &= 0xFF;
|
||||
zero = xReg == 0;
|
||||
negative = (xReg & 0x80) != 0;
|
||||
debug ("INX");
|
||||
}
|
||||
|
||||
protected void lda (byte value) // LDA
|
||||
{
|
||||
aReg = value;
|
||||
zero = aReg == 0;
|
||||
negative = (aReg & 0x80) != 0;
|
||||
debug ("LDA");
|
||||
}
|
||||
|
||||
protected void lda (byte[] buffer, int offset) // LDA
|
||||
{
|
||||
aReg = buffer[offset];
|
||||
zero = aReg == 0;
|
||||
negative = (aReg & 0x80) != 0;
|
||||
debug ("LDA");
|
||||
}
|
||||
|
||||
protected void ldx (byte value) // LDX
|
||||
{
|
||||
xReg = value;
|
||||
zero = xReg == 0;
|
||||
negative = (xReg & 0x80) != 0;
|
||||
debug ("LDX");
|
||||
}
|
||||
|
||||
protected void ldy (byte value) // LDY
|
||||
{
|
||||
yReg = value;
|
||||
zero = yReg == 0;
|
||||
negative = (yReg & 0x80) != 0;
|
||||
debug ("LDY");
|
||||
}
|
||||
|
||||
protected void lsr () // LSR
|
||||
{
|
||||
negative = false;
|
||||
carry = (aReg & 0x01) != 0;
|
||||
aReg = (byte) ((aReg & 0xFF) >>> 1);
|
||||
zero = aReg == 0;
|
||||
debug ("LSR");
|
||||
}
|
||||
|
||||
protected void ora (byte mask) // ORA
|
||||
{
|
||||
aReg |= mask;
|
||||
zero = aReg == 0;
|
||||
negative = (aReg & 0x80) != 0;
|
||||
debug ("ORA");
|
||||
}
|
||||
|
||||
protected void php () // PHP
|
||||
{
|
||||
byte flags = 0;
|
||||
if (negative)
|
||||
flags |= 0x80;
|
||||
if (overflow)
|
||||
flags |= 0x40;
|
||||
if (breakFlag)
|
||||
flags |= 0x10;
|
||||
if (decimal)
|
||||
flags |= 0x08;
|
||||
if (interrupt)
|
||||
flags |= 0x04;
|
||||
if (zero)
|
||||
flags |= 0x02;
|
||||
if (carry)
|
||||
flags |= 0x01;
|
||||
stack[--sp] = flags;
|
||||
debug ("PHP");
|
||||
}
|
||||
|
||||
protected void plp () // PLP
|
||||
{
|
||||
byte flags = stack[sp++];
|
||||
negative = (flags & 0x80) != 0;
|
||||
overflow = (flags & 0x40) != 0;
|
||||
breakFlag = (flags & 0x10) != 0;
|
||||
decimal = (flags & 0x08) != 0;
|
||||
interrupt = (flags & 0x04) != 0;
|
||||
zero = (flags & 0x02) != 0;
|
||||
carry = (flags & 0x01) != 0;
|
||||
debug ("PLP");
|
||||
}
|
||||
|
||||
protected void pha () // PHA
|
||||
{
|
||||
stack[--sp] = aReg;
|
||||
debug ("PHA");
|
||||
}
|
||||
|
||||
protected void pla () // PLA
|
||||
{
|
||||
aReg = stack[sp++];
|
||||
zero = aReg == 0;
|
||||
negative = (aReg & 0x80) != 0;
|
||||
debug ("PLA");
|
||||
}
|
||||
|
||||
protected void rol () // ROL
|
||||
{
|
||||
boolean tempCarry = carry;
|
||||
carry = (aReg & 0x80) != 0; // move bit 7 into the carry flag
|
||||
aReg = (byte) (aReg << 1); // shift left
|
||||
if (tempCarry)
|
||||
aReg |= 0x01; // move old carry into bit 0
|
||||
zero = aReg == 0;
|
||||
negative = (aReg & 0x80) != 0;
|
||||
debug ("ROL");
|
||||
}
|
||||
|
||||
protected byte rol (byte value) // ROL
|
||||
{
|
||||
boolean tempCarry = carry;
|
||||
carry = (value & 0x80) != 0; // move bit 7 into the carry flag
|
||||
value = (byte) (value << 1);
|
||||
if (tempCarry)
|
||||
value |= 0x01; // move old carry into bit 0
|
||||
zero = value == 0;
|
||||
negative = (value & 0x80) != 0;
|
||||
debug ("ROL");
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
protected byte ror (byte value) // ROR
|
||||
{
|
||||
boolean tempCarry = carry;
|
||||
carry = (value & 0x01) != 0; // move bit 0 into the carry flag
|
||||
value = (byte) ((value & 0xFF) >>> 1);
|
||||
if (tempCarry)
|
||||
value |= 0x80; // move old carry into bit 7
|
||||
zero = value == 0;
|
||||
negative = (value & 0x80) != 0;
|
||||
debug ("ROR");
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
protected byte sta () // STA
|
||||
{
|
||||
debug ("STA");
|
||||
return aReg;
|
||||
}
|
||||
|
||||
protected void sta (byte[] buffer, int offset) // STA
|
||||
{
|
||||
buffer[offset] = aReg;
|
||||
zero = aReg == 0;
|
||||
negative = (aReg & 0x80) != 0;
|
||||
debug ("STA");
|
||||
}
|
||||
|
||||
protected byte stx () // STX
|
||||
{
|
||||
debug ("STX");
|
||||
return xReg;
|
||||
}
|
||||
|
||||
protected byte sty () // STY
|
||||
{
|
||||
debug ("STY");
|
||||
return yReg;
|
||||
}
|
||||
|
||||
protected void txa () // TXA
|
||||
{
|
||||
aReg = xReg;
|
||||
zero = aReg == 0;
|
||||
negative = (aReg & 0x80) != 0;
|
||||
debug ("TXA");
|
||||
}
|
||||
|
||||
protected void tya () // TYA
|
||||
{
|
||||
aReg = yReg;
|
||||
zero = aReg == 0;
|
||||
negative = (aReg & 0x80) != 0;
|
||||
debug ("TYA");
|
||||
}
|
||||
|
||||
protected void tax () // TAX
|
||||
{
|
||||
xReg = aReg;
|
||||
zero = xReg == 0;
|
||||
negative = (xReg & 0x80) != 0;
|
||||
debug ("TAX");
|
||||
}
|
||||
|
||||
protected void tay () // TAY
|
||||
{
|
||||
yReg = aReg;
|
||||
zero = yReg == 0;
|
||||
negative = (yReg & 0x80) != 0;
|
||||
debug ("TAY");
|
||||
}
|
||||
|
||||
protected void sei () // SEI
|
||||
{
|
||||
interrupt = true;
|
||||
debug ("SEI");
|
||||
}
|
||||
|
||||
protected abstract String debugString ();
|
||||
|
||||
protected void debug (String cmd)
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
String flags = String.format ("%s %s - %s %s %s %s %s", negative ? "1" : ".",
|
||||
overflow ? "1" : ".", breakFlag ? "1" : ".", decimal ? "1" : ".",
|
||||
interrupt ? "1" : ".", zero ? "1" : ".", carry ? "1" : ".");
|
||||
System.out.printf ("%3s A: %02X X: %02X Y: %02X %s %s%n", cmd, aReg, xReg,
|
||||
yReg, flags, debugString ());
|
||||
}
|
||||
}
|
||||
|
||||
protected int indirectY (int base, byte offset, byte page)
|
||||
{
|
||||
if (debug)
|
||||
System.out.printf ("base: %,6d, page: %02X, offset: %02X, yReg: %02X%n", base, page,
|
||||
offset, yReg);
|
||||
|
||||
return ((page & 0xFF) * 256 + (offset & 0xFF)) - base + (yReg & 0xFF);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user