1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-11-19 11:31:57 +00:00

Added lexer support for all mnemonics used in CPU 65C02. Added Cpu65C02 instruction set.

This commit is contained in:
jespergravgaard 2020-07-28 21:31:17 +02:00
parent a454ee2cdd
commit ba9f99059a
17 changed files with 970 additions and 584 deletions

View File

@ -313,33 +313,33 @@ public class AsmInstructionSet {
* This will try to find a zeropage-based addressing mode if you indicate that you are interested in that.
*
* @param mnemonic The mnemonic
* @param mode The addressing mode you want.
* @param isZp Indicates whether you are interested in a zeropage-based opcode.
* @return The opcode, if it exists. If you have requested an absolute addressing mode passed isZp as true the
* resulting opcode will have zeropage-based addressing the instruction set offers that.
* @param addressingMode The addressing mode you want.
* @param isOperandZp Indicates whether the operand is <256 meaning the opcode could be zeropage-based.
* @return The opcode, if it exists. If you have requested an absolute addressing mode and pass isOperandZp as true the
* resulting opcode will have zeropage-based addressing if the instruction set offers that.
*/
public static AsmOpcode getOpcode(String mnemonic, AsmAddressingMode mode, boolean isZp) {
public static AsmOpcode getOpcode(String mnemonic, AsmAddressingMode addressingMode, boolean isOperandZp) {
AsmOpcode asmOpcode = null;
if(AsmAddressingMode.ABS.equals(mode) && isZp) {
if(AsmAddressingMode.ABS.equals(addressingMode) && isOperandZp) {
asmOpcode = set.getOpcode(mnemonic, AsmAddressingMode.ZP);
}
if(AsmAddressingMode.ABX.equals(mode) && isZp) {
if(AsmAddressingMode.ABX.equals(addressingMode) && isOperandZp) {
asmOpcode = set.getOpcode(mnemonic, AsmAddressingMode.ZPX);
}
if(AsmAddressingMode.ABY.equals(mode) && isZp) {
if(AsmAddressingMode.ABY.equals(addressingMode) && isOperandZp) {
asmOpcode = set.getOpcode(mnemonic, AsmAddressingMode.ZPY);
}
if(AsmAddressingMode.IND.equals(mode) && isZp) {
if(AsmAddressingMode.IND.equals(addressingMode) && isOperandZp) {
asmOpcode = set.getOpcode(mnemonic, AsmAddressingMode.INZ);
}
if(AsmAddressingMode.IAX.equals(mode) && isZp) {
if(AsmAddressingMode.IAX.equals(addressingMode) && isOperandZp) {
asmOpcode = set.getOpcode(mnemonic, AsmAddressingMode.IZX);
}
if(asmOpcode == null) {
// If the ZP-variation does not exist use the ABS-variation
asmOpcode = set.getOpcode(mnemonic, mode);
// If the ZP-form does not exist use the ABS-variation
asmOpcode = set.getOpcode(mnemonic, addressingMode);
}
if(asmOpcode == null && AsmAddressingMode.ABS.equals(mode)) {
if(asmOpcode == null && AsmAddressingMode.ABS.equals(addressingMode)) {
asmOpcode = set.getOpcode(mnemonic, AsmAddressingMode.REL);
}
return asmOpcode;

View File

@ -9,10 +9,10 @@ import dk.camelot64.cpufamily6502.AsmCpu;
*/
public class Cpu6502Illegal extends AsmCpu {
/** The 6502 with illegal CPU name. */
/** The 6502 with illegal instructions CPU name. */
public final static String NAME = "6502x";
/** The 6502 with illegal CPU. */
/** The 6502 with illegal instructions CPU. */
public final static Cpu6502Illegal INSTANCE = new Cpu6502Illegal();
public Cpu6502Illegal() {

View File

@ -0,0 +1,85 @@
package dk.camelot64.cpufamily6502.cpus;
import dk.camelot64.cpufamily6502.AsmAddressingMode;
import dk.camelot64.cpufamily6502.AsmCpu;
/**
* The 65C02 instruction set.
* https://eater.net/datasheets/w65c02s.pdf
*/
public class Cpu65C02 extends AsmCpu {
/** The 65C02 CPU name. */
public final static String NAME = "65c02";
/** The 65C02 with illegal CPU. */
public final static Cpu65C02 INSTANCE = new Cpu65C02();
public Cpu65C02() {
super(NAME, Cpu6502Official.INSTANCE);
addOpcode(0x4,"tsb",AsmAddressingMode.ZP,5,"z");
addOpcode(0x7,"rmb0",AsmAddressingMode.ZP,5,"");
addOpcode(0xC,"tsb",AsmAddressingMode.ABS,6,"z");
addOpcode(0xF,"bbr0",AsmAddressingMode.REZ,5,"");
addOpcode(0x12,"ora",AsmAddressingMode.INZ,5,"Anz");
addOpcode(0x14,"trb",AsmAddressingMode.ZP,5,"z");
addOpcode(0x17,"rmb1",AsmAddressingMode.ZP,5,"");
addOpcode(0x1A,"inc",AsmAddressingMode.NON,2,"Anz");
addOpcode(0x1C,"trb",AsmAddressingMode.ABS,6,"z");
addOpcode(0x1F,"bbr1",AsmAddressingMode.REZ,5,"");
addOpcode(0x27,"rmb2",AsmAddressingMode.ZP,5,"");
addOpcode(0x2F,"bbr2",AsmAddressingMode.REZ,5,"");
addOpcode(0x32,"and",AsmAddressingMode.INZ,5,"Anz");
addOpcode(0x34,"bit",AsmAddressingMode.ZPX,4,"nvz");
addOpcode(0x37,"rmb3",AsmAddressingMode.ZP,5,"");
addOpcode(0x3A,"dec",AsmAddressingMode.NON,2,"Anz");
addOpcode(0x3C,"bit",AsmAddressingMode.ZPX,4.5,"nvz");
addOpcode(0x3F,"bbr3",AsmAddressingMode.REZ,5,"");
addOpcode(0x47,"rmb4",AsmAddressingMode.ZP,5,"");
addOpcode(0x4F,"bbr4",AsmAddressingMode.REZ,5,"");
addOpcode(0x52,"eor",AsmAddressingMode.INZ,5,"Anz");
addOpcode(0x57,"rmb5",AsmAddressingMode.ZP,5,"");
addOpcode(0x5A,"phy",AsmAddressingMode.NON,3,"");
addOpcode(0x5F,"bbr5",AsmAddressingMode.REZ,5,"");
addOpcode(0x64,"stz",AsmAddressingMode.ZP,3,"");
addOpcode(0x67,"rmb6",AsmAddressingMode.ZP,5,"");
addOpcode(0x6F,"bbr6",AsmAddressingMode.REZ,5,"");
addOpcode(0x72,"adc",AsmAddressingMode.INZ,5,"Acvnz");
addOpcode(0x74,"stz",AsmAddressingMode.ZPX,4,"");
addOpcode(0x77,"rmb7",AsmAddressingMode.ZP,5,"");
addOpcode(0x7A,"ply",AsmAddressingMode.NON,4,"Ynz");
addOpcode(0x7C,"jmp",AsmAddressingMode.IAX,6,"");
addOpcode(0x7F,"bbr7",AsmAddressingMode.REZ,5,"");
addOpcode(0x80,"bra",AsmAddressingMode.NON,3,"");
addOpcode(0x87,"smb0",AsmAddressingMode.ZP,5,"");
addOpcode(0x89,"bit",AsmAddressingMode.IAX,2,"z");
addOpcode(0x8F,"bbs0",AsmAddressingMode.REZ,5,"");
addOpcode(0x92,"sta",AsmAddressingMode.INZ,5,"");
addOpcode(0x97,"smb1",AsmAddressingMode.ZP,5,"");
addOpcode(0x9C,"stz",AsmAddressingMode.ABS,4,"");
addOpcode(0x9E,"stz",AsmAddressingMode.ZPX,5,"");
addOpcode(0x9F,"bbs1",AsmAddressingMode.REZ,5,"");
addOpcode(0xA7,"smb2",AsmAddressingMode.ZP,5,"");
addOpcode(0xAF,"bbs2",AsmAddressingMode.REZ,5,"");
addOpcode(0xB2,"lda",AsmAddressingMode.INZ,5,"Anz");
addOpcode(0xB7,"smb3",AsmAddressingMode.ZP,5,"");
addOpcode(0xBF,"bbs3",AsmAddressingMode.REZ,5,"");
addOpcode(0xC7,"smb4",AsmAddressingMode.ZP,5,"");
addOpcode(0xCB,"wai",AsmAddressingMode.NON,3,"");
addOpcode(0xCF,"bbs4",AsmAddressingMode.REZ,5,"");
addOpcode(0xD2,"cmp",AsmAddressingMode.INZ,5,"cnz");
addOpcode(0xD7,"smb5",AsmAddressingMode.ZP,5,"");
addOpcode(0xDA,"phx",AsmAddressingMode.NON,3,"");
addOpcode(0xDB,"stp",AsmAddressingMode.NON,3,"");
addOpcode(0xDF,"bbs5",AsmAddressingMode.REZ,5,"");
addOpcode(0xE7,"smb6",AsmAddressingMode.ZP,5,"");
addOpcode(0xEF,"bbs6",AsmAddressingMode.REZ,5,"");
addOpcode(0xF2,"sbc",AsmAddressingMode.INZ,5,"Acvnz");
addOpcode(0xF7,"smb7",AsmAddressingMode.ZP,5,"");
addOpcode(0xFA,"plx",AsmAddressingMode.NON,4,"Xnz");
addOpcode(0xFF,"bbs7",AsmAddressingMode.REZ,5,"");
// TODO: Cycle differences for ASL LSR ROL ROR abs,X - http://6502.org/tutorials/65c02opcodes.html
}
}

View File

@ -173,7 +173,10 @@ ASM_MNEMONIC:
'brk' | 'ora' | 'kil' | 'slo' | 'nop' | 'asl' | 'php' | 'anc' | 'bpl' | 'clc' | 'jsr' | 'and' | 'rla' | 'bit' | 'rol' | 'pla' | 'plp' | 'bmi' | 'sec' |
'rti' | 'eor' | 'sre' | 'lsr' | 'pha' | 'alr' | 'jmp' | 'bvc' | 'cli' | 'rts' | 'adc' | 'rra' | 'bvs' | 'sei' | 'sax' | 'sty' | 'sta' | 'stx' | 'dey' |
'txa' | 'xaa' | 'bcc' | 'ahx' | 'tya' | 'txs' | 'tas' | 'shy' | 'shx' | 'ldy' | 'lda' | 'ldx' | 'lax' | 'tay' | 'tax' | 'bcs' | 'clv' | 'tsx' | 'las' |
'cpy' | 'cmp' | 'cpx' | 'dcp' | 'dec' | 'inc' | 'axs' | 'bne' | 'cld' | 'sbc' | 'isc' | 'inx' | 'beq' | 'sed' | 'dex' | 'iny' | 'ror'
'cpy' | 'cmp' | 'cpx' | 'dcp' | 'dec' | 'inc' | 'axs' | 'bne' | 'cld' | 'sbc' | 'isc' | 'inx' | 'beq' | 'sed' | 'dex' | 'iny' | 'ror' | 'bbr0'| 'bbr1'|
'bbr2'| 'bbr3'| 'bbr4'| 'bbr5'| 'bbr6'| 'bbr7'| 'bbs0'| 'bbs1'| 'bbs2'| 'bbs3'| 'bbs4'| 'bbs5'| 'bbs6'| 'bbs7'| 'bra' | 'phx' | 'phy' | 'plx' | 'ply' |
'rmb0'| 'rmb1'| 'rmb2'| 'rmb3'| 'rmb4'| 'rmb5'| 'rmb6'| 'rmb7'| 'smb0'| 'smb1'| 'smb2'| 'smb3'| 'smb4'| 'smb5'| 'smb6'| 'smb7'| 'stp' | 'stz' | 'trb' |
'tsb'| 'wai'
;
ASM_IMM : '#' ;

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -43,8 +43,23 @@ public class TestPrograms {
}
@Test
public void testAsmAddressingModes() throws IOException, URISyntaxException {
compileAndCompare("asm-addressing-modes.c");
public void testCpuAddressingModes() throws IOException, URISyntaxException {
compileAndCompare("cpu-addressing-modes.c");
}
@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");
}
@Test
@ -949,21 +964,6 @@ 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");
}
@Test
public void testZpCode() throws IOException, URISyntaxException {
compileAndCompare("examples/zpcode/zpcode.c");
@ -4058,6 +4058,11 @@ public class TestPrograms {
compileAndCompare("incd020.c");
}
@Test
public void testIncD0202() throws IOException, URISyntaxException {
compileAndCompare("incd020-2.c", log());
}
@Test
public void testOverlapAllocation2() throws IOException, URISyntaxException {
compileAndCompare("overlap-allocation-2.c");

View File

@ -8,12 +8,12 @@ void main() {
// Indirect
jmp ($1234)
// TODO Indirect Zeropage
// ora ($12)
// TODO: Indirect ABS,x
// jmp ($1234,x)
// TODO Indirect Zeropage
//jmp ($12)
// TODO test relative
// lda $12, $1234

7
src/test/kc/incd020-2.c Normal file
View File

@ -0,0 +1,7 @@
void main() {
do {
(*(unsigned char *)(53280))++;
} while ( (*(unsigned char *)(53280)) < 255);
}

View File

@ -0,0 +1,14 @@
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
__b1:
// (*(unsigned char *)(53280))++;
inc $d020
// while ( (*(unsigned char *)(53280)) < 255)
lda $d020
cmp #$ff
bcc __b1
// }
rts
}

View File

@ -0,0 +1,12 @@
(void()) main()
main: scope:[main] from
[0] phi()
to:main::@1
main::@1: scope:[main] from main main::@1
[1] *((byte*) 53280) ← ++ *((byte*) 53280)
[2] if(*((byte*) 53280)<(byte) $ff) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return

183
src/test/ref/incd020-2.log Normal file
View File

@ -0,0 +1,183 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
to:main::@1
main::@1: scope:[main] from main main::@1
*((byte*)(number) $d020) ← ++ *((byte*)(number) $d020)
(bool~) main::$1 ← *((byte*)(number) $d020) < (number) $ff
if((bool~) main::$1) goto main::@1
to:main::@return
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
(void()) __start()
(label) __start::@1
(label) __start::@return
(void()) main()
(bool~) main::$1
(label) main::@1
(label) main::@return
Adding number conversion cast (unumber) $ff in (bool~) main::$1 ← *((byte*)(number) $d020) < (number) $ff
Successful SSA optimization PassNAddNumberTypeConversions
Simplifying constant pointer cast (byte*) 53280
Simplifying constant pointer cast (byte*) 53280
Simplifying constant pointer cast (byte*) 53280
Simplifying constant integer cast $ff
Successful SSA optimization PassNCastSimplification
Finalized unsigned number type (byte) $ff
Successful SSA optimization PassNFinalizeNumberTypeConversions
Simple Condition (bool~) main::$1 [2] if(*((byte*) 53280)<(byte) $ff) goto main::@1
Successful SSA optimization Pass2ConditionalJumpSimplification
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
Adding NOP phi() at start of main
CALL GRAPH
Created 0 initial phi equivalence classes
Coalesced down to 0 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::@1
[1] *((byte*) 53280) ← ++ *((byte*) 53280)
[2] if(*((byte*) 53280)<(byte) $ff) goto main::@1
to:main::@return
main::@return: scope:[main] from main::@1
[3] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
jmp __b1
// main::@1
__b1:
// [1] *((byte*) 53280) ← ++ *((byte*) 53280) -- _deref_pbuc1=_inc__deref_pbuc1
inc $d020
// [2] if(*((byte*) 53280)<(byte) $ff) goto main::@1 -- _deref_pbuc1_lt_vbuc2_then_la1
lda $d020
cmp #$ff
bcc __b1
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement [2] if(*((byte*) 53280)<(byte) $ff) goto main::@1 [ ] ( [ ] { } ) always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope []
Uplifting [main] best 211 combination
Uplifting [] best 211 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
jmp __b1
// main::@1
__b1:
// [1] *((byte*) 53280) ← ++ *((byte*) 53280) -- _deref_pbuc1=_inc__deref_pbuc1
inc $d020
// [2] if(*((byte*) 53280)<(byte) $ff) goto main::@1 -- _deref_pbuc1_lt_vbuc2_then_la1
lda $d020
cmp #$ff
bcc __b1
jmp __breturn
// main::@return
__breturn:
// [3] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __b1
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(void()) main()
(label) main::@1
(label) main::@return
FINAL ASSEMBLER
Score: 151
// File Comments
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
// main::@1
__b1:
// (*(unsigned char *)(53280))++;
// [1] *((byte*) 53280) ← ++ *((byte*) 53280) -- _deref_pbuc1=_inc__deref_pbuc1
inc $d020
// while ( (*(unsigned char *)(53280)) < 255)
// [2] if(*((byte*) 53280)<(byte) $ff) goto main::@1 -- _deref_pbuc1_lt_vbuc2_then_la1
lda $d020
cmp #$ff
bcc __b1
// main::@return
// }
// [3] return
rts
}
// File Data

View File

@ -0,0 +1,4 @@
(void()) main()
(label) main::@1
(label) main::@return