1
0
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:
jespergravgaard 2020-07-31 23:16:54 +02:00
parent b7a6412440
commit 30b3172e7f
34 changed files with 620 additions and 104 deletions

View File

@ -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}

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE 15bc71afc6
//KICKC FRAGMENT CACHE 1368a0c981
//FRAGMENT vduz1=vduc1
lda #<{c1}
sta {z1}

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE 15bc71afc6
//KICKC FRAGMENT CACHE 1368a0c981
//FRAGMENT vbuz1=vbuc1
lda #{c1}
sta {z1}

View File

@ -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}

View File

@ -1,4 +1,4 @@
//KICKC FRAGMENT CACHE 15bc71afc6
//KICKC FRAGMENT CACHE 1368a0c981
//FRAGMENT vbuz1=_deref_pbuc1
lda {c1}
sta {z1}

View File

@ -0,0 +1 @@
inz

View File

@ -0,0 +1 @@
ldz #{c1}

View File

@ -0,0 +1,2 @@
cpz #{c1}
bcc {la1}

View File

@ -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() {

View File

@ -155,7 +155,7 @@ public class CpuClobber implements Serializable {
}
public boolean isRegisterZ() {
return registerY;
return registerZ;
}
public boolean isFlagC() {

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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);

View File

@ -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());
}
}

View File

@ -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 {

View File

@ -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;
}

View File

@ -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 {

View File

@ -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 */

View File

@ -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;
}

View File

@ -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());

View File

@ -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);
}

View File

@ -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<>();

View File

@ -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");

View 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;
}

View File

@ -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';
}

View File

@ -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]

View File

@ -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 ,

View 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
}

View 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

View 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

View 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 ]

View File

@ -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