1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-08-05 07:28:18 +00:00

Added fallback to ZP-addressing if inline ASM instruction does not support absolute addressing. Closes #673

This commit is contained in:
jespergravgaard
2021-06-26 09:46:46 +02:00
parent 8d797ac308
commit eec9f260df
7 changed files with 195 additions and 4 deletions

View File

@@ -4,10 +4,8 @@ import dk.camelot64.cpufamily6502.CpuAddressingMode;
import dk.camelot64.cpufamily6502.CpuOpcode;
import dk.camelot64.kickc.NumberParser;
import dk.camelot64.kickc.asm.*;
import dk.camelot64.kickc.model.ConstantNotLiteral;
import dk.camelot64.kickc.model.*;
import dk.camelot64.kickc.model.InternalError;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.Registers;
import dk.camelot64.kickc.model.symbols.Label;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.types.SymbolType;
@@ -345,10 +343,14 @@ public class AsmFragmentInstance {
// Convert to ZP-addressing mode if possible
boolean isZp = param1 != null && param1.isZp();
CpuOpcode cpuOpcode = this.getAsmProgram().getTargetCpu().getCpu65xx().getOpcode(mnemonic, addressingMode, isZp);
if(!isZp && cpuOpcode==null) {
// Fallback to ZP-addressing
cpuOpcode = this.getAsmProgram().getTargetCpu().getCpu65xx().getOpcode(mnemonic, addressingMode, true);
}
String operand1 = param1 == null ? null : param1.getParam();
String operand2 = param2 == null ? null : param2.getParam();
if(cpuOpcode == null) {
throw new InternalError("Error in " + name + ".asm line " + instructionCtx.getStart().getLine() + " - Instruction type not supported " + addressingMode.getAsm(mnemonic, operand1, operand2) + " by CPU " + this.fragmentInstance.fragmentTemplate.getTargetCpu().getName());
throw new CompileError("Error in " + name + ".asm line " + instructionCtx.getStart().getLine() + " - Instruction type not supported " + addressingMode.getAsm(mnemonic, operand1, operand2) + " by CPU " + this.fragmentInstance.fragmentTemplate.getTargetCpu().getName());
}
return new AsmInstruction(cpuOpcode, operand1, operand2);
}

View File

@@ -9,6 +9,11 @@ import java.io.IOException;
*/
public class TestProgramsFast extends TestPrograms {
@Test
public void testMissingInstruction() throws IOException {
compileAndCompare("missing-instruction.c", log());
}
@Test
public void testNpeProblem0() throws IOException {
compileAndCompare("npe-problem-0.c");

View File

@@ -0,0 +1,7 @@
void main()
{
volatile unsigned char test;
asm {
sty test,x
}
}

View File

@@ -0,0 +1,19 @@
// Commodore 64 PRG executable file
.file [name="missing-instruction.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
.segment Code
main: {
.label test = 2
// volatile unsigned char test
lda #0
sta.z test
// asm
sty.z test,x
// }
rts
}

View File

@@ -0,0 +1,9 @@
void main()
main: scope:[main] from
[0] main::test = 0
asm { stytest,x }
to:main::@return
main::@return: scope:[main] from main
[2] return
to:@return

View File

@@ -0,0 +1,145 @@
CONTROL FLOW GRAPH SSA
void main()
main: scope:[main] from __start
main::test = 0
asm { stytest,x }
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
void __start()
void main()
volatile byte main::test loadstore
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
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] main::test = 0
asm { stytest,x }
to:main::@return
main::@return: scope:[main] from main
[2] return
to:@return
VARIABLE REGISTER WEIGHTS
void main()
volatile byte main::test loadstore 2.0
Initial phi equivalence classes
Added variable main::test to live range equivalence class [ main::test ]
Complete equivalence classes
[ main::test ]
Allocated zp[1]:2 [ main::test ]
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [0] main::test = 0 [ main::test ] ( [ main::test ] { } ) always clobbers reg byte a
Potential registers zp[1]:2 [ main::test ] : zp[1]:2 ,
REGISTER UPLIFT SCOPES
Uplift Scope [main] 2: zp[1]:2 [ main::test ]
Uplift Scope []
Uplifting [main] best 18 combination zp[1]:2 [ main::test ]
Uplifting [] best 18 combination
Attempting to uplift remaining variables inzp[1]:2 [ main::test ]
Uplifting [main] best 18 combination zp[1]:2 [ main::test ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Upstart
// Commodore 64 PRG executable file
.file [name="missing-instruction.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.segment Code
// main
main: {
.label test = 2
// [0] main::test = 0 -- vbuz1=vbuc1
lda #0
sta.z test
// asm { stytest,x }
sty.z test,x
jmp __breturn
// main::@return
__breturn:
// [2] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
void main()
volatile byte main::test loadstore zp[1]:2 2.0
zp[1]:2 [ main::test ]
FINAL ASSEMBLER
Score: 15
// File Comments
// Upstart
// Commodore 64 PRG executable file
.file [name="missing-instruction.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(main)
// Global Constants & labels
.segment Code
// main
main: {
.label test = 2
// volatile unsigned char test
// [0] main::test = 0 -- vbuz1=vbuc1
lda #0
sta.z test
// asm
// asm { stytest,x }
sty.z test,x
// main::@return
// }
// [2] return
rts
}
// File Data

View File

@@ -0,0 +1,4 @@
void main()
volatile byte main::test loadstore zp[1]:2 2.0
zp[1]:2 [ main::test ]