1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-04-18 21:37:18 +00:00

Added initial support for new CPU's 65C02, 65CE02 and 45GS02.

This commit is contained in:
jespergravgaard 2020-07-26 16:50:49 +02:00
parent f62631812e
commit f221865593
23 changed files with 4978 additions and 1702 deletions

File diff suppressed because it is too large Load Diff

@ -0,0 +1,67 @@
//KICKC FRAGMENT CACHE 15c356fca7
//FRAGMENT vbuz1=_deref_pbuc1
lda {c1}
sta {z1}
//FRAGMENT vbuz1=vbuz2_plus_1
lda {z2}
inc
sta {z1}
//FRAGMENT _deref_pbuc1=vbuz1
lda {z1}
sta {c1}
//FRAGMENT vbuaa=_deref_pbuc1
lda {c1}
//FRAGMENT vbuxx=_deref_pbuc1
ldx {c1}
//FRAGMENT vbuz1=vbuaa_plus_1
inc
sta {z1}
//FRAGMENT _deref_pbuc1=vbuaa
sta {c1}
//FRAGMENT vbuz1=vbuxx_plus_1
inx
stx {z1}
//FRAGMENT vbuyy=_deref_pbuc1
ldy {c1}
//FRAGMENT vbuz1=vbuyy_plus_1
iny
sty {z1}
//FRAGMENT vbuaa=vbuz1_plus_1
lda {z1}
inc
//FRAGMENT vbuaa=vbuaa_plus_1
inc
//FRAGMENT vbuaa=vbuxx_plus_1
txa
inc
//FRAGMENT vbuaa=vbuyy_plus_1
tya
inc
//FRAGMENT vbuxx=vbuz1_plus_1
ldx {z1}
inx
//FRAGMENT _deref_pbuc1=vbuxx
stx {c1}
//FRAGMENT vbuxx=vbuaa_plus_1
inc
tax
//FRAGMENT vbuxx=vbuxx_plus_1
inx
//FRAGMENT vbuxx=vbuyy_plus_1
tya
inc
tax
//FRAGMENT vbuyy=vbuz1_plus_1
ldy {z1}
iny
//FRAGMENT _deref_pbuc1=vbuyy
sty {c1}
//FRAGMENT vbuyy=vbuaa_plus_1
inc
tay
//FRAGMENT vbuyy=vbuxx_plus_1
txa
inc
tay
//FRAGMENT vbuyy=vbuyy_plus_1
iny

@ -0,0 +1,2 @@
inc
inc

@ -284,6 +284,11 @@ public class AsmInstructionSet {
add(0xfd, "sbc", abx, 4.5);
add(0xfe, "inc", abx, 7.0);
add(0xff, "isc", abx, 7.0);
// 65c02 instructions
// TODO: create instruction set model that knows the different CPU's
add(0x1a, "inc", non, 2.0);
List<String> jumps = Arrays.asList("jmp", "beq", "bne", "bcc", "bcs", "bvs", "bvc", "bmi", "bpl", "jsr");
for(AsmInstructionType instruction : instructions) {
if(jumps.contains(instruction.getMnemnonic())) {

@ -0,0 +1,44 @@
package dk.camelot64.kickc.asm;
import dk.camelot64.kickc.model.TargetCpu;
/** Set the current CPU */
public class AsmSetCpu implements AsmLine {
private final TargetCpu cpu;
private int index;
public AsmSetCpu(TargetCpu cpu) {
this.cpu = cpu;
}
@Override
public int getLineBytes() {
return 0;
}
@Override
public double getLineCycles() {
return 0;
}
@Override
public String getAsm() {
final String cpuName = cpu.getAsmName();
return ".cpu " + cpuName;
}
@Override
public int getIndex() {
return index;
}
@Override
public void setIndex(int index) {
this.index = index;
}
public TargetCpu getCpu() {
return cpu;
}
}

@ -223,10 +223,14 @@ public class AsmFragmentInstance {
KickCParser.AsmParamModeContext paramModeCtx = ctx.asmParamMode();
AsmInstruction instruction;
if(paramModeCtx == null) {
final String mnemonic = ctx.ASM_MNEMONIC().getText();
AsmInstructionType type = AsmInstructionSet.getInstructionType(
ctx.ASM_MNEMONIC().getText(),
mnemonic,
AsmAddressingMode.NON,
false);
if(type == null) {
throw new InternalError("Error in " + name + ".asm line " + ctx.getStart().getLine() + " - Instruction type unknown " + mnemonic + " " + AsmAddressingMode.NON);
}
instruction = new AsmInstruction(type, null);
} else {
instruction = (AsmInstruction) this.visit(paramModeCtx);
@ -291,14 +295,14 @@ public class AsmFragmentInstance {
KickCParser.AsmExprContext exprCtx,
AsmAddressingMode addressingMode) {
KickCParser.AsmInstructionContext instructionCtx = (KickCParser.AsmInstructionContext) ctx.getParent();
String mnemonic = instructionCtx.ASM_MNEMONIC().getSymbol().getText();
AsmParameter parameter = (AsmParameter) this.visit(exprCtx);
String mnemonic = instructionCtx.ASM_MNEMONIC().getSymbol().getText();
AsmInstructionType type = AsmInstructionSet.getInstructionType(
mnemonic,
addressingMode,
parameter.isZp());
if(type == null) {
throw new InternalError("Error in " + name + ".asm line " + ctx.getStart().getLine() + " - Instruction type unknown " + mnemonic + " " + addressingMode + " " + parameter);
throw new InternalError("Error in " + name + ".asm line " + instructionCtx.getStart().getLine() + " - Instruction type unknown " + mnemonic + " " + addressingMode + " " + parameter);
}
return new AsmInstruction(type, parameter.getParam());
}

@ -1,5 +1,7 @@
package dk.camelot64.kickc.model;
import kickass._65xx.cpus.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -10,32 +12,42 @@ import java.util.List;
* */
public enum TargetCpu {
/** Vanilla MOS 6502 CPU running in ROM - no illegal opcodes, no self-modifying code. */
ROM6502("rom6502", Collections.singletonList(Feature.MOS6502_COMMON)),
ROM6502("rom6502", CPU_6502NoIllegals.name, Collections.singletonList(Feature.MOS6502_COMMON)),
/** MOS 6502 CPU running in ROM - allows illegal instructions, no self-modifying code. */
ROM6502X("rom6502x", Arrays.asList(Feature.MOS6502_COMMON, Feature.MOS6502_UNODC)),
ROM6502X("rom6502x", CPU_6502WithIllegals.name, Arrays.asList(Feature.MOS6502_COMMON, Feature.MOS6502_UNODC)),
/** Vanilla MOS 6502 CPU - no illegal opcodes, allows self-modifying code. */
MOS6502("mos6502", Arrays.asList(Feature.MOS6502_COMMON, Feature.MOS6502_SELFMOD)),
MOS6502("mos6502", CPU_6502NoIllegals.name, Arrays.asList(Feature.MOS6502_COMMON, Feature.MOS6502_SELFMOD)),
/** MOS 6502 CPU - allows illegal instructions, allows self-modifying code. */
MOS6502X("mos6502x", Arrays.asList(Feature.MOS6502_COMMON, Feature.MOS6502_UNODC, Feature.MOS6502_SELFMOD)),
///** 65C02 CPU - More addressing modes and instructions, no illegal instructions. http://westerndesigncenter.com/wdc/documentation/w65c02s.pdf */
//WDC65C02("65C02"),
///** 65CE02 CPU - Even more addressing modes and instructions. http://www.zimmers.net/anonftp/pub/cbm/documents/chipdata/65ce02.txt */
//MOS65CE02("65CE02"),
MOS6502X("mos6502x", CPU_6502WithIllegals.name, Arrays.asList(Feature.MOS6502_COMMON, Feature.MOS6502_UNODC, Feature.MOS6502_SELFMOD)),
/** WDC 65C02 CPU - More addressing modes and instructions, no self-modifying code. http://westerndesigncenter.com/wdc/documentation/w65c02s.pdf */
WDC65C02("wdc65c02", CPU_65C02.name, Arrays.asList(Feature.MOS6502_COMMON, Feature.WDC65C02_COMMON, Feature.WDC65C02_SPECIFIC)),
/** CSG 65CE02 CPU - Even more addressing modes and instructions, no self-modifying code. http://www.zimmers.net/anonftp/pub/cbm/documents/chipdata/65ce02.txt */
CSG65CE02("csg65ce02", CPU_65CE02.name, Arrays.asList(Feature.MOS6502_COMMON, Feature.WDC65C02_COMMON, Feature.CSG65CE02_COMMON)),
/** 45GS02 CPU - Even more addressing modes and instructions, no self-modifying code. https://github.com/MEGA65/mega65-user-guide/blob/master/MEGA65-Book_draft.pdf */
MEGA45GS02("mega45gs02", CPU_45GS02.name, Arrays.asList(Feature.MOS6502_COMMON, Feature.WDC65C02_COMMON, Feature.CSG65CE02_COMMON, Feature.MEGA45GS02_COMMON)),
///** 65C186 CPU - 16-bit instructions, 24-bit addressing modes and more instructions. http://www.westerndesigncenter.com/wdc/documentation/w65c816s.pdf */
//WDC65C186("65CE02"),
//WDC65C186("65C186"),
;
/** The default target CPU */
public static final TargetCpu DEFAULT = MOS6502X;
/** Feature of a CPU. A feature is represented by a folder containing a number of fragments. */
/** A feature set of a CPU. The feature set is effectively a subset of the instruction set. In practice a feature is represented by a folder containing a number of fragments using the instructions. */
public enum Feature {
/** Official Instruction Set of the MOS6502 CPU. https://www.masswerk.at/6502/6502_instruction_set.html */
/** Official Instruction Set of the MOS 6502 CPU, which is also present on descendants. https://www.masswerk.at/6502/6502_instruction_set.html */
MOS6502_COMMON("mos6502-common"),
/** The Undocumented Opcodes of the MOS6502 CPU. http://www.oxyron.de/html/opcodes02.html */
/** The Undocumented Opcodes of the MOS 6502 CPU, not present on descendant CPU's. http://www.oxyron.de/html/opcodes02.html */
MOS6502_UNODC("mos6502-undoc"),
/** Self-modifying Code using MOS6502 instructions. */
/** Self-modifying Code using MOS 6502 instructions, not usable in ROM. */
MOS6502_SELFMOD("mos6502-selfmod"),
/** Added instructions of the WDC 65C02 CPU that are also present on the descendants 65CE02 and 45GS02. https://eater.net/datasheets/w65c02s.pdf */
WDC65C02_COMMON("wdc65c02-common"),
/** Instructions and features of the WDC 65C02 CPU that are not present on the descendants 65CE02 and 45GS02 (such as assuming that Z is always zero). https://eater.net/datasheets/w65c02s.pdf */
WDC65C02_SPECIFIC("wdc65c02-specific"),
/** Added instructions of the CSG 65CE02 CPU that are also present on the descendant 45GS02. http://archive.6502.org/datasheets/mos_65ce02_mpu.pdf */
CSG65CE02_COMMON("csg65ce02-common"),
/** Added instructions of the MEGA 45GS02 CPU. https://github.com/MEGA65/mega65-user-guide/blob/master/MEGA65-Book_draft.pdf */
MEGA45GS02_COMMON("mega45gs02-common"),
;
/** The CPU feature name. */
@ -53,11 +65,15 @@ public enum TargetCpu {
/** The name of the CPU. */
private String name;
/** The CPU name used by KickAsm */
private String asmName;
/** Features of the CPU */
private List<Feature> features;
TargetCpu(String name, List<Feature> features) {
TargetCpu(String name, String asmName, List<Feature> features) {
this.name = name;
this.asmName = asmName;
this.features = features;
}
@ -65,6 +81,14 @@ public enum TargetCpu {
return name;
}
/**
* Get the name used by KickAsm
* @return The CPU name used by KickAsm
*/
public String getAsmName() {
return asmName;
}
/**
* Get the features of the CPU deciding which fragments is usable
* @return The features

@ -81,6 +81,12 @@ public class Pass4CodeGeneration {
generateComments(asm, program.getFileComments());
asm.startChunk(currentScope, null, "Upstart");
final TargetPlatform targetPlatform = program.getTargetPlatform();
// Add Target CPU - if it is not the default
final TargetCpu targetCpu = program.getTargetCpu();
if(!targetCpu.equals(TargetCpu.DEFAULT))
asm.addLine(new AsmSetCpu(targetCpu));
String linkScriptBody = targetPlatform.getLinkScriptBody();
String outputFileName = new File(program.getPrimaryFileName()).getName() + "." + program.getTargetPlatform().getOutFileExtension();
linkScriptBody = linkScriptBody.replace("%O", outputFileName);

@ -34,7 +34,7 @@ public class Pass5DoubleJumpElimination extends Pass5AsmOptimization {
currentLabel = ((AsmLabel) line).getLabel();
} else if(line instanceof AsmComment || line instanceof AsmConstant || line instanceof AsmLabelDecl) {
// ignore
} else if(line instanceof AsmBasicUpstart || line instanceof AsmDataNumeric || line instanceof AsmDataFill || line instanceof AsmDataString || line instanceof AsmDataAlignment || line instanceof AsmSetPc || line instanceof AsmInlineKickAsm|| line instanceof AsmSetEncoding|| line instanceof AsmDataKickAsm|| line instanceof AsmSegmentDef|| line instanceof AsmSegment|| line instanceof AsmFile) {
} else if(line instanceof AsmBasicUpstart || line instanceof AsmDataNumeric || line instanceof AsmDataFill || line instanceof AsmDataString || line instanceof AsmDataAlignment || line instanceof AsmSetPc || line instanceof AsmInlineKickAsm|| line instanceof AsmSetEncoding|| line instanceof AsmSetCpu|| line instanceof AsmDataKickAsm|| line instanceof AsmSegmentDef|| line instanceof AsmSegment|| line instanceof AsmFile) {
currentLabel = null;
} else if(line instanceof AsmInstruction) {
if(currentLabel != null) {

@ -42,11 +42,6 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testMega65C65ce02() throws IOException, URISyntaxException {
compileAndCompare("mega65-c65ce02.c");
}
@Test
public void testCastingNegative() throws IOException, URISyntaxException {
compileAndCompare("casting-negative.c");
@ -949,6 +944,16 @@ public class TestPrograms {
}
*/
@Test
public void testMega65C65ce02() throws IOException, URISyntaxException {
compileAndCompare("cpu-45gs02.c");
}
@Test
public void testCpu65C02() throws IOException, URISyntaxException {
compileAndCompare("cpu-65c02.c");
}
@Test
public void testCpu6502() throws IOException, URISyntaxException {
compileAndCompare("cpu-6502.c");

@ -1,8 +1,9 @@
// Tests compiling inline C65CE02 Assembler
// Tests compiling inline C65CE02/45GS02 Assembler
#pragma cpu(MEGA45GS02)
void main() {
kickasm {{
.cpu _45gs02
ldz #2
stz $0800
adcq ($2)

11
src/test/kc/cpu-65c02.c Normal file

@ -0,0 +1,11 @@
// Test the 65C02 CPU
// A program that uses 65C02 instructions
#pragma cpu(WDC65C02)
char* const SCREEN = 0x0400;
void main() {
char a = SCREEN[0];
SCREEN[1] = a+1;
}

@ -1,11 +1,11 @@
// Tests compiling inline C65CE02 Assembler
// Tests compiling inline C65CE02/45GS02 Assembler
.cpu _45gs02
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
// kickasm
.cpu _45gs02
ldz #2
ldz #2
stz $0800
adcq ($2)

@ -1,8 +1,7 @@
(void()) main()
main: scope:[main] from
kickasm() {{ .cpu _45gs02
ldz #2
kickasm() {{ ldz #2
stz $0800
adcq ($2)
}}

@ -3,8 +3,7 @@ CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
kickasm() {{ .cpu _45gs02
ldz #2
kickasm() {{ ldz #2
stz $0800
adcq ($2)
}}
@ -44,8 +43,7 @@ FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
kickasm() {{ .cpu _45gs02
ldz #2
kickasm() {{ ldz #2
stz $0800
adcq ($2)
}}
@ -62,19 +60,19 @@ Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
Target platform is c64basic / MOS6502X
Target platform is c64basic / MEGA45GS02
// File Comments
// Tests compiling inline C65CE02 Assembler
// Tests compiling inline C65CE02/45GS02 Assembler
// Upstart
.cpu _45gs02
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
// kickasm() {{ .cpu _45gs02 ldz #2 stz $0800 adcq ($2) }}
.cpu _45gs02
ldz #2
// kickasm() {{ ldz #2 stz $0800 adcq ($2) }}
ldz #2
stz $0800
adcq ($2)
@ -97,17 +95,17 @@ Uplifting [] best 265 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Tests compiling inline C65CE02 Assembler
// Tests compiling inline C65CE02/45GS02 Assembler
// Upstart
.cpu _45gs02
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
// kickasm() {{ .cpu _45gs02 ldz #2 stz $0800 adcq ($2) }}
.cpu _45gs02
ldz #2
// kickasm() {{ ldz #2 stz $0800 adcq ($2) }}
ldz #2
stz $0800
adcq ($2)
@ -135,8 +133,9 @@ FINAL ASSEMBLER
Score: 262
// File Comments
// Tests compiling inline C65CE02 Assembler
// Tests compiling inline C65CE02/45GS02 Assembler
// Upstart
.cpu _45gs02
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
@ -144,9 +143,8 @@ Score: 262
// main
main: {
// kickasm
// kickasm() {{ .cpu _45gs02 ldz #2 stz $0800 adcq ($2) }}
.cpu _45gs02
ldz #2
// kickasm() {{ ldz #2 stz $0800 adcq ($2) }}
ldz #2
stz $0800
adcq ($2)

@ -1,5 +1,6 @@
// Test the 6502 CPU without support for illegal opcodes
// By a program that normally uses illegal opcodes
.cpu _6502NoIllegals
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"

@ -162,6 +162,7 @@ Target platform is c64basic / MOS6502
// Test the 6502 CPU without support for illegal opcodes
// By a program that normally uses illegal opcodes
// Upstart
.cpu _6502NoIllegals
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
@ -249,6 +250,7 @@ ASSEMBLER BEFORE OPTIMIZATION
// Test the 6502 CPU without support for illegal opcodes
// By a program that normally uses illegal opcodes
// Upstart
.cpu _6502NoIllegals
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
@ -348,6 +350,7 @@ Score: 356
// Test the 6502 CPU without support for illegal opcodes
// By a program that normally uses illegal opcodes
// Upstart
.cpu _6502NoIllegals
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"

@ -0,0 +1,17 @@
// Test the 65C02 CPU
// A program that uses 65C02 instructions
.cpu _65c02
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.label SCREEN = $400
main: {
// a = SCREEN[0]
lda SCREEN
// a+1
inc
// SCREEN[1] = a+1
sta SCREEN+1
// }
rts
}

@ -0,0 +1,10 @@
(void()) main()
main: scope:[main] from
[0] (byte) main::a#0 ← *((const nomodify byte*) SCREEN)
[1] (byte~) main::$0 ← (byte) main::a#0 + (byte) 1
[2] *((const nomodify byte*) SCREEN+(byte) 1) ← (byte~) main::$0
to:main::@return
main::@return: scope:[main] from main
[3] return
to:@return

212
src/test/ref/cpu-65c02.log Normal file

@ -0,0 +1,212 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
(byte) main::a#0 ← *((const nomodify byte*) SCREEN + (number) 0)
(number~) main::$0 ← (byte) main::a#0 + (number) 1
*((const nomodify byte*) SCREEN + (number) 1) ← (number~) main::$0
to:main::@return
main::@return: scope:[main] from main
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()
(number~) main::$0
(label) main::@return
(byte) main::a
(byte) main::a#0
Adding number conversion cast (unumber) 0 in (byte) main::a#0 ← *((const nomodify byte*) SCREEN + (number) 0)
Adding number conversion cast (unumber) 1 in (number~) main::$0 ← (byte) main::a#0 + (number) 1
Adding number conversion cast (unumber) main::$0 in (number~) main::$0 ← (byte) main::a#0 + (unumber)(number) 1
Adding number conversion cast (unumber) 1 in *((const nomodify byte*) SCREEN + (number) 1) ← (unumber~) main::$0
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (byte*) 1024
Simplifying constant integer cast 0
Simplifying constant integer cast 1
Simplifying constant integer cast 1
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) 0
Finalized unsigned number type (byte) 1
Finalized unsigned number type (byte) 1
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inferred type updated to byte in (unumber~) main::$0 ← (byte) main::a#0 + (byte) 1
Simplifying expression containing zero SCREEN in [0] (byte) main::a#0 ← *((const nomodify byte*) SCREEN + (byte) 0)
Successful SSA optimization PassNSimplifyExpressionWithZero
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
Consolidated array index constant in *(SCREEN+1)
Successful SSA optimization Pass2ConstantAdditionElimination
CALL GRAPH
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
[0] (byte) main::a#0 ← *((const nomodify byte*) SCREEN)
[1] (byte~) main::$0 ← (byte) main::a#0 + (byte) 1
[2] *((const nomodify byte*) SCREEN+(byte) 1) ← (byte~) main::$0
to:main::@return
main::@return: scope:[main] from main
[3] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
(byte~) main::$0 4.0
(byte) main::a
(byte) main::a#0 4.0
Initial phi equivalence classes
Added variable main::a#0 to live range equivalence class [ main::a#0 ]
Added variable main::$0 to live range equivalence class [ main::$0 ]
Complete equivalence classes
[ main::a#0 ]
[ main::$0 ]
Allocated zp[1]:2 [ main::a#0 ]
Allocated zp[1]:3 [ main::$0 ]
INITIAL ASM
Target platform is c64basic / WDC65C02
// File Comments
// Test the 65C02 CPU
// A program that uses 65C02 instructions
// Upstart
.cpu _65c02
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// main
main: {
.label __0 = 3
.label a = 2
// [0] (byte) main::a#0 ← *((const nomodify byte*) SCREEN) -- vbuz1=_deref_pbuc1
lda SCREEN
sta.z a
// [1] (byte~) main::$0 ← (byte) main::a#0 + (byte) 1 -- vbuz1=vbuz2_plus_1
lda.z a
inc
sta.z __0
// [2] *((const nomodify byte*) SCREEN+(byte) 1) ← (byte~) main::$0 -- _deref_pbuc1=vbuz1
lda.z __0
sta SCREEN+1
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
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::$0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 4: zp[1]:2 [ main::a#0 ] 4: zp[1]:3 [ main::$0 ]
Uplift Scope []
Uplifting [main] best 19 combination reg byte a [ main::a#0 ] reg byte a [ main::$0 ]
Uplifting [] best 19 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Test the 65C02 CPU
// A program that uses 65C02 instructions
// Upstart
.cpu _65c02
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// main
main: {
// [0] (byte) main::a#0 ← *((const nomodify byte*) SCREEN) -- vbuaa=_deref_pbuc1
lda SCREEN
// [1] (byte~) main::$0 ← (byte) main::a#0 + (byte) 1 -- vbuaa=vbuaa_plus_1
inc
// [2] *((const nomodify byte*) SCREEN+(byte) 1) ← (byte~) main::$0 -- _deref_pbuc1=vbuaa
sta SCREEN+1
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(const nomodify byte*) SCREEN = (byte*) 1024
(void()) main()
(byte~) main::$0 reg byte a 4.0
(label) main::@return
(byte) main::a
(byte) main::a#0 reg byte a 4.0
reg byte a [ main::a#0 ]
reg byte a [ main::$0 ]
FINAL ASSEMBLER
Score: 16
// File Comments
// Test the 65C02 CPU
// A program that uses 65C02 instructions
// Upstart
.cpu _65c02
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
.label SCREEN = $400
// main
main: {
// a = SCREEN[0]
// [0] (byte) main::a#0 ← *((const nomodify byte*) SCREEN) -- vbuaa=_deref_pbuc1
lda SCREEN
// a+1
// [1] (byte~) main::$0 ← (byte) main::a#0 + (byte) 1 -- vbuaa=vbuaa_plus_1
inc
// SCREEN[1] = a+1
// [2] *((const nomodify byte*) SCREEN+(byte) 1) ← (byte~) main::$0 -- _deref_pbuc1=vbuaa
sta SCREEN+1
// main::@return
// }
// [3] return
rts
}
// File Data

@ -0,0 +1,9 @@
(const nomodify byte*) SCREEN = (byte*) 1024
(void()) main()
(byte~) main::$0 reg byte a 4.0
(label) main::@return
(byte) main::a
(byte) main::a#0 reg byte a 4.0
reg byte a [ main::a#0 ]
reg byte a [ main::$0 ]