mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-24 04:31:02 +00:00
Added Z register support to register allocation, synthesis, fragment system, clobber and more for 65CE02 and 45GS02.
This commit is contained in:
parent
b7a6412440
commit
30b3172e7f
@ -1,4 +1,15 @@
|
||||
//KICKC FRAGMENT CACHE 15bc71afc6
|
||||
//KICKC FRAGMENT CACHE 1368a0c981
|
||||
//FRAGMENT vbuzz=vbuc1
|
||||
ldz #{c1}
|
||||
//FRAGMENT vbuzz_lt_vbuc1_then_la1
|
||||
cpz #{c1}
|
||||
bcc {la1}
|
||||
//FRAGMENT pbuc1_derefidx_vbuzz=vbuzz
|
||||
tza
|
||||
tax
|
||||
sta {c1},x
|
||||
//FRAGMENT vbuzz=_inc_vbuzz
|
||||
inz
|
||||
//FRAGMENT vbsz1=_deref_pbsc1
|
||||
lda {c1}
|
||||
sta {z1}
|
||||
@ -29,6 +40,10 @@ sta {z1}
|
||||
tya
|
||||
neg
|
||||
sta {z1}
|
||||
//FRAGMENT vbsz1=_neg_vbszz
|
||||
tza
|
||||
neg
|
||||
sta {z1}
|
||||
//FRAGMENT vbsaa=_neg_vbsz1
|
||||
lda {z1}
|
||||
neg
|
||||
@ -40,6 +55,9 @@ neg
|
||||
//FRAGMENT vbsaa=_neg_vbsyy
|
||||
tya
|
||||
neg
|
||||
//FRAGMENT vbsaa=_neg_vbszz
|
||||
tza
|
||||
neg
|
||||
//FRAGMENT vbsxx=_neg_vbsz1
|
||||
lda {z1}
|
||||
neg
|
||||
@ -55,6 +73,10 @@ tax
|
||||
tya
|
||||
neg
|
||||
tax
|
||||
//FRAGMENT vbsxx=_neg_vbszz
|
||||
tza
|
||||
neg
|
||||
tax
|
||||
//FRAGMENT vbsyy=_neg_vbsz1
|
||||
lda {z1}
|
||||
neg
|
||||
@ -70,6 +92,29 @@ tay
|
||||
tya
|
||||
neg
|
||||
tay
|
||||
//FRAGMENT vbsyy=_neg_vbszz
|
||||
tza
|
||||
neg
|
||||
tay
|
||||
//FRAGMENT vbszz=_neg_vbsz1
|
||||
lda {z1}
|
||||
neg
|
||||
taz
|
||||
//FRAGMENT vbszz=_neg_vbsaa
|
||||
neg
|
||||
taz
|
||||
//FRAGMENT vbszz=_neg_vbsxx
|
||||
txa
|
||||
neg
|
||||
taz
|
||||
//FRAGMENT vbszz=_neg_vbsyy
|
||||
tya
|
||||
neg
|
||||
taz
|
||||
//FRAGMENT vbszz=_neg_vbszz
|
||||
tza
|
||||
neg
|
||||
taz
|
||||
//FRAGMENT _deref_pbsc1=vbsaa
|
||||
sta {c1}
|
||||
//FRAGMENT vbsz1=vbsaa_ror_2
|
||||
@ -86,6 +131,11 @@ tya
|
||||
asr
|
||||
asr
|
||||
sta {z1}
|
||||
//FRAGMENT vbsz1=vbszz_ror_2
|
||||
tza
|
||||
asr
|
||||
asr
|
||||
sta {z1}
|
||||
//FRAGMENT vbsaa=vbsz1_ror_2
|
||||
lda {z1}
|
||||
asr
|
||||
@ -101,6 +151,10 @@ asr
|
||||
tya
|
||||
asr
|
||||
asr
|
||||
//FRAGMENT vbsaa=vbszz_ror_2
|
||||
tza
|
||||
asr
|
||||
asr
|
||||
//FRAGMENT vbsxx=vbsz1_ror_2
|
||||
lda {z1}
|
||||
asr
|
||||
@ -120,6 +174,11 @@ tya
|
||||
asr
|
||||
asr
|
||||
tax
|
||||
//FRAGMENT vbsxx=vbszz_ror_2
|
||||
tza
|
||||
asr
|
||||
asr
|
||||
tax
|
||||
//FRAGMENT vbsyy=vbsz1_ror_2
|
||||
lda {z1}
|
||||
asr
|
||||
@ -139,11 +198,46 @@ tya
|
||||
asr
|
||||
asr
|
||||
tay
|
||||
//FRAGMENT vbsyy=vbszz_ror_2
|
||||
tza
|
||||
asr
|
||||
asr
|
||||
tay
|
||||
//FRAGMENT vbszz=vbsz1_ror_2
|
||||
lda {z1}
|
||||
asr
|
||||
asr
|
||||
taz
|
||||
//FRAGMENT vbszz=vbsaa_ror_2
|
||||
asr
|
||||
asr
|
||||
taz
|
||||
//FRAGMENT vbszz=vbsxx_ror_2
|
||||
txa
|
||||
asr
|
||||
asr
|
||||
taz
|
||||
//FRAGMENT vbszz=vbsyy_ror_2
|
||||
tya
|
||||
asr
|
||||
asr
|
||||
taz
|
||||
//FRAGMENT vbszz=vbszz_ror_2
|
||||
tza
|
||||
asr
|
||||
asr
|
||||
taz
|
||||
//FRAGMENT vbsyy=_deref_pbsc1
|
||||
ldy {c1}
|
||||
//FRAGMENT vbszz=_deref_pbsc1
|
||||
lda {c1}
|
||||
taz
|
||||
//FRAGMENT _deref_pbsc1=vbsxx
|
||||
txa
|
||||
sta {c1}
|
||||
//FRAGMENT _deref_pbsc1=vbsyy
|
||||
tya
|
||||
sta {c1}
|
||||
//FRAGMENT _deref_pbsc1=vbszz
|
||||
tza
|
||||
sta {c1}
|
||||
|
@ -1,4 +1,4 @@
|
||||
//KICKC FRAGMENT CACHE 15bc71afc6
|
||||
//KICKC FRAGMENT CACHE 1368a0c981
|
||||
//FRAGMENT vduz1=vduc1
|
||||
lda #<{c1}
|
||||
sta {z1}
|
||||
|
@ -1,4 +1,4 @@
|
||||
//KICKC FRAGMENT CACHE 15bc71afc6
|
||||
//KICKC FRAGMENT CACHE 1368a0c981
|
||||
//FRAGMENT vbuz1=vbuc1
|
||||
lda #{c1}
|
||||
sta {z1}
|
||||
|
@ -1,12 +1,57 @@
|
||||
//KICKC FRAGMENT CACHE 15bc71afc6
|
||||
//FRAGMENT vbuz1=vbuc1
|
||||
lda #{c1}
|
||||
sta {z1}
|
||||
//KICKC FRAGMENT CACHE 1368a0c981
|
||||
//FRAGMENT pbuz1=pbuc1
|
||||
lda #<{c1}
|
||||
sta {z1}
|
||||
lda #>{c1}
|
||||
sta {z1}+1
|
||||
//FRAGMENT vbuz1=vbuc1
|
||||
lda #{c1}
|
||||
sta {z1}
|
||||
//FRAGMENT _deref_pbuz1=pbuc1_derefidx_vbuz2
|
||||
ldy {z2}
|
||||
lda {c1},y
|
||||
ldy #0
|
||||
sta ({z1}),y
|
||||
//FRAGMENT vbuz1=_inc_vbuz1
|
||||
inc {z1}
|
||||
//FRAGMENT vbuz1_neq_vbuc1_then_la1
|
||||
lda #{c1}
|
||||
cmp {z1}
|
||||
bne {la1}
|
||||
//FRAGMENT pbuz1=_inc_pbuz1
|
||||
inc {z1}
|
||||
bne !+
|
||||
inc {z1}+1
|
||||
!:
|
||||
//FRAGMENT pbuz1_lt_pbuc1_then_la1
|
||||
lda {z1}+1
|
||||
cmp #>{c1}
|
||||
bcc {la1}
|
||||
bne !+
|
||||
lda {z1}
|
||||
cmp #<{c1}
|
||||
bcc {la1}
|
||||
!:
|
||||
//FRAGMENT _deref_pbuz1=pbuc1_derefidx_vbuaa
|
||||
tay
|
||||
lda {c1},y
|
||||
ldy #0
|
||||
sta ({z1}),y
|
||||
//FRAGMENT _deref_pbuz1=pbuc1_derefidx_vbuxx
|
||||
lda {c1},x
|
||||
ldy #0
|
||||
sta ({z1}),y
|
||||
//FRAGMENT _deref_pbuz1=pbuc1_derefidx_vbuyy
|
||||
lda {c1},y
|
||||
ldy #0
|
||||
sta ({z1}),y
|
||||
//FRAGMENT vbuxx_neq_vbuc1_then_la1
|
||||
cpx #{c1}
|
||||
bne {la1}
|
||||
//FRAGMENT vbuxx=vbuc1
|
||||
ldx #{c1}
|
||||
//FRAGMENT vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//FRAGMENT vwuz1=vwuc1
|
||||
lda #<{c1}
|
||||
sta {z1}
|
||||
@ -43,12 +88,6 @@ lda {z2}
|
||||
sta {z1}
|
||||
lda {z2}+1
|
||||
sta {z1}+1
|
||||
//FRAGMENT vbuz1=_inc_vbuz1
|
||||
inc {z1}
|
||||
//FRAGMENT vbuz1_neq_vbuc1_then_la1
|
||||
lda #{c1}
|
||||
cmp {z1}
|
||||
bne {la1}
|
||||
//FRAGMENT pbuz1=pbuz2
|
||||
lda {z2}
|
||||
sta {z1}
|
||||
@ -69,11 +108,6 @@ sta {z1}+1
|
||||
lda {z2}
|
||||
ldy #0
|
||||
sta ({z1}),y
|
||||
//FRAGMENT pbuz1=_inc_pbuz1
|
||||
inc {z1}
|
||||
bne !+
|
||||
inc {z1}+1
|
||||
!:
|
||||
//FRAGMENT vbuz1=_hi_vwuz2
|
||||
lda {z2}+1
|
||||
sta {z1}
|
||||
@ -112,9 +146,6 @@ sta {z1}
|
||||
lda #{c1}
|
||||
and {z2}
|
||||
sta {z1}
|
||||
//FRAGMENT vbuxx_neq_vbuc1_then_la1
|
||||
cpx #{c1}
|
||||
bne {la1}
|
||||
//FRAGMENT _deref_pbuz1=vbuaa
|
||||
ldy #0
|
||||
sta ({z1}),y
|
||||
@ -255,8 +286,6 @@ and #{c1}
|
||||
tay
|
||||
//FRAGMENT vbuaa=vbuc1
|
||||
lda #{c1}
|
||||
//FRAGMENT vbuxx=vbuc1
|
||||
ldx #{c1}
|
||||
//FRAGMENT vbuyy=vbuc1
|
||||
ldy #{c1}
|
||||
//FRAGMENT vbuaa=pbuc1_derefidx_vbuxx
|
||||
@ -1278,8 +1307,6 @@ ldy {z1}+1
|
||||
//FRAGMENT vbuyy=vbuaa_band_vbuc1
|
||||
and #{c1}
|
||||
tay
|
||||
//FRAGMENT vbuxx=_inc_vbuxx
|
||||
inx
|
||||
//FRAGMENT vbuyy=_inc_vbuyy
|
||||
iny
|
||||
//FRAGMENT vbuyy_neq_vbuc1_then_la1
|
||||
@ -1659,11 +1686,6 @@ bne {la1}
|
||||
//FRAGMENT _deref_pbuc1=_deref_pbuc2
|
||||
lda {c2}
|
||||
sta {c1}
|
||||
//FRAGMENT _deref_pbuz1=pbuc1_derefidx_vbuz2
|
||||
ldy {z2}
|
||||
lda {c1},y
|
||||
ldy #0
|
||||
sta ({z1}),y
|
||||
//FRAGMENT vbuz1=vbuz1_plus_vbuz2
|
||||
lda {z1}
|
||||
clc
|
||||
@ -1886,14 +1908,6 @@ tay
|
||||
//FRAGMENT vbuc1_neq_vbuaa_then_la1
|
||||
cmp #{c1}
|
||||
bne {la1}
|
||||
//FRAGMENT _deref_pbuz1=pbuc1_derefidx_vbuxx
|
||||
lda {c1},x
|
||||
ldy #0
|
||||
sta ({z1}),y
|
||||
//FRAGMENT _deref_pbuz1=pbuc1_derefidx_vbuyy
|
||||
lda {c1},y
|
||||
ldy #0
|
||||
sta ({z1}),y
|
||||
//FRAGMENT vbuz1=vbuz1_plus_vbuxx
|
||||
txa
|
||||
clc
|
||||
@ -2889,15 +2903,6 @@ inc {m1}
|
||||
lda #{c1}
|
||||
cmp {m1}
|
||||
bne {la1}
|
||||
//FRAGMENT pbuz1_lt_pbuc1_then_la1
|
||||
lda {z1}+1
|
||||
cmp #>{c1}
|
||||
bcc {la1}
|
||||
bne !+
|
||||
lda {z1}
|
||||
cmp #<{c1}
|
||||
bcc {la1}
|
||||
!:
|
||||
//FRAGMENT vboz1=vbuz2_eq_vbuc1
|
||||
lda {z2}
|
||||
eor #{c1}
|
||||
@ -3735,11 +3740,6 @@ tax
|
||||
//FRAGMENT vbuyy=_byte_vwuz1
|
||||
lda {z1}
|
||||
tay
|
||||
//FRAGMENT _deref_pbuz1=pbuc1_derefidx_vbuaa
|
||||
tay
|
||||
lda {c1},y
|
||||
ldy #0
|
||||
sta ({z1}),y
|
||||
//FRAGMENT pwsz1=pwsc1_plus_vwsz1
|
||||
clc
|
||||
lda {z1}
|
||||
|
@ -1,4 +1,4 @@
|
||||
//KICKC FRAGMENT CACHE 15bc71afc6
|
||||
//KICKC FRAGMENT CACHE 1368a0c981
|
||||
//FRAGMENT vbuz1=_deref_pbuc1
|
||||
lda {c1}
|
||||
sta {z1}
|
||||
|
1
src/main/fragment/csg65ce02-common/vbuzz=_inc_vbuzz.asm
Normal file
1
src/main/fragment/csg65ce02-common/vbuzz=_inc_vbuzz.asm
Normal file
@ -0,0 +1 @@
|
||||
inz
|
1
src/main/fragment/csg65ce02-common/vbuzz=vbuc1.asm
Normal file
1
src/main/fragment/csg65ce02-common/vbuzz=vbuc1.asm
Normal file
@ -0,0 +1 @@
|
||||
ldz #{c1}
|
@ -0,0 +1,2 @@
|
||||
cpz #{c1}
|
||||
bcc {la1}
|
@ -13,19 +13,21 @@ public class Cpu65xx {
|
||||
/** All opcodes in the instruction set. */
|
||||
private final List<CpuOpcode> allOpcodes;
|
||||
|
||||
/** true if the CPU has a Z register. */
|
||||
private boolean registerZ;
|
||||
|
||||
/** Maps mnemonic_addressingMode to the instruction opcode */
|
||||
private final Map<String, CpuOpcode> opcodesByMnemonicAddrMode;
|
||||
|
||||
public Cpu65xx(String name) {
|
||||
public Cpu65xx(String name, boolean registerZ) {
|
||||
this.name = name;
|
||||
this.registerZ = registerZ;
|
||||
this.allOpcodes = new ArrayList<>();
|
||||
this.opcodesByMnemonicAddrMode = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public Cpu65xx(String name, Cpu65xx basedOn) {
|
||||
this.name = name;
|
||||
this.allOpcodes = new ArrayList<>();
|
||||
this.opcodesByMnemonicAddrMode = new LinkedHashMap<>();
|
||||
public Cpu65xx(String name, Cpu65xx basedOn, boolean registerZ) {
|
||||
this(name, registerZ);
|
||||
for(CpuOpcode opcode : basedOn.allOpcodes) {
|
||||
addOpcode(opcode);
|
||||
}
|
||||
@ -33,12 +35,22 @@ public class Cpu65xx {
|
||||
|
||||
/**
|
||||
* Get the CPU name.
|
||||
*
|
||||
* @return The name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the CPU have an extra Z-register. (only the 65ce02 and 45gs02) have this.
|
||||
*
|
||||
* @return true if the CPU has a Z register
|
||||
*/
|
||||
public boolean hasRegisterZ() {
|
||||
return registerZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an instruction opcode to the instruction set.
|
||||
*
|
||||
@ -48,7 +60,7 @@ public class Cpu65xx {
|
||||
* @param cycles The number of cycles
|
||||
*/
|
||||
protected void addOpcode(int opcode, String mnemonic, CpuAddressingMode addressingMode, double cycles, String clobberString) {
|
||||
addOpcode(new int[] { opcode }, mnemonic, addressingMode, cycles, clobberString);
|
||||
addOpcode(new int[]{opcode}, mnemonic, addressingMode, cycles, clobberString);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,19 +87,18 @@ public class Cpu65xx {
|
||||
|
||||
/**
|
||||
* Remove an opcode from the instruction set. (should only be done during initialization)
|
||||
*
|
||||
* @param mnemonic The lower case mnemonic
|
||||
* @param addressingMode The addressing mode
|
||||
*/
|
||||
protected void removeOpcode(String mnemonic, CpuAddressingMode addressingMode) {
|
||||
final CpuOpcode opcode = getOpcode(mnemonic, addressingMode);
|
||||
if(opcode==null)
|
||||
throw new RuntimeException("Opcode not found "+mnemonic+" "+addressingMode.getName());
|
||||
if(opcode == null)
|
||||
throw new RuntimeException("Opcode not found " + mnemonic + " " + addressingMode.getName());
|
||||
allOpcodes.remove(opcode);
|
||||
opcodesByMnemonicAddrMode.remove(opcode.getMnemonic() + "_" + opcode.getAddressingMode().getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get a specific instruction opcode form the instruction set
|
||||
*
|
||||
@ -140,6 +151,7 @@ public class Cpu65xx {
|
||||
|
||||
/**
|
||||
* Get all the opcodes of the CPU
|
||||
*
|
||||
* @return The opcodes
|
||||
*/
|
||||
public Collection<CpuOpcode> getAllOpcodes() {
|
||||
|
@ -155,7 +155,7 @@ public class CpuClobber implements Serializable {
|
||||
}
|
||||
|
||||
public boolean isRegisterZ() {
|
||||
return registerY;
|
||||
return registerZ;
|
||||
}
|
||||
|
||||
public boolean isFlagC() {
|
||||
|
@ -16,7 +16,7 @@ public class Cpu45GS02 extends Cpu65xx {
|
||||
public final static Cpu45GS02 INSTANCE = new Cpu45GS02();
|
||||
|
||||
public Cpu45GS02() {
|
||||
super(NAME, Cpu65CE02.INSTANCE);
|
||||
super(NAME, Cpu65CE02.INSTANCE, true);
|
||||
|
||||
addOpcode( new int[] {0x42, 0x42, 0x5},"orq",CpuAddressingMode.ZP,8,"AXYZnz");
|
||||
addOpcode( new int[] {0x42, 0x42, 0x6},"aslq",CpuAddressingMode.ZP,12,"cnz");
|
||||
|
@ -16,7 +16,7 @@ public class Cpu6502Illegal extends Cpu65xx {
|
||||
public final static Cpu6502Illegal INSTANCE = new Cpu6502Illegal();
|
||||
|
||||
public Cpu6502Illegal() {
|
||||
super(NAME, Cpu6502Official.INSTANCE);
|
||||
super(NAME, Cpu6502Official.INSTANCE, false);
|
||||
addOpcode(0x03, "slo", CpuAddressingMode.IZX, 8.0, "Acnz");
|
||||
addOpcode(0x07, "slo", CpuAddressingMode.ZP, 5.0, "Acnz");
|
||||
addOpcode(0x0b, "anc", CpuAddressingMode.IMM, 2.0, "Acnz");
|
||||
|
@ -17,7 +17,7 @@ public class Cpu6502Official extends Cpu65xx {
|
||||
public final static Cpu6502Official INSTANCE = new Cpu6502Official();
|
||||
|
||||
public Cpu6502Official() {
|
||||
super(NAME);
|
||||
super(NAME, false);
|
||||
addOpcode(0x00, "brk", CpuAddressingMode.NON, 7.0, "");
|
||||
addOpcode(0x01, "ora", CpuAddressingMode.IZX, 6.0, "Anz");
|
||||
addOpcode(0x05, "ora", CpuAddressingMode.ZP, 3.0, "Anz");
|
||||
|
@ -16,7 +16,7 @@ public class Cpu65C02 extends Cpu65xx {
|
||||
public final static Cpu65C02 INSTANCE = new Cpu65C02();
|
||||
|
||||
public Cpu65C02() {
|
||||
super(NAME, Cpu6502Official.INSTANCE);
|
||||
super(NAME, Cpu6502Official.INSTANCE, false);
|
||||
addOpcode(0x4,"tsb", CpuAddressingMode.ZP,5,"z");
|
||||
addOpcode(0x7,"rmb0", CpuAddressingMode.ZP,5,"");
|
||||
addOpcode(0xC,"tsb", CpuAddressingMode.ABS,6,"z");
|
||||
|
@ -16,7 +16,7 @@ public class Cpu65CE02 extends Cpu65xx {
|
||||
public final static Cpu65CE02 INSTANCE = new Cpu65CE02();
|
||||
|
||||
public Cpu65CE02() {
|
||||
super(NAME, Cpu65C02.INSTANCE);
|
||||
super(NAME, Cpu65C02.INSTANCE, true);
|
||||
|
||||
// Remove all opcodes not present on 65CE02 - eg. (zp), which is changed to (zp),y
|
||||
removeOpcode("ora", CpuAddressingMode.INZ);
|
||||
|
@ -2,21 +2,25 @@ package dk.camelot64.kickc.fragment;
|
||||
|
||||
import dk.camelot64.cpufamily6502.CpuClobber;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/** The clobber profile for a fragment template. Only distinguishes the 3 registers A/X/Y and not the flags. */
|
||||
public class AsmFragmentClobber implements Comparable<AsmFragmentClobber> {
|
||||
|
||||
private boolean clobberA;
|
||||
private boolean clobberX;
|
||||
private boolean clobberY;
|
||||
private boolean clobberZ;
|
||||
|
||||
public AsmFragmentClobber(boolean clobberA, boolean clobberX, boolean clobberY) {
|
||||
public AsmFragmentClobber(boolean clobberA, boolean clobberX, boolean clobberY, boolean clobberZ) {
|
||||
this.clobberA = clobberA;
|
||||
this.clobberX = clobberX;
|
||||
this.clobberY = clobberY;
|
||||
this.clobberZ = clobberZ;
|
||||
}
|
||||
|
||||
public AsmFragmentClobber(CpuClobber clobber) {
|
||||
this(clobber.isRegisterA(), clobber.isRegisterX(), clobber.isRegisterY());
|
||||
this(clobber.isRegisterA(), clobber.isRegisterX(), clobber.isRegisterY(), clobber.isRegisterZ());
|
||||
}
|
||||
|
||||
public boolean isClobberA() {
|
||||
@ -31,22 +35,24 @@ public class AsmFragmentClobber implements Comparable<AsmFragmentClobber> {
|
||||
return clobberY;
|
||||
}
|
||||
|
||||
public boolean isClobberZ() {
|
||||
return clobberY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(this == o) return true;
|
||||
if(o == null || getClass() != o.getClass()) return false;
|
||||
AsmFragmentClobber that = (AsmFragmentClobber) o;
|
||||
if(clobberA != that.clobberA) return false;
|
||||
if(clobberX != that.clobberX) return false;
|
||||
return clobberY == that.clobberY;
|
||||
return clobberA == that.clobberA &&
|
||||
clobberX == that.clobberX &&
|
||||
clobberY == that.clobberY &&
|
||||
clobberZ == that.clobberZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (clobberA ? 1 : 0);
|
||||
result = 31 * result + (clobberX ? 1 : 0);
|
||||
result = 31 * result + (clobberY ? 1 : 0);
|
||||
return result;
|
||||
return Objects.hash(clobberA, clobberX, clobberY, clobberZ);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,11 +68,15 @@ public class AsmFragmentClobber implements Comparable<AsmFragmentClobber> {
|
||||
return false;
|
||||
}
|
||||
if(!other.isClobberX() && this.isClobberX()) {
|
||||
// This clobber clobbers A, while the other does not - not a subset
|
||||
// This clobber clobbers X, while the other does not - not a subset
|
||||
return false;
|
||||
}
|
||||
if(!other.isClobberY() && this.isClobberY()) {
|
||||
// This clobber clobbers A, while the other does not - not a subset
|
||||
// This clobber clobbers Y, while the other does not - not a subset
|
||||
return false;
|
||||
}
|
||||
if(!other.isClobberZ() && this.isClobberZ()) {
|
||||
// This clobber clobbers Z, while the other does not - not a subset
|
||||
return false;
|
||||
}
|
||||
// This is a subset
|
||||
@ -86,11 +96,12 @@ public class AsmFragmentClobber implements Comparable<AsmFragmentClobber> {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (clobberA?"A ":"")+(clobberX?"X ":"")+(clobberY?"Y ":" ");
|
||||
return (clobberA?"A ":"")+(clobberX?"X ":"")+(clobberY?"Y ":" ")+(clobberZ?"Z ":" ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(AsmFragmentClobber o) {
|
||||
return toString().compareTo(o.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -536,6 +536,8 @@ public class AsmFragmentInstanceSpecFactory {
|
||||
return "xx";
|
||||
} else if(Registers.RegisterType.REG_Y.equals(register.getType())) {
|
||||
return "yy";
|
||||
} else if(Registers.RegisterType.REG_Z.equals(register.getType())) {
|
||||
return "zz";
|
||||
} else if(Registers.RegisterType.REG_ALU.equals(register.getType())) {
|
||||
throw new AsmFragmentInstance.AluNotApplicableException();
|
||||
} else {
|
||||
|
@ -116,7 +116,7 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
if(subDontClobber.contains("aa") && subTemplate.getClobber().isClobberA()) return null;
|
||||
if(subDontClobber.contains("xx") && subTemplate.getClobber().isClobberX()) return null;
|
||||
if(subDontClobber.contains("yy") && subTemplate.getClobber().isClobberY()) return null;
|
||||
// TODO Z register: if(subDontClobber.contains("zz") && subTemplate.getClobber().isClobberZ()) return null;
|
||||
if(subDontClobber.contains("zz") && subTemplate.getClobber().isClobberZ()) return null;
|
||||
}
|
||||
|
||||
StringBuilder newFragment = new StringBuilder();
|
||||
@ -280,6 +280,7 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
mapSToU.put("vbsaa", "vbuaa");
|
||||
mapSToU.put("vbsxx", "vbuxx");
|
||||
mapSToU.put("vbsyy", "vbuyy");
|
||||
mapSToU.put("vbszz", "vbuzz");
|
||||
mapSToU.put("vwsz1", "vwuz1");
|
||||
mapSToU.put("vwsz2", "vwuz2");
|
||||
mapSToU.put("vwsz3", "vwuz3");
|
||||
@ -350,6 +351,7 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
String rvalAa = ".*=.*aa.*|.*_.*aa.*|...aa_(lt|gt|le|ge|eq|neq)_.*";
|
||||
String rvalXx = ".*=.*xx.*|.*_.*xx.*|...xx_(lt|gt|le|ge|eq|neq)_.*";
|
||||
String rvalYy = ".*=.*yy.*|.*_.*yy.*|...yy_(lt|gt|le|ge|eq|neq)_.*";
|
||||
String rvalZz = ".*=.*zz.*|.*_.*zz.*|...zz_(lt|gt|le|ge|eq|neq)_.*";
|
||||
String rvalZ1 = ".*=.*z1.*|.*_.*z1.*|...z1_(lt|gt|le|ge|eq|neq)_.*";
|
||||
String rvalZ2 = ".*=.*z2.*|.*_.*z2.*|...z2_(lt|gt|le|ge|eq|neq)_.*";
|
||||
String lvalC1 = ".*c1.*=.*";
|
||||
@ -369,6 +371,7 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
String lvalAa = "...aa=.*";
|
||||
String lvalXx = "...xx=.*";
|
||||
String lvalYy = "...yy=.*";
|
||||
String lvalZz = "...zz=.*";
|
||||
String lvalZM1 = "...[zm]1=.*";
|
||||
String lvalZM2 = "...[zm]2=.*";
|
||||
String lvalZM3 = "...[zm]3=.*";
|
||||
@ -445,12 +448,29 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
// Replace two YYs with AA (not assigned)
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*vb.)yy(.*vb.)yy(.*)", rvalAa, "tya", "$1=$2aa$3aa$4", null, null));
|
||||
|
||||
// Replace first ZZ with AA
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)zz(.*)", lvalZz+"|"+rvalAa, "tza", "$1aa$2", null, null));
|
||||
// Replace two ZZs with AA
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*vb.)zz(.*vb.)zz(.*)", lvalZz+"|"+rvalAa, "tza", "$1aa$2aa$3", null, null));
|
||||
// Replace second (not first) ZZ with AA
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)zz(.*vb.)zz(.*)", lvalZz+"|"+rvalAa, "tza", "$1zz$2aa$3", null, null));
|
||||
// Replace ZZ with AA (not assigned)
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vb(.)zz(.*)", rvalAa, "tza", "$1=$2vb$3aa$4", null, null));
|
||||
// Replace two ZZs with AA (not assigned)
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*vb.)zz(.*vb.)zz(.*)", rvalAa, "tza", "$1=$2aa$3aa$4", null, null));
|
||||
|
||||
// Replace XX with YY
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vb(.)xx(.*)", rvalYy, "stx $ff\nldy $ff", "$1=$2vb$3yy$4", null, null));
|
||||
|
||||
// Replace YY with XX
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vb(.)yy(.*)", rvalXx, "sty $ff\nldx $ff", "$1=$2vb$3xx$4", null, null));
|
||||
|
||||
// Replace ZZ with YY
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vb(.)zz(.*)", rvalYy, "stz $ff\nldy $ff", "$1=$2vb$3yy$4", null, null));
|
||||
// Replace ZZ with XX
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)vb(.)zz(.*)", rvalXx, "stz $ff\nldx $ff", "$1=$2vb$3xx$4", null, null));
|
||||
|
||||
|
||||
// Replace Z1 with M1
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)z1(.*)", twoZM1, null, "$1m1$2", null, mapZ1M1));
|
||||
// Replace two Z1 with M1
|
||||
@ -636,6 +656,9 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("vb(.)xx=(.*)", null, null, "vb$1aa=$2", "tax", null));
|
||||
// Rewrite Assignments to Y from A
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("vb(.)yy=(.*)", null, null, "vb$1aa=$2", "tay", null));
|
||||
// Rewrite Assignments to Z from A
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("vb(.)zz=(.*)", null, null, "vb$1aa=$2", "taz", null));
|
||||
|
||||
// Rewrite Assignments to Z1 from A
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("vb(.)m1=(.*)", twoZM1, null, "vb$1aa=$2", "sta {m1}", mapZM1));
|
||||
// Rewrite Assignments to Z1 from A
|
||||
@ -731,14 +754,14 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)q[^v][^o]([czm][1-9])(.*[pq].*)", null, null, "$1qvo$2$3", null, null));
|
||||
|
||||
// Synthesize some constant pointers as constant words (remove when the above section can be included)
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_(lt|gt|le|ge|eq|neq)_p..([czm].)_then_(.*)", null, null, "$1_$2_vwu$3_then_$4", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("p..([czm].)_(lt|gt|le|ge|eq|neq)_(.*)", null, null, "vwu$1_$2_$3", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=p..([czm].)", null, null, "$1=vwu$2", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_(plus|minus|bor|bxor)_p..([czm].)", null, null, "$1=$2_$3_vwu$4", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=p..([czm].)_(plus|minus|bor|bxor)_(.*)", null, null, "$1=vwu$2_$3_$4", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("p..([czm].)=(.*)_(sethi|setlo|plus|minus)_(.*)", null, null, "vwu$1=$2_$3_$4", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=p..([czm].)_(sethi|setlo|plus|minus)_(.*)", null, null, "$1=vwu$2_$3_$4", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("p..([czm].)=_(inc|dec)_p..([czm].)", null, null, "vwu$1=_$2_vwu$3", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_(lt|gt|le|ge|eq|neq)_p..([czm][0-9])_then_(.*)", null, null, "$1_$2_vwu$3_then_$4", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("p..([czm][0-9])_(lt|gt|le|ge|eq|neq)_(.*)", null, null, "vwu$1_$2_$3", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=p..([czm][0-9])", null, null, "$1=vwu$2", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)_(plus|minus|bor|bxor)_p..([czm][0-9])", null, null, "$1=$2_$3_vwu$4", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=p..([czm][0-9])_(plus|minus|bor|bxor)_(.*)", null, null, "$1=vwu$2_$3_$4", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("p..([czm][0-9])=(.*)_(sethi|setlo|plus|minus)_(.*)", null, null, "vwu$1=$2_$3_$4", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=p..([czm][0-9])_(sethi|setlo|plus|minus)_(.*)", null, null, "$1=vwu$2_$3_$4", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("p..([czm][0-9])=_(inc|dec)_p..([czm][0-9])", null, null, "vwu$1=_$2_vwu$3", null, null));
|
||||
|
||||
// Synthesize constants using AA/XX/YY
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)vb(.)c1(.*)", rvalAa+"|"+ derefC1, "lda #{c1}", "$1vb$2aa$3", null, null));
|
||||
@ -809,7 +832,7 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)=(.*)pb(.)c2_derefidx_vbuyy(.*c2.*)", rvalAa, "lda {c2},y", "$1=$2vb$3aa$4", null, null));
|
||||
|
||||
// Remove any parenthesis ending up around values
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)\\(([vp][bwd][us][zcaxy][123456axy])\\)(.*)", null, null, "$1$2$3", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)\\(([vp][bwd][us][mzcaxy][123456axyz])\\)(.*)", null, null, "$1$2$3", null, null));
|
||||
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_derefidx_vbuz1_(.*)", rvalYy+"|"+twoZM1, "ldy {z1}", "$1_derefidx_vbuyy_$2", null, mapZM1));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(.*)_derefidx_vbuz1_(lt|gt|le|ge|eq|neq)_(.*)", rvalXx+"|"+twoZM1, "ldx {z1}", "$1_derefidx_vbuxx_$2_$3", null, mapZM1));
|
||||
@ -837,7 +860,7 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(vb[su]..)=(vb[su]..)_(plus|minus)_(vb[su]..)", null, null, "$1=$2_$3_$4", null, mapSToU));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(vw[su]..)=(vw[su]..)_(plus|minus)_(vw[su]..)", null, null, "$1=$2_$3_$4", null, mapSToU));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(vd[su]..)=(vd[su]..)_(plus|minus)_(vd[su]..)", null, null, "$1=$2_$3_$4", null, mapSToU));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(vbu..)=_(lo|hi)_vws(z.|c.|m.)", null, null, "$1=_$2_vwu$3", null, mapSToU));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(vbu..)=_(lo|hi)_vws(z[0-9]|c[0-9]|m[0-9])", null, null, "$1=_$2_vwu$3", null, mapSToU));
|
||||
|
||||
// Use Z1/Z2 ASM to synthesize Z1-only code ( ...z1...z1... -> ...z1...z2... )
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(v..[zm])1=(v..[zm])1_(plus|minus|band|bxor|bor)_(.*)", oneZM2, null, "$11=$22_$3_$4", null, mapZM1, false));
|
||||
@ -849,7 +872,7 @@ class AsmFragmentTemplateSynthesisRule {
|
||||
// Convert INC/DEC to +1/-1 ( ..._inc_xxx... -> ...xxx_plus_1_... / ..._dec_xxx... -> ...xxx_minus_1_... )
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("vb(.)aa=_inc_(.*)", null, null, "vb$1aa=$2_plus_1", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("vb(.)aa=_dec_(.*)", null, null, "vb$1aa=$2_minus_1", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(v..[zm].)=_inc_(v..[zm].)", null, null, "$1=$2_plus_1", null, null));
|
||||
synths.add(new AsmFragmentTemplateSynthesisRule("(v..[zm][0-9])=_inc_(v..[zm][0-9])", null, null, "$1=$2_plus_1", null, null));
|
||||
|
||||
return synths;
|
||||
}
|
||||
|
@ -19,6 +19,10 @@ public class Registers {
|
||||
return new RegisterYByte();
|
||||
}
|
||||
|
||||
public static Register getRegisterZ() {
|
||||
return new RegisterZByte();
|
||||
}
|
||||
|
||||
public static Register getRegisterA() {
|
||||
return new RegisterAByte();
|
||||
}
|
||||
@ -35,6 +39,8 @@ public class Registers {
|
||||
return getRegisterX();
|
||||
case "Y":
|
||||
return getRegisterY();
|
||||
case "Z":
|
||||
return getRegisterZ();
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@ -45,6 +51,7 @@ public class Registers {
|
||||
REG_A,
|
||||
REG_Y,
|
||||
REG_X,
|
||||
REG_Z,
|
||||
REG_ALU,
|
||||
ZP_MEM,
|
||||
MAIN_MEM,
|
||||
@ -250,6 +257,19 @@ public class Registers {
|
||||
|
||||
}
|
||||
|
||||
/** The Z register. */
|
||||
public static class RegisterZByte extends RegisterCpuByte {
|
||||
@Override
|
||||
public RegisterType getType() {
|
||||
return RegisterType.REG_Z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "reg byte z";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** The X register. */
|
||||
public static class RegisterXByte extends RegisterCpuByte {
|
||||
|
@ -70,7 +70,7 @@ public enum TargetCpu {
|
||||
/** The CPU name used by KickAsm */
|
||||
private final String asmName;
|
||||
|
||||
/** The SM CPU knowing the instruction set. */
|
||||
/** The CPU instruction set. */
|
||||
private final Cpu65xx cpu65xx;
|
||||
|
||||
/** Features of the CPU */
|
||||
|
@ -40,6 +40,9 @@ public class Pass4AssertNoCpuClobber extends Pass2Base {
|
||||
if(clobber.isRegisterY()) {
|
||||
clobberRegisters.add(Registers.getRegisterY());
|
||||
}
|
||||
if(clobber.isRegisterZ()) {
|
||||
clobberRegisters.add(Registers.getRegisterZ());
|
||||
}
|
||||
return clobberRegisters;
|
||||
}
|
||||
|
||||
|
@ -272,6 +272,8 @@ public class Pass4CodeGeneration {
|
||||
signature.append("register(X)");
|
||||
} else if(allocation instanceof Registers.RegisterYByte) {
|
||||
signature.append("register(Y)");
|
||||
} else if(allocation instanceof Registers.RegisterZByte) {
|
||||
signature.append("register(Z)");
|
||||
}
|
||||
signature.append(" ");
|
||||
signature.append(parameter.getLocalName());
|
||||
|
@ -62,6 +62,8 @@ public class Pass4RegisterUpliftPotentialInitialize extends Pass2Base {
|
||||
potentials.add(Registers.getRegisterA());
|
||||
potentials.add(Registers.getRegisterX());
|
||||
potentials.add(Registers.getRegisterY());
|
||||
if(getProgram().getTargetCpu().getCpu65xx().hasRegisterZ())
|
||||
potentials.add(Registers.getRegisterZ());
|
||||
}
|
||||
registerPotentials.setPotentialRegisters(equivalenceClass, potentials);
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ import dk.camelot64.kickc.asm.AsmProgram;
|
||||
import dk.camelot64.kickc.fragment.AsmFragmentInstance;
|
||||
import dk.camelot64.kickc.fragment.AsmFragmentTemplateSynthesizer;
|
||||
import dk.camelot64.kickc.model.*;
|
||||
import dk.camelot64.kickc.model.statements.*;
|
||||
import dk.camelot64.kickc.model.statements.Statement;
|
||||
import dk.camelot64.kickc.model.statements.StatementLValue;
|
||||
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
|
||||
import dk.camelot64.kickc.model.values.LValue;
|
||||
import dk.camelot64.kickc.model.values.RValue;
|
||||
import dk.camelot64.kickc.model.values.ValueList;
|
||||
@ -157,6 +159,8 @@ public class Pass4RegisterUpliftPotentialRegisterAnalysis extends Pass2Base {
|
||||
alwaysClobbered.add(Registers.getRegisterA());
|
||||
alwaysClobbered.add(Registers.getRegisterX());
|
||||
alwaysClobbered.add(Registers.getRegisterY());
|
||||
if(getProgram().getTargetCpu().getCpu65xx().hasRegisterZ())
|
||||
alwaysClobbered.add(Registers.getRegisterZ());
|
||||
|
||||
Set<String> unknownFragments = new LinkedHashSet<>();
|
||||
|
||||
|
@ -67,6 +67,11 @@ public class TestPrograms {
|
||||
compileAndCompare("cpu-45gs02.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCpu65CE02b() throws IOException, URISyntaxException {
|
||||
compileAndCompare("cpu-65ce02-b.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCpu65CE02() throws IOException, URISyntaxException {
|
||||
compileAndCompare("cpu-65ce02.c");
|
||||
|
11
src/test/kc/cpu-65ce02-b.c
Normal file
11
src/test/kc/cpu-65ce02-b.c
Normal file
@ -0,0 +1,11 @@
|
||||
// Test the 65CE02 CPU
|
||||
// A program that uses 65CE02 instructions
|
||||
|
||||
#pragma cpu(CSG65CE02)
|
||||
|
||||
char* const SCREEN = 0x0400;
|
||||
|
||||
void main() {
|
||||
for(register(Z) char i=0;i<100;i++)
|
||||
SCREEN[i] = i;
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
|
||||
void main() {
|
||||
char* const SCREEN = 0x0400;
|
||||
char register(Z) idx = 3;
|
||||
char register(H) idx = 3;
|
||||
while(idx++<7)
|
||||
SCREEN[idx] = 'a';
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ main: {
|
||||
far: .byte $60
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement asm { inx lda#$12 phw#$1234 lda$12 lda$12,x ldx$12,y lda($12,x) lda($12),y ora($12),z lda($12,sp),y lda$1234 lda$1234,x lda$1234,y beqlbl1 lbeqfar bbr0$12,lbl2 lbl1: jmp($1234) lbl2: jmp($1234,x) lbl3: lda(($12)),z ldq(($12)) } always clobbers reg byte a reg byte x reg byte y
|
||||
Statement asm { inx lda#$12 phw#$1234 lda$12 lda$12,x ldx$12,y lda($12,x) lda($12),y ora($12),z lda($12,sp),y lda$1234 lda$1234,x lda$1234,y beqlbl1 lbeqfar bbr0$12,lbl2 lbl1: jmp($1234) lbl2: jmp($1234,x) lbl3: lda(($12)),z ldq(($12)) } always clobbers reg byte a reg byte x reg byte y reg byte z
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main]
|
||||
|
@ -257,15 +257,16 @@ main: {
|
||||
// File Data
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [3] *((const dword*) SCREEN) ← (dword) main::sum#2 [ ] ( [ ] { } ) always clobbers reg byte a reg byte x reg byte y
|
||||
Statement [5] (dword) main::sum#1 ← (dword) main::sum#2 + (dword) main::addend#2 [ main::i#2 main::addend#2 main::sum#1 ] ( [ main::i#2 main::addend#2 main::sum#1 ] { } ) always clobbers reg byte a reg byte x reg byte y
|
||||
Statement [3] *((const dword*) SCREEN) ← (dword) main::sum#2 [ ] ( [ ] { } ) always clobbers reg byte a reg byte x reg byte y reg byte z
|
||||
Statement [5] (dword) main::sum#1 ← (dword) main::sum#2 + (dword) main::addend#2 [ main::i#2 main::addend#2 main::sum#1 ] ( [ main::i#2 main::addend#2 main::sum#1 ] { } ) always clobbers reg byte a reg byte x reg byte y reg byte z
|
||||
Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
Removing always clobbered register reg byte x as potential for zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
Removing always clobbered register reg byte y as potential for zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
Removing always clobbered register reg byte z as potential for zp[1]:2 [ main::i#2 main::i#1 ]
|
||||
Statement [6] (dword) main::addend#1 ← (dword) main::addend#2 + (byte) main::i#2 [ main::i#2 main::sum#1 main::addend#1 ] ( [ main::i#2 main::sum#1 main::addend#1 ] { } ) always clobbers reg byte a
|
||||
Statement [2] if((byte) main::i#2<(byte) $64) goto main::@2 [ main::i#2 main::sum#2 main::addend#2 ] ( [ main::i#2 main::sum#2 main::addend#2 ] { } ) always clobbers reg byte a
|
||||
Statement [3] *((const dword*) SCREEN) ← (dword) main::sum#2 [ ] ( [ ] { } ) always clobbers reg byte a reg byte x reg byte y
|
||||
Statement [5] (dword) main::sum#1 ← (dword) main::sum#2 + (dword) main::addend#2 [ main::i#2 main::addend#2 main::sum#1 ] ( [ main::i#2 main::addend#2 main::sum#1 ] { } ) always clobbers reg byte a reg byte x reg byte y
|
||||
Statement [3] *((const dword*) SCREEN) ← (dword) main::sum#2 [ ] ( [ ] { } ) always clobbers reg byte a reg byte x reg byte y reg byte z
|
||||
Statement [5] (dword) main::sum#1 ← (dword) main::sum#2 + (dword) main::addend#2 [ main::i#2 main::addend#2 main::sum#1 ] ( [ main::i#2 main::addend#2 main::sum#1 ] { } ) always clobbers reg byte a reg byte x reg byte y reg byte z
|
||||
Statement [6] (dword) main::addend#1 ← (dword) main::addend#2 + (byte) main::i#2 [ main::i#2 main::sum#1 main::addend#1 ] ( [ main::i#2 main::sum#1 main::addend#1 ] { } ) always clobbers reg byte a
|
||||
Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 ,
|
||||
Potential registers zp[4]:3 [ main::sum#2 main::sum#1 ] : zp[4]:3 ,
|
||||
|
24
src/test/ref/cpu-65ce02-b.asm
Normal file
24
src/test/ref/cpu-65ce02-b.asm
Normal file
@ -0,0 +1,24 @@
|
||||
// Test the 65CE02 CPU
|
||||
// A program that uses 65CE02 instructions
|
||||
.cpu _65ce02
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
.label SCREEN = $400
|
||||
main: {
|
||||
ldz #0
|
||||
__b1:
|
||||
// for(register(Z) char i=0;i<100;i++)
|
||||
cpz #$64
|
||||
bcc __b2
|
||||
// }
|
||||
rts
|
||||
__b2:
|
||||
// SCREEN[i] = i
|
||||
tza
|
||||
tax
|
||||
sta SCREEN,x
|
||||
// for(register(Z) char i=0;i<100;i++)
|
||||
inz
|
||||
jmp __b1
|
||||
}
|
16
src/test/ref/cpu-65ce02-b.cfg
Normal file
16
src/test/ref/cpu-65ce02-b.cfg
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
[1] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
|
||||
[2] if((byte) main::i#2<(byte) $64) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[4] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← (byte) main::i#2
|
||||
[5] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
to:main::@1
|
271
src/test/ref/cpu-65ce02-b.log
Normal file
271
src/test/ref/cpu-65ce02-b.log
Normal file
@ -0,0 +1,271 @@
|
||||
|
||||
CONTROL FLOW GRAPH SSA
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from __start
|
||||
(byte) main::i#0 ← (byte) 0
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
(byte) main::i#2 ← phi( main/(byte) main::i#0 main::@2/(byte) main::i#1 )
|
||||
(bool~) main::$0 ← (byte) main::i#2 < (number) $64
|
||||
if((bool~) main::$0) goto main::@2
|
||||
to:main::@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
(byte) main::i#3 ← phi( main::@1/(byte) main::i#2 )
|
||||
*((const nomodify byte*) SCREEN + (byte) main::i#3) ← (byte) main::i#3
|
||||
(byte) main::i#1 ← ++ (byte) main::i#3
|
||||
to:main::@1
|
||||
main::@return: scope:[main] from main::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
(void()) __start()
|
||||
__start: scope:[__start] from
|
||||
call main
|
||||
to:__start::@1
|
||||
__start::@1: scope:[__start] from __start
|
||||
to:__start::@return
|
||||
__start::@return: scope:[__start] from __start::@1
|
||||
return
|
||||
to:@return
|
||||
|
||||
SYMBOL TABLE SSA
|
||||
(const nomodify byte*) SCREEN = (byte*)(number) $400
|
||||
(void()) __start()
|
||||
(label) __start::@1
|
||||
(label) __start::@return
|
||||
(void()) main()
|
||||
(bool~) main::$0
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@return
|
||||
(byte) main::i !reg byte z
|
||||
(byte) main::i#0 !reg byte z
|
||||
(byte) main::i#1 !reg byte z
|
||||
(byte) main::i#2 !reg byte z
|
||||
(byte) main::i#3 !reg byte z
|
||||
|
||||
Adding number conversion cast (unumber) $64 in (bool~) main::$0 ← (byte) main::i#2 < (number) $64
|
||||
Successful SSA optimization PassNAddNumberTypeConversions
|
||||
Simplifying constant pointer cast (byte*) 1024
|
||||
Simplifying constant integer cast $64
|
||||
Successful SSA optimization PassNCastSimplification
|
||||
Finalized unsigned number type (byte) $64
|
||||
Successful SSA optimization PassNFinalizeNumberTypeConversions
|
||||
Alias main::i#2 = main::i#3
|
||||
Successful SSA optimization Pass2AliasElimination
|
||||
Simple Condition (bool~) main::$0 [3] if((byte) main::i#2<(byte) $64) goto main::@2
|
||||
Successful SSA optimization Pass2ConditionalJumpSimplification
|
||||
Constant (const byte) main::i#0 = 0
|
||||
Successful SSA optimization Pass2ConstantIdentification
|
||||
Removing unused procedure __start
|
||||
Removing unused procedure block __start
|
||||
Removing unused procedure block __start::@1
|
||||
Removing unused procedure block __start::@return
|
||||
Successful SSA optimization PassNEliminateEmptyStart
|
||||
Inlining constant with var siblings (const byte) main::i#0
|
||||
Constant inlined main::i#0 = (byte) 0
|
||||
Successful SSA optimization Pass2ConstantInlining
|
||||
Adding NOP phi() at start of main
|
||||
CALL GRAPH
|
||||
|
||||
Created 1 initial phi equivalence classes
|
||||
Coalesced [6] main::i#4 ← main::i#1
|
||||
Coalesced down to 1 phi equivalence classes
|
||||
Adding NOP phi() at start of main
|
||||
|
||||
FINAL CONTROL FLOW GRAPH
|
||||
|
||||
(void()) main()
|
||||
main: scope:[main] from
|
||||
[0] phi()
|
||||
to:main::@1
|
||||
main::@1: scope:[main] from main main::@2
|
||||
[1] (byte) main::i#2 ← phi( main/(byte) 0 main::@2/(byte) main::i#1 )
|
||||
[2] if((byte) main::i#2<(byte) $64) goto main::@2
|
||||
to:main::@return
|
||||
main::@return: scope:[main] from main::@1
|
||||
[3] return
|
||||
to:@return
|
||||
main::@2: scope:[main] from main::@1
|
||||
[4] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← (byte) main::i#2
|
||||
[5] (byte) main::i#1 ← ++ (byte) main::i#2
|
||||
to:main::@1
|
||||
|
||||
|
||||
VARIABLE REGISTER WEIGHTS
|
||||
(void()) main()
|
||||
(byte) main::i !reg byte z
|
||||
(byte) main::i#1 !reg byte z 22.0
|
||||
(byte) main::i#2 !reg byte z 18.333333333333332
|
||||
|
||||
Initial phi equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
Complete equivalence classes
|
||||
[ main::i#2 main::i#1 ]
|
||||
|
||||
INITIAL ASM
|
||||
Target platform is c64basic / CSG65CE02
|
||||
// File Comments
|
||||
// Test the 65CE02 CPU
|
||||
// A program that uses 65CE02 instructions
|
||||
// Upstart
|
||||
.cpu _65ce02
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
// main
|
||||
main: {
|
||||
// [1] phi from main to main::@1 [phi:main->main::@1]
|
||||
__b1_from_main:
|
||||
// [1] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuzz=vbuc1
|
||||
ldz #0
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [2] if((byte) main::i#2<(byte) $64) goto main::@2 -- vbuzz_lt_vbuc1_then_la1
|
||||
cpz #$64
|
||||
bcc __b2
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [3] return
|
||||
rts
|
||||
// main::@2
|
||||
__b2:
|
||||
// [4] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← (byte) main::i#2 -- pbuc1_derefidx_vbuzz=vbuzz
|
||||
tza
|
||||
tax
|
||||
sta SCREEN,x
|
||||
// [5] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuzz=_inc_vbuzz
|
||||
inz
|
||||
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
|
||||
__b1_from___b2:
|
||||
// [1] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [4] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← (byte) main::i#2 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a reg byte x
|
||||
Statement [5] (byte) main::i#1 ← ++ (byte) main::i#2 [ main::i#1 ] ( [ main::i#1 ] { } ) always clobbers reg byte z
|
||||
Potential registers reg byte z [ main::i#2 main::i#1 ] : reg byte z ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 40.33: reg byte z [ main::i#2 main::i#1 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 251 combination reg byte z [ main::i#2 main::i#1 ]
|
||||
Uplifting [] best 251 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
// File Comments
|
||||
// Test the 65CE02 CPU
|
||||
// A program that uses 65CE02 instructions
|
||||
// Upstart
|
||||
.cpu _65ce02
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
// main
|
||||
main: {
|
||||
// [1] phi from main to main::@1 [phi:main->main::@1]
|
||||
__b1_from_main:
|
||||
// [1] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuzz=vbuc1
|
||||
ldz #0
|
||||
jmp __b1
|
||||
// main::@1
|
||||
__b1:
|
||||
// [2] if((byte) main::i#2<(byte) $64) goto main::@2 -- vbuzz_lt_vbuc1_then_la1
|
||||
cpz #$64
|
||||
bcc __b2
|
||||
jmp __breturn
|
||||
// main::@return
|
||||
__breturn:
|
||||
// [3] return
|
||||
rts
|
||||
// main::@2
|
||||
__b2:
|
||||
// [4] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← (byte) main::i#2 -- pbuc1_derefidx_vbuzz=vbuzz
|
||||
tza
|
||||
tax
|
||||
sta SCREEN,x
|
||||
// [5] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuzz=_inc_vbuzz
|
||||
inz
|
||||
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
|
||||
__b1_from___b2:
|
||||
// [1] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
||||
ASSEMBLER OPTIMIZATIONS
|
||||
Removing instruction jmp __b1
|
||||
Removing instruction jmp __breturn
|
||||
Succesful ASM optimization Pass5NextJumpElimination
|
||||
Removing instruction __b1_from_main:
|
||||
Removing instruction __breturn:
|
||||
Removing instruction __b1_from___b2:
|
||||
Succesful ASM optimization Pass5UnusedLabelElimination
|
||||
|
||||
FINAL SYMBOL TABLE
|
||||
(const nomodify byte*) SCREEN = (byte*) 1024
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@return
|
||||
(byte) main::i !reg byte z
|
||||
(byte) main::i#1 !reg byte z 22.0
|
||||
(byte) main::i#2 !reg byte z 18.333333333333332
|
||||
|
||||
reg byte z [ main::i#2 main::i#1 ]
|
||||
|
||||
|
||||
FINAL ASSEMBLER
|
||||
Score: 191
|
||||
|
||||
// File Comments
|
||||
// Test the 65CE02 CPU
|
||||
// A program that uses 65CE02 instructions
|
||||
// Upstart
|
||||
.cpu _65ce02
|
||||
.pc = $801 "Basic"
|
||||
:BasicUpstart(main)
|
||||
.pc = $80d "Program"
|
||||
// Global Constants & labels
|
||||
.label SCREEN = $400
|
||||
// main
|
||||
main: {
|
||||
// [1] phi from main to main::@1 [phi:main->main::@1]
|
||||
// [1] phi (byte) main::i#2 = (byte) 0 [phi:main->main::@1#0] -- vbuzz=vbuc1
|
||||
ldz #0
|
||||
// main::@1
|
||||
__b1:
|
||||
// for(register(Z) char i=0;i<100;i++)
|
||||
// [2] if((byte) main::i#2<(byte) $64) goto main::@2 -- vbuzz_lt_vbuc1_then_la1
|
||||
cpz #$64
|
||||
bcc __b2
|
||||
// main::@return
|
||||
// }
|
||||
// [3] return
|
||||
rts
|
||||
// main::@2
|
||||
__b2:
|
||||
// SCREEN[i] = i
|
||||
// [4] *((const nomodify byte*) SCREEN + (byte) main::i#2) ← (byte) main::i#2 -- pbuc1_derefidx_vbuzz=vbuzz
|
||||
tza
|
||||
tax
|
||||
sta SCREEN,x
|
||||
// for(register(Z) char i=0;i<100;i++)
|
||||
// [5] (byte) main::i#1 ← ++ (byte) main::i#2 -- vbuzz=_inc_vbuzz
|
||||
inz
|
||||
// [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1]
|
||||
// [1] phi (byte) main::i#2 = (byte) main::i#1 [phi:main::@2->main::@1#0] -- register_copy
|
||||
jmp __b1
|
||||
}
|
||||
// File Data
|
||||
|
10
src/test/ref/cpu-65ce02-b.sym
Normal file
10
src/test/ref/cpu-65ce02-b.sym
Normal file
@ -0,0 +1,10 @@
|
||||
(const nomodify byte*) SCREEN = (byte*) 1024
|
||||
(void()) main()
|
||||
(label) main::@1
|
||||
(label) main::@2
|
||||
(label) main::@return
|
||||
(byte) main::i !reg byte z
|
||||
(byte) main::i#1 !reg byte z 22.0
|
||||
(byte) main::i#2 !reg byte z 18.333333333333332
|
||||
|
||||
reg byte z [ main::i#2 main::i#1 ]
|
@ -155,15 +155,16 @@ main: {
|
||||
REGISTER UPLIFT POTENTIAL REGISTERS
|
||||
Statement [1] (signed byte) main::a#1 ← - (signed byte) main::a#0 [ main::a#1 ] ( [ main::a#1 ] { } ) always clobbers reg byte a
|
||||
Statement [3] (signed byte~) main::$1 ← (signed byte) main::a#1 >> (byte) 2 [ main::$1 ] ( [ main::$1 ] { } ) always clobbers reg byte a
|
||||
Potential registers zp[1]:2 [ main::a#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:3 [ main::a#1 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:4 [ main::$1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
|
||||
Potential registers zp[1]:2 [ main::a#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y , reg byte z ,
|
||||
Potential registers zp[1]:3 [ main::a#1 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y , reg byte z ,
|
||||
Potential registers zp[1]:4 [ main::$1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y , reg byte z ,
|
||||
|
||||
REGISTER UPLIFT SCOPES
|
||||
Uplift Scope [main] 4: zp[1]:2 [ main::a#0 ] 4: zp[1]:4 [ main::$1 ] 3: zp[1]:3 [ main::a#1 ]
|
||||
Uplift Scope []
|
||||
|
||||
Uplifting [main] best 27 combination reg byte a [ main::a#0 ] reg byte a [ main::$1 ] reg byte a [ main::a#1 ]
|
||||
Limited combination testing to 100 combinations of 125 possible.
|
||||
Uplifting [] best 27 combination
|
||||
|
||||
ASSEMBLER BEFORE OPTIMIZATION
|
||||
|
Loading…
Reference in New Issue
Block a user