123 files changed, 3001 insertions(+), 17 deletions(-)

M jasm/assemble/assembler_impl/assembler_impl.h
M jasm/docs/jasm.md
M jasm/docs/syntax_highlight.py
M jasm/processor/65c02/instructions_65c02.cpp
M jasm/processor/65c02/instructions_65c02.h
M jasm/processor/65c02/processor_keywords_65c02.cpp
M jasm/processor/65c02/processor_keywords_65c02.h
A => jasm/processor/65ce02/instructions_65ce02.cpp
A => jasm/processor/65ce02/instructions_65ce02.h
A => jasm/processor/65ce02/processor_65ce02.cpp
A => jasm/processor/65ce02/processor_65ce02.h
A => jasm/processor/65ce02/processor_keywords_65ce02.cpp
A => jasm/processor/65ce02/processor_keywords_65ce02.h
M jasm/processor/instructions.h
M jasm/processor/processor.cpp
M jasm/processor/processor.h
M jasm/syntax/syntax_parser.cpp
M jasm/syntax/syntax_parser.h
M jasm/unit_test.py
A => jasm/unit_tests/results/test_addressing_mode_branch_too_long_1_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_branch_too_long_2_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_expected_x_in_indirect_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_expected_y_in_indirect_65c02.stdout
A => jasm/unit_tests/results/test_addressing_mode_expected_y_or_z_in_indirect_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_immediate_value_too_large_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_immediate_value_too_small_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_is_illegal_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_needs_bit_size_argument_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_needs_byte_argument_1_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_needs_byte_argument_2_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_needs_byte_argument_3_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_needs_integer_argument_1_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_needs_integer_argument_2_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_needs_integer_argument_3_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_needs_integer_argument_4_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_needs_positive_argument_1_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_needs_positive_argument_2_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_needs_word_size_argument_1_65ce02.stdout
A => jasm/unit_tests/results/test_addressing_mode_needs_word_size_argument_2_65ce02.stdout
A => jasm/unit_tests/results/test_bank_mode_truncates_address_instructions_65ce02.bin
A => jasm/unit_tests/results/test_generate_data_in_instruction_1_65ce02.stdout
A => jasm/unit_tests/results/test_instruction_data_label_cant_have_implied_addressing_mode_65ce02.stdout
A => jasm/unit_tests/results/test_instruction_data_label_for_wrong_argument_type_3_65ce02.stdout
A => jasm/unit_tests/results/test_instruction_data_label_has_lo_hi_properties_65ce02.bin
A => jasm/unit_tests/results/test_instruction_data_label_with_export_65ce02.bin
A => jasm/unit_tests/results/test_instruction_data_label_with_local_export_65ce02.stdout
A => jasm/unit_tests/results/test_instruction_ends_at_newline_2_65ce02.stdout
A => jasm/unit_tests/results/test_instructions_must_be_in_code_sections_1_65ce02.stdout
A => jasm/unit_tests/results/test_instructions_must_be_in_code_sections_2_65ce02.stdout
M jasm/unit_tests/results/test_processor_with_invalid_name.stdout
A => jasm/unit_tests/results/test_pseudo_instructions_for_branching_65ce02.bin
A => jasm/unit_tests/results/test_pseudo_instructions_for_incrementing_65ce02.bin
A => jasm/unit_tests/results/test_pseudo_instructions_in_standard_mode_65ce02.stdout
A => jasm/unit_tests/results/test_pseudo_instructions_use_names_in_standard_mode_65ce02.bin
A => jasm/unit_tests/results/test_register_names_cant_be_used_as_global_variables_65ce02.stdout
A => jasm/unit_tests/results/test_subroutine_call_65ce02.bin
A => jasm/unit_tests/results/test_subroutine_call_must_be_in_code_section_65ce02.stdout
A => jasm/unit_tests/results/test_subroutine_call_negative_argument_65ce02.stdout
A => jasm/unit_tests/results/test_subroutine_call_recursive_data_generation_65ce02.stdout
A => jasm/unit_tests/results/test_subroutine_call_too_large_argument_65ce02.stdout
A => jasm/unit_tests/results/test_subroutine_call_with_arguments_65ce02.stdout
A => jasm/unit_tests/results/test_subroutine_falls_through_1_65ce02.stdout
A => jasm/unit_tests/results/test_subroutine_falls_through_2_65ce02.stdout
A => jasm/unit_tests/results/test_subroutine_falls_through_3_65ce02.stdout
A => jasm/unit_tests/results/test_subroutine_falls_through_4_65ce02.stdout
A => jasm/unit_tests/results/test_subroutine_falls_through_5_65ce02.stdout
A => jasm/unit_tests/test_addressing_mode_branch_too_long_1_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_branch_too_long_2_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_expected_x_in_indirect_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_expected_y_in_indirect_65c02.asm
A => jasm/unit_tests/test_addressing_mode_expected_y_or_z_in_indirect_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_immediate_value_too_large_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_immediate_value_too_small_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_is_illegal_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_needs_bit_size_argument_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_needs_byte_argument_1_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_needs_byte_argument_2_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_needs_byte_argument_3_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_needs_integer_argument_1_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_needs_integer_argument_2_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_needs_integer_argument_3_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_needs_integer_argument_4_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_needs_positive_argument_1_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_needs_positive_argument_2_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_needs_word_size_argument_1_65ce02.asm
A => jasm/unit_tests/test_addressing_mode_needs_word_size_argument_2_65ce02.asm
A => jasm/unit_tests/test_all_instructions_65ce02.asm
A => jasm/unit_tests/test_bank_mode_truncates_address_instructions_65ce02.asm
A => jasm/unit_tests/test_generate_data_in_instruction_1_65ce02.asm
A => jasm/unit_tests/test_instruction_data_global_label_65ce02.asm
A => jasm/unit_tests/test_instruction_data_label_cant_have_implied_addressing_mode_65ce02.asm
A => jasm/unit_tests/test_instruction_data_label_for_wrong_argument_type_3_65ce02.asm
A => jasm/unit_tests/test_instruction_data_label_has_lo_hi_properties_65ce02.asm
A => jasm/unit_tests/test_instruction_data_label_offsets_65ce02.asm
A => jasm/unit_tests/test_instruction_data_label_sizes_65ce02.asm
A => jasm/unit_tests/test_instruction_data_label_with_export_65ce02.asm
A => jasm/unit_tests/test_instruction_data_label_with_local_export_65ce02.asm
A => jasm/unit_tests/test_instruction_data_local_label_65ce02.asm
A => jasm/unit_tests/test_instruction_ends_at_newline_1_65ce02.asm
A => jasm/unit_tests/test_instruction_ends_at_newline_2_65ce02.asm
A => jasm/unit_tests/test_instruction_names_can_be_used_in_local_variables_65ce02.asm
A => jasm/unit_tests/test_instructions_must_be_in_code_sections_1_65ce02.asm
A => jasm/unit_tests/test_instructions_must_be_in_code_sections_2_65ce02.asm
A => jasm/unit_tests/test_pseudo_instructions_for_branching_65ce02.asm
A => jasm/unit_tests/test_pseudo_instructions_for_incrementing_65ce02.asm
A => jasm/unit_tests/test_pseudo_instructions_in_standard_mode_65ce02.asm
A => jasm/unit_tests/test_pseudo_instructions_use_names_in_standard_mode_65ce02.asm
A => jasm/unit_tests/test_register_names_can_be_used_in_local_names_65ce02.asm
A => jasm/unit_tests/test_register_names_cant_be_used_as_global_variables_65ce02.asm
A => jasm/unit_tests/test_subroutine_call_65ce02.asm
A => jasm/unit_tests/test_subroutine_call_must_be_in_code_section_65ce02.asm
A => jasm/unit_tests/test_subroutine_call_negative_argument_65ce02.asm
A => jasm/unit_tests/test_subroutine_call_recursive_data_generation_65ce02.asm
A => jasm/unit_tests/test_subroutine_call_too_large_argument_65ce02.asm
A => jasm/unit_tests/test_subroutine_call_with_arguments_65ce02.asm
A => jasm/unit_tests/test_subroutine_falls_through_1_65ce02.asm
A => jasm/unit_tests/test_subroutine_falls_through_2_65ce02.asm
A => jasm/unit_tests/test_subroutine_falls_through_3_65ce02.asm
A => jasm/unit_tests/test_subroutine_falls_through_4_65ce02.asm
A => jasm/unit_tests/test_subroutine_falls_through_5_65ce02.asm
M jasm/version.h
M jasm/website/site/docs/index.html
M jasm/website/site/index.html
M jasm/assemble/assembler_impl/assembler_impl.h +6 -1
@@ 36,6 36,10 @@ namespace jasm
 	{
 		class Processor65c02;
 	}
+	namespace csg65ce02
+	{
+		class Processor65ce02;
+	}
 
 class HexSourceWriter;
 

          
@@ 64,7 68,8 @@ class Assembler
 	friend mos6502::Processor6502;
 	friend z80::ProcessorZ80;
 	friend wdc65c02::Processor65c02;
-	
+	friend csg65ce02::Processor65ce02;
+
 public:
 	Assembler(
 		  bool multiple_output_files

          
M jasm/docs/jasm.md +50 -1
@@ 2,7 2,7 @@ 
 
 - - -
 
-This is the documentation for the 6502 and Z80 assembler jAsm. It was written in 2015 by me, Jonas Hultén, because I used DAsm before and over the years it started to feel outdated. I missed namespaces and I was annoyed by some bugs, like its inability to use local variables as macro arguments. It felt a bit slow on my slow laptop computer as well, although that wasn't a strong argument. Also, I hadn't written a language before and it felt like an interesting challenge.
+This is the documentation for the 6502, 65C02, 65CE02 and Z80 assembler jAsm. It was written in 2015 by me, Jonas Hultén, because I used DAsm before and over the years it started to feel outdated. I missed namespaces and I was annoyed by some bugs, like its inability to use local variables as macro arguments. It felt a bit slow on my slow laptop computer as well, although that wasn't a strong argument. Also, I hadn't written a language before and it felt like an interesting challenge.
 
 jAsm was written with two main goals. It should be fast enough to assemble a large program in under a second and it should support everything DAsm can do and more. To reach the required speed it tries to use memory as linearly as possible and it proved to be faster than DAsm in the end.
 

          
@@ 21,6 21,7 @@ This documentation covers the language a
 * [Processor Support](#processor-support)
    * [6502](#m6502)
    * [65c02](#wdc65c02)
+   * [65ce02](#csg65ce02)
    * [Z80](#z80)
 * [Starter Guide](#starter-guide)
    * [Basic Start](#starter-guide-basic-start)

          
@@ 56,6 57,7 @@ This documentation covers the language a
    * [Pseudo Instructions](#pseudo-instructions)
       * [6502 Pseudo Instructions](#6502-pseudo-instructions)
       * [65c02 Pseudo Instructions](#65c02-pseudo-instructions)
+      * [65ce02 Pseudo Instructions](#65ce02-pseudo-instructions)
       * [Z80 Pseudo Instructions](#z80-pseudo-instructions)
    * [Verboseness](#verboseness)
    * [Return Codes](#return-codes)

          
@@ 148,6 150,30 @@ The bit operation instructions don't hav
 	rmb 2, zp
 	smb 3, zp
 
+<div id="csg65ce02"></div>
+## 65CE02
+
+jAsm supports all regular instructions of the Commodore Semiconductor Group 65CE02. Instructions are written in lower case.
+
+	[65ce02]
+	ldz $d020
+	bru loop
+
+Just like 65C02, the bit operation instructions don't have the bit in the instruction name as some assemblers do. Instead it is a separate argument. To follow convention, there is no '#' before the bit number to indicate immediate mode, even if that would be more consistent.
+
+	[65ce02]
+	bbr 0, zp, label
+	bbs 1, zp, label
+	rmb 2, zp
+	smb 3, zp
+
+The aug instruction isn't available since that's intended to extend the processor with more instructions in the future.
+
+The stack pointer relative access addressing mode is written like this.
+
+	[65ce02]
+	lda ($55,sp),y
+
 <div id="z80"></div>
 ## Z80
 

          
@@ 1252,6 1278,29 @@ These are equivalent to `[65c02]|bcs` an
 
 These are equivalent to the implied mode `[65c02]|dec` and `[65c02]|inc`, respectively.
 
+<div id="65ce02-pseudo-instructions"></div>
+### 65CE02 pseudo instructions
+
+These are the pseudo instructions for 65CE02.
+
+	[65ce02]
+	bhs addr // branch if higher or same
+	blt addr // branch if lower
+
+These are equivalent to `[65ce02]|bcs` and `[65ce02]|bcc`, respectively.
+
+	[65ce02]
+	dea // decrement A register
+	ina // increment A register
+
+These are equivalent to the implied mode `[65ce02]|dec` and `[65ce02]|inc`, respectively.
+
+	[65ce02]
+	bra label // branch unconditionally
+
+This is equivalent to the `[65ce02]|bru` instruction.
+
+
 <div id="z80-pseudo-instructions"></div>
 ### Z80 pseudo instructions
 

          
M jasm/docs/syntax_highlight.py +5 -2
@@ 46,7 46,8 @@ def syntax_highlight_code(code_class, te
 	keywords = re.compile(r'\b(address|align|basic|bss|byte|code|const|declare|define|dynamic|elif|else|enum|export|fill|for|function|if|import|incbin|include|long|macro|mapping|module|namespace|optimize|part|pop|processor|reserve|return|section|struct|subroutine|using|var|word)\b')
 	functions = re.compile(r'\b(abs|acos|asin|atan|atan2|ceil|clamp|cos|cosh|degrees|exp|float|floor|format|hexstring|int|lerp|log|log10|logn|max|min|modulo|offsetof|pow|print|radians|remainder|round|select|sin|sinh|sizeof|sqrt|static_assert|string|symbol|tan|tanh|unicode|uppercase|lowercase)\b')
 	instructions_6502 = re.compile(r'\b(adc|and|asl|bcc|bcs|beq|bit|bmi|bne|bpl|brk|bvc|bvs|clc|cld|cli|clv|cmp|cpx|cpy|dec|dex|dey|eor|inc|inx|iny|jmp|jsr|lda|ldx|ldy|lsr|nop|ora|pha|php|pla|plp|rol|ror|rti|rts|sbc|sec|sed|sei|sta|stx|sty|tax|tay|tsx|txa|txs|tya|bhs|blt)\b')
-	instructions_65c02 = re.compile(r'\b(adc|and|asl|bbr|bbs|bcc|bcs|beq|bit|bmi|bne|bpl|bra|brk|bvc|bvs|clc|cld|cli|clv|cmp|cpx|cpy|dec|dex|dey|eor|inc|inx|iny|jmp|jsr|lda|ldx|ldy|lsr|nop|ora|pha|php|phx|phy|pla|plp|plx|ply|rmb|rol|ror|rti|rts|sbc|sec|sed|sei|smb|sta|stp|stx|sty|stz|tax|tay|trb|tsx|txa|txs|tya|wai|bhs|blt|dea|ina)\b')
+	instructions_65c02 = re.compile(r'\b(adc|and|asl|bbr|bbs|bcc|bcs|beq|bit|bmi|bne|bpl|bra|brk|bvc|bvs|clc|cld|cli|clv|cmp|cpx|cpy|dec|dex|dey|eor|inc|inx|iny|jmp|jsr|lda|ldx|ldy|lsr|nop|ora|pha|php|phx|phy|pla|plp|plx|ply|rmb|rol|ror|rti|rts|sbc|sec|sed|sei|smb|sta|stp|stx|sty|stz|tax|tay|trb|tsb|tsx|txa|txs|tya|wai|bhs|blt|dea|ina)\b')
+	instructions_65ce02 = re.compile(r'\b(adc|and|asl|asr|asw|bbr|bbs|bcc|bcs|beq|bit|bmi|bne|bpl|bru|brk|bsr|bvc|bvs|clc|cld|cle|cli|clv|cmp|cpx|cpy|cpz|dec|dew|dex|dey|dez|eor|inc|inw|inx|iny|inz|jmp|jsr|lda|ldx|ldy|ldz|lsr|neg|nop|ora|pha|php|phw|phx|phy|phz|pla|plp|plx|ply|plz|rmb|rol|ror|row|rti|rtn|rts|sbc|sec|sed|see|sei|smb|sta|stx|sty|stz|tab|tax|tay|taz|tba|trb|tsb|tsx|tsy|txa|txs|tya|tys|tza|bhs|blt|bra|dea|ina)\b')
 	instructions_z80 = re.compile(r'\b(adc|add|and|bit|call|ccf|cp|cpd|cpdr|cpi|cpir|cpl|daa|dec|di|djnz|ei|ex|exx|halt|im|in|inc|ind|indr|ini|inir|jp|jr|ld|ldd|lddr|ldi|ldir|neg|nop|or|otdr|otir|out|outd|outi|pop|push|res|ret|reti|retn|rl|rla|rlc|rlca|rld|rr|rra|rrc|rrca|rrd|rst|sbc|scf|set|sla|sra|srl|sub|xor)\b')
 	operators = re.compile(r'(<<=|>>=|&amp;&amp;=|[|][|]=|!=|[+][+]|--|<<|>>|<=|>=|==|&amp;&amp;|[|][|]|[+]=|-=|[*]=|[/]=|&amp;=|[|]=|\^=|::|!|~|[*]|[/]|[+]|-|&lt;|&gt;|&amp;|\^|[|]|=|#|%)')
 	special = re.compile(r'({|}|\(|\)|;|\[|\])')

          
@@ 81,6 82,8 @@ def syntax_highlight_code(code_class, te
 		text = colorize(text, instructions_6502, "instruction")
 	elif code_class == "[65c02]":
 		text = colorize(text, instructions_65c02, "instruction")
+	elif code_class == "[65ce02]":
+		text = colorize(text, instructions_65ce02, "instruction")
 	else:
 		text = colorize(text, instructions_z80, "instruction")
 

          
@@ 114,7 117,7 @@ def syntax_highlight_code(code_class, te
 
 
 def syntax_highlight_text(code_class, code):
-	if code_class == "[6502]" or code_class == "[65c02]" or code_class == "[z80]":
+	if code_class == "[6502]" or code_class == "[65c02]" or code_class == "[65ce02]" or code_class == "[z80]":
 		return syntax_highlight_code(code_class, code)
 	elif code_class == "[text]":
 		return code

          
M jasm/processor/65c02/instructions_65c02.cpp +2 -2
@@ 176,7 176,7 @@ OpCodes __opcodes[static_cast<int>(Instr
 	/* TAY */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x00}},
 	/* TRB */ {{0x14, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
 	/*           ZP , ABSO,  ZPX, ABSX,  ZPY, ABSY, ZPIN, INDI, ZPIX, INDX, ZPIY, IMPL, IMME,  ZB ,  ZBR, RELA,*/
-	/* TRB */ {{0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* TSB */ {{0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
 	/* TSX */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00}},
 	/* TXA */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00}},
 	/* TXS */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00}},

          
@@ 411,5 411,5 @@ std::string_view to_string(InstructionTy
 	return names[static_cast<size_t>(type)];
 }
 
-	} // namespace mos6502
+	} // namespace wdc65c02
 } // namespace jasm

          
M jasm/processor/65c02/instructions_65c02.h +1 -1
@@ 189,5 189,5 @@ std::string_view to_string(InstructionTy
 
 /// @}
 
-	} // namespace mos6502
+	} // namespace wdc65c02
 } // namespace jasm

          
M jasm/processor/65c02/processor_keywords_65c02.cpp +1 -1
@@ 20,5 20,5 @@ std::string_view to_string(ProcessorKeyw
 	return names[static_cast<size_t>(type)];
 }
 
-	} // namespace mos6502
+	} // namespace wdc65c02
 } // namespace jasm

          
M jasm/processor/65c02/processor_keywords_65c02.h +1 -1
@@ 21,5 21,5 @@ std::string_view to_string(ProcessorKeyw
 
 /// @}
 
-	} // namespace mos6502
+	} // namespace wdc65c02
 } // namespace jasm

          
A => jasm/processor/65ce02/instructions_65ce02.cpp +517 -0
@@ 0,0 1,517 @@ 
+#include "pch.h"
+
+#include <processor/65ce02/instructions_65ce02.h>
+
+namespace jasm
+{
+	namespace csg65ce02
+	{
+
+using namespace AddressingModeMask;
+
+/// All opcodes for one instruction.
+struct OpCodes
+{
+	uint8_t op_codes[static_cast<int>(AddressingModeType::NumAddressingModes)];
+};
+
+uint32_t __addressing_modes_mask[static_cast<int>(InstructionType::NumTypes)] = {
+	/*        Bp   Abs   Bpx   AbsX   Bpy   AbsY   BpIX   IndX   Rel   RelW   BpIY   BpIZ   SpIY   Ind   Imp   Imm   ImmW   Bb   Bbr */
+	/* ADC */ Bp | Abs | Bpx | AbsX | ___ | AbsY | BpIX | ____ | ___ | ____ | BpIY | BpIZ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* AND */ Bp | Abs | Bpx | AbsX | ___ | AbsY | BpIX | ____ | ___ | ____ | BpIY | BpIZ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* ASL */ Bp | Abs | Bpx | AbsX | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* ASR */ Bp | ___ | Bpx | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* ASW */ __ | Abs | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* BBR */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | Bbr ,
+	/* BBS */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | Bbr ,
+	/* BCC */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | Rel | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* BCS */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | Rel | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* BEQ */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | Rel | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* BIT */ Bp | Abs | Bpx | AbsX | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* BMI */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | Rel | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* BNE */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | Rel | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* BPL */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | Rel | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* BRK */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* BRU */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | Rel | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* BSR */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* BVC */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | Rel | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* BVS */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | Rel | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* CLC */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* CLD */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* CLE */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* CLI */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* CLV */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* CMP */ Bp | Abs | Bpx | AbsX | ___ | AbsY | BpIX | ____ | ___ | ____ | BpIY | BpIZ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* CPX */ Bp | Abs | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* CPY */ Bp | Abs | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* CPZ */ Bp | Abs | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* DEC */ Bp | Abs | Bpx | AbsX | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* DEW */ Bp | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* DEX */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* DEY */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* DEZ */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* EOR */ Bp | Abs | Bpx | AbsX | ___ | AbsY | BpIX | ____ | ___ | ____ | BpIY | BpIZ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* INC */ Bp | Abs | Bpx | AbsX | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* INW */ Bp | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* INX */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* INY */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* INZ */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* JMP */ __ | Abs | ___ | ____ | ___ | ____ | ____ | IndX | ___ | ____ | ____ | ____ | ____ | Ind | ___ | ___ | ____ | __ | ___ ,
+	/* JSR */ __ | Abs | ___ | ____ | ___ | ____ | ____ | IndX | ___ | ____ | ____ | ____ | ____ | Ind | ___ | ___ | ____ | __ | ___ ,
+	/* LDA */ Bp | Abs | Bpx | AbsX | ___ | AbsY | BpIX | ____ | ___ | ____ | BpIY | BpIZ | SpIY | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* LDX */ Bp | Abs | ___ | ____ | Bpy | AbsY | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* LDY */ Bp | Abs | Bpx | AbsX | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* LDZ */ __ | Abs | ___ | AbsX | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* LSR */ Bp | Abs | Bpx | AbsX | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* NEG */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* NOP */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* ORA */ Bp | Abs | Bpx | AbsX | ___ | AbsY | BpIX | ____ | ___ | ____ | BpIY | BpIZ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* PHA */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* PHP */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* PHW */ __ | Abs | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ImmW | __ | ___ ,
+	/* PHX */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* PHY */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* PHZ */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* PLA */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* PLP */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* PLX */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* PLY */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* PLZ */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* RMB */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | Bb | ___ ,
+	/* ROL */ Bp | Abs | Bpx | AbsX | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* ROR */ Bp | Abs | Bpx | AbsX | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* ROW */ __ | Abs | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* RTI */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* RTN */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* RTS */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* SBC */ Bp | Abs | Bpx | AbsX | ___ | AbsY | BpIX | ____ | ___ | ____ | BpIY | BpIZ | ____ | ___ | ___ | Imm | ____ | __ | ___ ,
+	/* SEC */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* SED */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* SEE */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* SEI */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* SMB */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | Bb | ___ ,
+	/* STA */ Bp | Abs | Bpx | AbsX | ___ | AbsY | BpIX | ____ | ___ | ____ | BpIY | BpIZ | SpIY | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* STX */ Bp | Abs | ___ | ____ | Bpy | AbsY | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* STY */ Bp | Abs | Bpx | AbsX | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* STZ */ Bp | Abs | Bpx | AbsX | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* TAB */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* TAX */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* TAY */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* TAZ */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* TBA */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* TRB */ Bp | Abs | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* TSB */ Bp | Abs | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* TSX */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* TSY */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* TXA */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* TXS */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* TYS */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* TYA */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* TZA */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+
+	/* BHS */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | Rel | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* BLT */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | Rel | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* BRA */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | Rel | RelW | ____ | ____ | ____ | ___ | ___ | ___ | ____ | __ | ___ ,
+	/* DEA */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+	/* INA */ __ | ___ | ___ | ____ | ___ | ____ | ____ | ____ | ___ | ____ | ____ | ____ | ____ | ___ | Imp | ___ | ____ | __ | ___ ,
+
+};
+
+OpCodes __opcodes[static_cast<int>(InstructionType::NumTypes)] = {
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* ADC */ {{0x65, 0x6d, 0x75, 0x7d, 0x00, 0x79, 0x61, 0x00, 0x00, 0x00, 0x71, 0x72, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00}},
+	/* AND */ {{0x25, 0x2d, 0x35, 0x3d, 0x00, 0x39, 0x21, 0x00, 0x00, 0x00, 0x31, 0x32, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00}},
+	/* ASL */ {{0x06, 0x0e, 0x16, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00}},
+	/* ASR */ {{0x44, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00}},
+	/* ASW */ {{0x00, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* BBR */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f}},
+	/* BBS */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f}},
+	/* BCC */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* BCS */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* BEQ */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* BIT */ {{0x24, 0x2c, 0x34, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00}},
+	/* BMI */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* BNE */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* BPL */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* BRK */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* BRU */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* BSR */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* BVC */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* BVS */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* CLC */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00}},
+	/* CLD */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00}},
+	/* CLE */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00}},
+	/* CLI */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00}},
+	/* CLV */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* CMP */ {{0xc5, 0xcd, 0xd5, 0xdd, 0x00, 0xd9, 0xc1, 0x00, 0x00, 0x00, 0xd1, 0xd2, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00}},
+	/* CPX */ {{0xe4, 0xec, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00}},
+	/* CPY */ {{0xc4, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00}},
+	/* CPZ */ {{0xd4, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00}},
+	/* DEC */ {{0xc6, 0xce, 0xd6, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* DEW */ {{0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* DEX */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0x00}},
+	/* DEY */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00}},
+	/* DEZ */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00}},
+	/* EOR */ {{0x45, 0x4d, 0x55, 0x5d, 0x00, 0x59, 0x41, 0x00, 0x00, 0x00, 0x51, 0x52, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* INC */ {{0xe6, 0xee, 0xf6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00}},
+	/* INW */ {{0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* INX */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00}},
+	/* INY */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00}},
+	/* INZ */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* JMP */ {{0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* JSR */ {{0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* LDA */ {{0xa5, 0xad, 0xb5, 0xbd, 0x00, 0xb9, 0xa1, 0x00, 0x00, 0x00, 0xb1, 0xb2, 0xe2, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00}},
+	/* LDX */ {{0xa6, 0xae, 0x00, 0x00, 0xb6, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00}},
+	/* LDY */ {{0xa4, 0xac, 0xb4, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* LDZ */ {{0x00, 0xab, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00}},
+	/* LSR */ {{0x46, 0x4e, 0x56, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00}},
+	/* NEG */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00}},
+	/* NOP */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0x00}},
+	/* ORA */ {{0x05, 0x0d, 0x15, 0x1d, 0x00, 0x19, 0x01, 0x00, 0x00, 0x00, 0x11, 0x12, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* PHA */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00}},
+	/* PHP */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00}},
+	/* PHW */ {{0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00}},
+	/* PHX */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00}},
+	/* PHY */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* PHZ */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x00}},
+	/* PLA */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00}},
+	/* PLP */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00}},
+	/* PLX */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x00}},
+	/* PLY */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* PLZ */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0x00}},
+	/* RMB */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00}},
+	/* ROL */ {{0x26, 0x2e, 0x36, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00}},
+	/* ROR */ {{0x66, 0x6e, 0x76, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00}},
+	/* ROW */ {{0x00, 0xeb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* RTI */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00}},
+	/* RTN */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00}},
+	/* RTS */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00}},
+	/* SBC */ {{0xe5, 0xed, 0xf5, 0xfd, 0x00, 0xf9, 0xe1, 0x00, 0x00, 0x00, 0xf1, 0xf2, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00}},
+	/* SEC */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* SED */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x00}},
+	/* SEE */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00}},
+	/* SEI */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00}},
+	/* SMB */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x00}},
+	/* STA */ {{0x85, 0x8d, 0x95, 0x9d, 0x00, 0x99, 0x81, 0x00, 0x00, 0x00, 0x91, 0x92, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* STX */ {{0x86, 0x8e, 0x00, 0x00, 0x96, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* STY */ {{0x84, 0x8c, 0x94, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* STZ */ {{0x64, 0x9c, 0x74, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* TAB */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00}},
+	/* TAX */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* TAY */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x00}},
+	/* TAZ */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00}},
+	/* TBA */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00}},
+	/* TRB */ {{0x14, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* TSB */ {{0x04, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* TSX */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00}},
+	/* TSY */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00}},
+	/* TXA */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00}},
+	/* TXS */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00}},
+	/* TYA */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00}},
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* TYS */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00}},
+	/* TZA */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00}},
+
+	/*           BP , ABSO,  BPX, ABSX,  BPY, ABSY, BPIX, INDX, RELA, RELW, BPIY, BPIZ, SPIY, INDI, IMPL, IMME, IMMW,  BB ,  BBR,*/
+	/* BHS */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* BLT */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* BRA */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+	/* DEA */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00}},
+	/* INA */ {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00}},
+};
+
+InstructionType __inverse_branch_instruction[static_cast<int>(InstructionType::NumTypes)] = {
+	/* ADC */ InstructionType::Brk,
+	/* AND */ InstructionType::Brk,
+	/* ASL */ InstructionType::Brk,
+	/* ASR */ InstructionType::Brk,
+	/* ASW */ InstructionType::Brk,
+	/* BBR */ InstructionType::Brk,
+	/* BBS */ InstructionType::Brk,
+	/* BCC */ InstructionType::Bcs,
+	/* BCS */ InstructionType::Bcc,
+	/* BEQ */ InstructionType::Bne,
+	/* BIT */ InstructionType::Brk,
+	/* BMI */ InstructionType::Bpl,
+	/* BNE */ InstructionType::Beq,
+	/* BPL */ InstructionType::Bmi,
+	/* BRK */ InstructionType::Brk,
+	/* BRU */ InstructionType::Brk,
+	/* BSR */ InstructionType::Brk,
+	/* BVC */ InstructionType::Bvs,
+	/* BVS */ InstructionType::Bvc,
+	/* CLC */ InstructionType::Brk,
+	/* CLD */ InstructionType::Brk,
+	/* CLE */ InstructionType::Brk,
+	/* CLI */ InstructionType::Brk,
+	/* CLV */ InstructionType::Brk,
+	/* CMP */ InstructionType::Brk,
+	/* CPX */ InstructionType::Brk,
+	/* CPY */ InstructionType::Brk,
+	/* CPZ */ InstructionType::Brk,
+	/* DEC */ InstructionType::Brk,
+	/* DEW */ InstructionType::Brk,
+	/* DEX */ InstructionType::Brk,
+	/* DEY */ InstructionType::Brk,
+	/* DEZ */ InstructionType::Brk,
+	/* EOR */ InstructionType::Brk,
+	/* INC */ InstructionType::Brk,
+	/* INW */ InstructionType::Brk,
+	/* INX */ InstructionType::Brk,
+	/* INY */ InstructionType::Brk,
+	/* INZ */ InstructionType::Brk,
+	/* JMP */ InstructionType::Brk,
+	/* JSR */ InstructionType::Brk,
+	/* LDA */ InstructionType::Brk,
+	/* LDX */ InstructionType::Brk,
+	/* LDY */ InstructionType::Brk,
+	/* LDZ */ InstructionType::Brk,
+	/* LSR */ InstructionType::Brk,
+	/* NEG */ InstructionType::Brk,
+	/* NOP */ InstructionType::Brk,
+	/* ORA */ InstructionType::Brk,
+	/* PHA */ InstructionType::Brk,
+	/* PHP */ InstructionType::Brk,
+	/* PHW */ InstructionType::Brk,
+	/* PHX */ InstructionType::Brk,
+	/* PHY */ InstructionType::Brk,
+	/* PHZ */ InstructionType::Brk,
+	/* PLA */ InstructionType::Brk,
+	/* PLP */ InstructionType::Brk,
+	/* PLX */ InstructionType::Brk,
+	/* PLY */ InstructionType::Brk,
+	/* PLZ */ InstructionType::Brk,
+	/* RMB */ InstructionType::Brk,
+	/* ROL */ InstructionType::Brk,
+	/* ROR */ InstructionType::Brk,
+	/* RTI */ InstructionType::Brk,
+	/* RTN */ InstructionType::Brk,
+	/* RTS */ InstructionType::Brk,
+	/* SBC */ InstructionType::Brk,
+	/* SEC */ InstructionType::Brk,
+	/* SED */ InstructionType::Brk,
+	/* SEI */ InstructionType::Brk,
+	/* SMB */ InstructionType::Brk,
+	/* STA */ InstructionType::Brk,
+	/* STX */ InstructionType::Brk,
+	/* STY */ InstructionType::Brk,
+	/* STZ */ InstructionType::Brk,
+	/* TAB */ InstructionType::Brk,
+	/* TAX */ InstructionType::Brk,
+	/* TAY */ InstructionType::Brk,
+	/* TAZ */ InstructionType::Brk,
+	/* TBA */ InstructionType::Brk,
+	/* TRB */ InstructionType::Brk,
+	/* TSB */ InstructionType::Brk,
+	/* TSX */ InstructionType::Brk,
+	/* TSY */ InstructionType::Brk,
+	/* TXA */ InstructionType::Brk,
+	/* TXS */ InstructionType::Brk,
+	/* TYA */ InstructionType::Brk,
+	/* TYS */ InstructionType::Brk,
+	/* TZA */ InstructionType::Brk,
+
+	/* BHS */ InstructionType::Blt,
+	/* BLT */ InstructionType::Bhs,
+	/* BRA */ InstructionType::Brk,
+	/* DEA */ InstructionType::Brk,
+	/* INA */ InstructionType::Brk,
+
+/*
+	Tza,
+	// end of standard instructions
+	Bhs, // branch if higher or same
+	NumStandard = Bhs,
+	Blt, // branch if less than
+	Bra, // BRU
+	Dea, // DEC A
+	Ina, // INC A
+*/
+	
+};
+
+uint32_t addressing_modes(InstructionType instruction)
+{
+	assert(instruction < InstructionType::NumTypes);
+	return __addressing_modes_mask[static_cast<int>(instruction)];
+}
+
+uint8_t opcode(InstructionType instruction, AddressingModeType addr_mode)
+{
+	assert(instruction < InstructionType::NumTypes);
+	assert(addr_mode < AddressingModeType::NumAddressingModes);
+	return __opcodes[static_cast<int>(instruction)].op_codes[static_cast<int>(addr_mode)];
+}
+
+InstructionType inverse_branch(InstructionType instruction)
+{
+	assert(instruction < InstructionType::NumTypes);
+	return __inverse_branch_instruction[static_cast<int>(instruction)];
+}
+
+bool is_ending_instruction(InstructionType type)
+{
+	return
+		   type == InstructionType::Brk
+		|| type == InstructionType::Bru
+		|| type == InstructionType::Bra
+		|| type == InstructionType::Jmp
+		|| type == InstructionType::Rti
+		|| type == InstructionType::Rts;
+}
+
+std::string_view to_string(AddressingModeType type)
+{
+	const static std::string_view names[] = {
+		std::string_view("base page address"),
+		std::string_view("absolute address"),
+		std::string_view("base page address with x offset"),
+		std::string_view("absolute address with x offset"),
+		std::string_view("base page address with y offset"),
+		std::string_view("absolute address with y offset"),
+		std::string_view("indirect base page address with x offset"),
+		std::string_view("indirect absolute address with x offset"),
+		std::string_view("byte relative address"),
+		std::string_view("word relative address"),
+		std::string_view("indirect base page address with y offset"),
+		std::string_view("indirect base page address with z offset"),
+		std::string_view("indirect stack page address with y offset"),
+		std::string_view("absolute indirect"),
+		std::string_view("implied"),
+		std::string_view("immediate"),
+		std::string_view("immediate word"),
+		std::string_view("bit, base page"),
+		std::string_view("bit, base page, relative"),
+	};
+	static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(AddressingModeType::NumAddressingModes), "Number of addressing modes doesn't match number of strings");
+
+	assert(type < AddressingModeType::NumAddressingModes);
+	return names[static_cast<size_t>(type)];
+}
+
+std::string_view to_string(InstructionType type)
+{
+	static const std::string_view names[] = {
+		std::string_view("adc"),
+		std::string_view("and"),
+		std::string_view("asl"),
+		std::string_view("asr"),
+		std::string_view("asw"),
+		std::string_view("bbr"),
+		std::string_view("bbs"),
+		std::string_view("bcc"),
+		std::string_view("bcs"),
+		std::string_view("beq"),
+		std::string_view("bit"),
+		std::string_view("bmi"),
+		std::string_view("bne"),
+		std::string_view("bpl"),
+		std::string_view("brk"),
+		std::string_view("bru"),
+		std::string_view("bsr"),
+		std::string_view("bvc"),
+		std::string_view("bvs"),
+		std::string_view("clc"),
+		std::string_view("cld"),
+		std::string_view("cle"),
+		std::string_view("cli"),
+		std::string_view("clv"),
+		std::string_view("cmp"),
+		std::string_view("cpx"),
+		std::string_view("cpy"),
+		std::string_view("cpz"),
+		std::string_view("dec"),
+		std::string_view("dew"),
+		std::string_view("dex"),
+		std::string_view("dey"),
+		std::string_view("dez"),
+		std::string_view("eor"),
+		std::string_view("inc"),
+		std::string_view("inw"),
+		std::string_view("inx"),
+		std::string_view("iny"),
+		std::string_view("inz"),
+		std::string_view("jmp"),
+		std::string_view("jsr"),
+		std::string_view("lda"),
+		std::string_view("ldx"),
+		std::string_view("ldy"),
+		std::string_view("ldz"),
+		std::string_view("lsr"),
+		std::string_view("neg"),
+		std::string_view("nop"),
+		std::string_view("ora"),
+		std::string_view("pha"),
+		std::string_view("php"),
+		std::string_view("phw"),
+		std::string_view("phx"),
+		std::string_view("phy"),
+		std::string_view("phz"),
+		std::string_view("pla"),
+		std::string_view("plp"),
+		std::string_view("plx"),
+		std::string_view("ply"),
+		std::string_view("plz"),
+		std::string_view("rmb"),
+		std::string_view("rol"),
+		std::string_view("ror"),
+		std::string_view("row"),
+		std::string_view("rti"),
+		std::string_view("rtn"),
+		std::string_view("rts"),
+		std::string_view("sbc"),
+		std::string_view("sec"),
+		std::string_view("sed"),
+		std::string_view("see"),
+		std::string_view("sei"),
+		std::string_view("smb"),
+		std::string_view("sta"),
+		std::string_view("stx"),
+		std::string_view("sty"),
+		std::string_view("stz"),
+		std::string_view("tab"),
+		std::string_view("tax"),
+		std::string_view("tay"),
+		std::string_view("taz"),
+		std::string_view("tba"),
+		std::string_view("trb"),
+		std::string_view("tsb"),
+		std::string_view("tsx"),
+		std::string_view("tsy"),
+		std::string_view("txa"),
+		std::string_view("txs"),
+		std::string_view("tya"),
+		std::string_view("tys"),
+		std::string_view("tza"),
+
+		std::string_view("bhs"),
+		std::string_view("blt"),
+		std::string_view("bra"),
+		std::string_view("dea"),
+		std::string_view("ina"),
+	};
+	static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(InstructionType::NumTypes), "Number of instructions doesn't match number of strings");
+
+	assert(type < InstructionType::NumTypes);
+	return names[static_cast<size_t>(type)];
+}
+
+	} // namespace csg65ce02
+} // namespace jasm

          
A => jasm/processor/65ce02/instructions_65ce02.h +221 -0
@@ 0,0 1,221 @@ 
+#pragma once
+
+#include <processor/instructions_common.h>
+
+namespace jasm
+{
+	namespace csg65ce02
+	{
+	
+/// @addtogroup assemble
+/// @{
+
+enum class InstructionType : uint8_t
+{
+	Adc,
+	And,
+	Asl,
+	Asr,
+	Asw,
+	Bbr,
+	Bbs,
+	Bcc,
+	Bcs,
+	Beq,
+	Bit,
+	Bmi,
+	Bne,
+	Bpl,
+	Brk,
+	Bru,
+	Bsr,
+	Bvc,
+	Bvs,
+	Clc,
+	Cld,
+	Cle,
+	Cli,
+	Clv,
+	Cmp,
+	Cpx,
+	Cpy,
+	Cpz,
+	Dec,
+	Dew,
+	Dex,
+	Dey,
+	Dez,
+	Eor,
+	Inc,
+	Inw,
+	Inx,
+	Iny,
+	Inz,
+	Jmp,
+	Jsr,
+	Lda,
+	Ldx,
+	Ldy,
+	Ldz,
+	Lsr,
+	Neg,
+	Nop,
+	Ora,
+	Pha,
+	Php,
+	Phw,
+	Phx,
+	Phy,
+	Phz,
+	Pla,
+	Plp,
+	Plx,
+	Ply,
+	Plz,
+	Rmb,
+	Rol,
+	Ror,
+	Row,
+	Rti,
+	Rtn,
+	Rts,
+	Sbc,
+	Sec,
+	Sed,
+	See,
+	Sei,
+	Smb,
+	Sta,
+	Stx,
+	Sty,
+	Stz,
+	Tab,
+	Tax,
+	Tay,
+	Taz,
+	Tba,
+	Trb,
+	Tsb,
+	Tsx,
+	Tsy,
+	Txa,
+	Txs,
+	Tya,
+	Tys,
+	Tza,
+	// end of standard instructions
+	Bhs, // branch if higher or same
+	NumStandard = Bhs,
+	Blt, // branch if less than
+	Bra, // BRU
+	Dea, // DEC A
+	Ina, // INC A
+	
+	NumTypes,
+};
+
+enum class AddressingModeType
+{
+	// these must be in base-page-non-base-page order
+	// because the instruction generation relies on it
+	BasePageAddr,
+	AbsoluteAddr,
+	BasePageIndexX,
+	AbsoluteIndexX,
+	BasePageIndexY,
+	AbsoluteIndexY,
+	BasePageIndirectIndexX,
+	AbsoluteIndirectIndexX,
+	RelativeAddr,
+	RelativeWordAddr,
+
+	BasePageIndirectIndexY,
+	BasePageIndirectIndexZ,
+	StackIndirectIndexY,
+	AbsoluteIndirect,
+	Implied,
+	Immediate,
+	ImmediateWord,
+	BitBp,
+	BitBpRel,
+
+	NumAddressingModes,
+};
+
+// fake enum to be able to shorten the table in the cpp file
+namespace AddressingModeMask
+{
+	enum
+	{
+		Bp = 1 << static_cast<int>(AddressingModeType::BasePageAddr),
+		Abs = 1 << static_cast<int>(AddressingModeType::AbsoluteAddr),
+		Bpx = 1 << static_cast<int>(AddressingModeType::BasePageIndexX),
+		AbsX = 1 << static_cast<int>(AddressingModeType::AbsoluteIndexX),
+		Bpy = 1 << static_cast<int>(AddressingModeType::BasePageIndexY),
+		AbsY = 1 << static_cast<int>(AddressingModeType::AbsoluteIndexY),
+		BpIX = 1 << static_cast<int>(AddressingModeType::BasePageIndirectIndexX),
+		IndX = 1 << static_cast<int>(AddressingModeType::AbsoluteIndirectIndexX),
+		Rel = 1 << static_cast<int>(AddressingModeType::RelativeAddr),
+		RelW = 1 << static_cast<int>(AddressingModeType::RelativeWordAddr),
+		
+		BpIY = 1 << static_cast<int>(AddressingModeType::BasePageIndirectIndexY),
+		BpIZ = 1 << static_cast<int>(AddressingModeType::BasePageIndirectIndexZ),
+		SpIY = 1 << static_cast<int>(AddressingModeType::StackIndirectIndexY),
+		Ind = 1 << static_cast<int>(AddressingModeType::AbsoluteIndirect),
+		Imp = 1 << static_cast<int>(AddressingModeType::Implied),
+		Imm = 1 << static_cast<int>(AddressingModeType::Immediate),
+		ImmW = 1 << static_cast<int>(AddressingModeType::ImmediateWord),
+		Bb = 1 << static_cast<int>(AddressingModeType::BitBp),
+		Bbr = 1 << static_cast<int>(AddressingModeType::BitBpRel),
+		
+		__ = 0,
+		___ = 0,
+		____ = 0,
+	};
+}
+
+/// Select the byte mode version of a combined byte and word mode addressing mode.
+inline uint32_t select_byte_mode(uint32_t a)
+{
+	return static_cast<uint32_t>(a & 0b0101010101);
+}
+
+/// Select the word mode version of a combined byte and word mode addressing mode.
+inline uint32_t select_word_mode(uint32_t a)
+{
+	return static_cast<uint32_t>(a & 0b1010101010);
+}
+
+/// Convert a bitmask with one bit set to an addressing mode.
+inline AddressingModeType mask_to_addressing_mode(uint32_t mask)
+{
+	int result = 0;
+	result += ((mask & 0b1111111100000000) != 0) ? 8 : 0;
+	result += ((mask & 0b1111000011110000) != 0) ? 4 : 0;
+	result += ((mask & 0b1100110011001100) != 0) ? 2 : 0;
+	result += ((mask & 0b1010101010101010) != 0) ? 1 : 0;
+	return static_cast<AddressingModeType>(result);
+}
+
+/// Get the addressing mode mask with bits set for each AddressingModeTypes value.
+uint32_t addressing_modes(InstructionType instruction);
+
+/// Returns the opcode for an instruction and addressing mode.
+uint8_t opcode(InstructionType instruction, AddressingModeType addr_mode);
+
+/// Returns the instruction for the opposite branch instruction.
+/// Call it with bcc and get bcs for example.
+InstructionType inverse_branch(InstructionType instruction);
+
+/// Returns true if the instruction doesn't provide a fall-through branch.
+bool is_ending_instruction(InstructionType type);
+
+/// Convert an addressing mode to a string for printing.
+std::string_view to_string(AddressingModeType type);
+
+std::string_view to_string(InstructionType type);
+
+/// @}
+
+	} // namespace csg65ce02
+} // namespace jasm

          
A => jasm/processor/65ce02/processor_65ce02.cpp +1061 -0
@@ 0,0 1,1061 @@ 
+#include "pch.h"
+
+#include <algorithm>
+#include <assemble/assembler_impl/assembler_impl.h>
+#include <assemble/scope_counter.h>
+#include <exceptions/assembly_exception.h>
+#include <io/hex_source_writer.h>
+#include <processor/65ce02/processor_65ce02.h>
+#include <processor/65ce02/processor_keywords_65ce02.h>
+#include <sstream>
+#include <syntax/syntax_parser.h>
+#include <syntax/syntax_tokens.h>
+#include <tokenize/tokens.h>
+
+namespace jasm
+{
+	namespace csg65ce02
+	{
+
+namespace
+{
+	enum
+	{
+		Bp = 1 << static_cast<int>(AddressingModeType::BasePageAddr),
+		Abs = 1 << static_cast<int>(AddressingModeType::AbsoluteAddr),
+		Bpx = 1 << static_cast<int>(AddressingModeType::BasePageIndexX),
+		AbsX = 1 << static_cast<int>(AddressingModeType::AbsoluteIndexX),
+		Bpy = 1 << static_cast<int>(AddressingModeType::BasePageIndexY),
+		AbsY = 1 << static_cast<int>(AddressingModeType::AbsoluteIndexY),
+		BpIX = 1 << static_cast<int>(AddressingModeType::BasePageIndirectIndexX),
+		IndX = 1 << static_cast<int>(AddressingModeType::AbsoluteIndirectIndexX),
+		Rel = 1 << static_cast<int>(AddressingModeType::RelativeAddr),
+		RelW = 1 << static_cast<int>(AddressingModeType::RelativeWordAddr),
+		BpIY = 1 << static_cast<int>(AddressingModeType::BasePageIndirectIndexY),
+		BpIZ = 1 << static_cast<int>(AddressingModeType::BasePageIndirectIndexZ),
+		SpIY = 1 << static_cast<int>(AddressingModeType::StackIndirectIndexY),
+		Ind = 1 << static_cast<int>(AddressingModeType::AbsoluteIndirect),
+		Imp = 1 << static_cast<int>(AddressingModeType::Implied),
+		Imm = 1 << static_cast<int>(AddressingModeType::Immediate),
+		ImmW = 1 << static_cast<int>(AddressingModeType::ImmediateWord),
+		Bb = 1 << static_cast<int>(AddressingModeType::BitBp),
+		Bbr = 1 << static_cast<int>(AddressingModeType::BitBpRel),
+	};
+}
+
+struct InstructionToken : public SyntaxToken
+{
+	InstructionType instruction;
+	uint8_t padding1[3];
+	uint32_t addressing_modes; ///< Mask with InstructionType bits set for each possible addressing mode.
+	// 8 byte aligned
+	SourceLocation source_location; ///< Source location to instruction.
+	SourceLocation address_label_location[3]; ///< Source location to address label, if existing.
+	// 8 byte aligned
+	bool has_instruction_data_label[3]; ///< True if there is a label defined that points to the instruction data.
+	bool global_data_label[3]; ///< True if the label is global.
+	uint8_t padding2[2];
+	// 8 byte aligned
+	uint64_t data_label_symbol_hash[3]; ///< Symbol to define as the data label.
+	// 8 byte aligned
+};
+
+void Processor65ce02::register_processor_keywords(std::vector<std::string> &keywords)
+{
+	add_type_tokens<ProcessorKeywordType>(keywords, TokenType::ProcessorKeyword);
+}
+
+void Processor65ce02::register_processor_instructions(bool pseudo_instructions)
+{
+	// generate instruction lookup
+	uint8_t num_instructions = static_cast<uint8_t>(pseudo_instructions ? InstructionType::NumTypes : InstructionType::NumStandard);
+	for (uint8_t i = 0; i < num_instructions; ++i) {
+		const std::string_view name = to_string(static_cast<InstructionType>(i));
+		_instructions.insert(core::murmur_hash3_string_x64_64(name)) = i;
+	}
+}
+
+bool Processor65ce02::allow_processor_keyword_with_prim(uint64_t &/*keyword_hash*/) const
+{
+	// no prim translation
+	return false;
+}
+
+std::string Processor65ce02::token_to_string(const Token &t) const
+{
+	std::stringstream ss;
+	if (jasm::is_instruction(t)) {
+		ss << "instruction";
+	} else {
+		ss << to_string(t.type);
+	}
+
+	switch (t.type) {
+	case TokenType::Whitespace:
+	case TokenType::Char:
+	case TokenType::Integer:
+	case TokenType::Float:
+	case TokenType::String:
+	case TokenType::End:
+	case TokenType::Newline:
+	case TokenType::Processor:
+	case TokenType::NumTypes:
+		break;
+
+	case TokenType::Symbol:
+	{
+		if (t.instruction_index != invalid_instruction) {
+			ss << " " << to_string(static_cast<InstructionType>(t.instruction_index));
+		}
+		break;
+	}
+
+	case TokenType::Boolean:
+		ss << " " << to_string(t.boolean_index);
+		break;
+
+	case TokenType::Operator:
+		ss << " " << to_string(t.operator_index);
+		break;
+
+	case TokenType::Keyword:
+		ss << " " << to_string(t.keyword_index);
+		break;
+
+	case TokenType::ProcessorKeyword:
+		ss << " " << to_string(static_cast<ProcessorKeywordType>(t.processor_keyword_index));
+		break;
+
+	case TokenType::Typename:
+		ss << " " << to_string(t.typename_index);
+		break;
+	}
+	return ss.str();
+}
+
+
+const Token *Processor65ce02::parse_optional_arg_label(SyntaxParser &parser, const Token *t, ArgLabel &label) const
+{
+	t = parser.skip_spaces_and_tabs(t);
+	if (parser.label_definition_follows(t)) {
+		label.enabled = true;
+		label.location = t->source_location;
+
+		t = parser.parse_symbol_definition(t, label.global, label.symbol_hash);
+		t = parser.consume_next_token(); // the colon
+		t = parser.skip_spaces_and_tabs(t);
+	}
+	return t;
+}
+
+const Token *Processor65ce02::skip_optional_arg_label(SyntaxParser &parser, const Token *t, const ArgLabel &label) const
+{
+	t = parser.skip_spaces_and_tabs(t);
+	if (label.enabled) {
+		bool global = false;
+		uint64_t hash = 0;
+		t = parser.parse_symbol_definition(t, global, hash);
+		t = parser.consume_next_token(); // the colon
+		t = parser.skip_spaces_and_tabs(t);
+	}
+	return t;
+}
+
+uint32_t Processor65ce02::try_parse_addressing_mode(SyntaxParser &parser, const std::vector<std::string> &source_files, const Token *t, std::array<ArgLabel, 3> &arg_labels) const
+{
+	// save read state to restore later since we are reading ahead.
+	TokenChainScope rewind_scope(parser.create_rewind_scope());
+
+	t = parse_optional_arg_label(parser, t, arg_labels[0]);
+
+	if (parser.is_operator(t, OperatorType::Hash)) {
+		// #...
+		// Immediate
+		// ImmediateWord
+		return
+			1 << static_cast<int>(AddressingModeType::Immediate) |
+			1 << static_cast<int>(AddressingModeType::ImmediateWord);
+	}
+	
+	if (parser.is_operator(t, OperatorType::LeftParenthesis)) {
+		// (<something>
+		// possibly indirect addressing mode but could also be an expression beginning with parenthesis
+		// BasePageAddr
+		// AbsoluteAddr
+		// BasePageIndexX
+		// AbsoluteIndexX
+		// BasePageIndexY
+		// AbsoluteIndexY
+		// BasePageIndirectIndexX
+		// AbsoluteIndirectIndexX
+		// RelativeAddr
+		// RelativeWordAddr
+		// BasePageIndirectIndexY
+		// BasePageIndirectIndexZ
+		// StackIndirectIndexY
+		// AbsoluteIndirect
+		// BitBp
+		// BitBpRel
+
+		// Try to parse an expression, ignoring the first parenthesis. That makes it possible to see
+		// if there is a comma within the parenthesis. This is not optimal for performance because
+		// it does more than it needs to for this.
+		const Token *next;
+		{
+			constexpr bool end_at_unmatched_right_parenthesis = true;
+			constexpr bool end_at_newline = true;
+			next = parser.parse_expression(parser.consume_next_token(), end_at_unmatched_right_parenthesis, end_at_newline);
+		}
+		if (parser.is_operator(next, OperatorType::Comma)) {
+			// (<expression>,
+			// BasePageIndirectIndexX
+			// AbsoluteIndirectIndexX
+			// StackIndirectIndexY
+
+			next = parser.consume_next_token(); // comma
+			next = parser.skip_spaces_and_tabs(next);
+
+			// check if "sp" follows
+			if (next->type == TokenType::ProcessorKeyword && static_cast<ProcessorKeywordType>(next->processor_keyword_index) == ProcessorKeywordType::SP) {
+				// (<expression>,sp
+				next = parser.consume_next_token(); // sp
+				next = parser.skip_spaces_and_tabs(next);
+				
+				if (next->type != TokenType::Operator || next->operator_index != OperatorType::RightParenthesis) {
+					std::stringstream ss;
+					ss << "Expected closing parenthesis in indirect addressing mode, but got " << token_to_string(*next);
+					throw AssemblyException(source_files, next->source_location, AssemblyErrorCodes::ExpectedEndingParenthesisInIndirectAddressingMode, ss.str());
+				}
+				// (<expression>,sp)
+				next = parser.consume_next_token(); // )
+				next = parser.parse_operator_on_same_line(next, OperatorType::Comma);
+				// (<expression>,sp),
+				next = parser.skip_spaces_and_tabs(next);
+				
+				// verify that "y" follows
+				if (next->type != TokenType::ProcessorKeyword || static_cast<ProcessorKeywordType>(next->processor_keyword_index) != ProcessorKeywordType::Y) {
+					std::stringstream ss;
+					ss << "Expected y for stack indirect addressing mode, but got " << token_to_string(*next);
+					throw AssemblyException(source_files, next->source_location, AssemblyErrorCodes::InvalidIndexRegisterInAddressingMode, ss.str());
+				}
+
+				return 1 << static_cast<int>(AddressingModeType::StackIndirectIndexY);
+			}
+			
+			// verify that "x" follows
+			if (next->type != TokenType::ProcessorKeyword || static_cast<ProcessorKeywordType>(next->processor_keyword_index) != ProcessorKeywordType::X) {
+				std::stringstream ss;
+				ss << "Expected x or sp for indirect addressing mode, but got " << token_to_string(*next);
+				throw AssemblyException(source_files, next->source_location, AssemblyErrorCodes::InvalidIndexRegisterInAddressingMode, ss.str());
+			}
+			// (<expression>,x
+
+			// verify that right parenthesis follows
+			next = parser.skip_spaces_and_tabs(parser.consume_next_token());
+			if (next->type != TokenType::Operator || next->operator_index != OperatorType::RightParenthesis) {
+				std::stringstream ss;
+				ss << "Expected closing parenthesis in indirect addressing mode, but got " << token_to_string(*next);
+				throw AssemblyException(source_files, next->source_location, AssemblyErrorCodes::ExpectedEndingParenthesisInIndirectAddressingMode, ss.str());
+			}
+			// (<expression>,x)
+
+			return
+				1 << static_cast<int>(AddressingModeType::BasePageIndirectIndexX) |
+				1 << static_cast<int>(AddressingModeType::AbsoluteIndirectIndexX);
+		}
+
+		if (parser.is_operator(next, OperatorType::RightParenthesis)) {
+			// (<expression>)...
+			// BasePageAddr
+			// AbsoluteAddr
+			// BasePageIndexX
+			// AbsoluteIndexX
+			// BasePageIndexY
+			// AbsoluteIndexY
+			// RelativeAddr
+			// RelativeWordAddr
+			// BasePageIndirectIndexY
+			// BasePageIndirectIndexZ
+			// AbsoluteIndirect
+			// BitBp
+			// BitBpRel
+
+			next = parser.skip_spaces_and_tabs(parser.consume_next_token());
+
+			if (next->type == TokenType::Operator && next->operator_index < OperatorType::NumOperatorFunctions) {
+				// (<expression>)<operator>
+				// BasePageAddr
+				// AbsoluteAddr
+				// BasePageIndexX
+				// AbsoluteIndexX
+				// BasePageIndexY
+				// AbsoluteIndexY
+				// RelativeAddr
+				// RelativeWordAddr
+				// BitBp
+				// BitBpRel
+
+				// go back and parse the whole thing to get to the end of the expression and check if it ends
+				// with ,x or ,y or ,something. This is not optimal from a performance perspective. I could write
+				// specialized code to skip an expression.
+				rewind_scope.rewind();
+				{
+					constexpr bool end_at_unmatched_right_parenthesis = false;
+					constexpr bool end_at_newline = true;
+					next = parser.parse_expression(t, end_at_unmatched_right_parenthesis, end_at_newline);
+				}
+
+				if (parser.is_operator(next, OperatorType::Comma)) {
+					// <expression>,
+					// BasePageIndexX
+					// AbsoluteIndexX
+					// BasePageIndexY
+					// AbsoluteIndexY
+					// BitBp
+					// BitBpRel
+					next = parser.skip_spaces_and_tabs(parser.consume_next_token());
+					if (next->type == TokenType::ProcessorKeyword && static_cast<ProcessorKeywordType>(next->processor_keyword_index) == ProcessorKeywordType::X) {
+						// <expression>,x
+						// BasePageIndexX
+						// AbsoluteIndexX
+						return
+							1 << static_cast<int>(AddressingModeType::BasePageIndexX) |
+							1 << static_cast<int>(AddressingModeType::AbsoluteIndexX);
+					}
+					if (next->type == TokenType::ProcessorKeyword && static_cast<ProcessorKeywordType>(next->processor_keyword_index) == ProcessorKeywordType::Y) {
+						// <expression>,y
+						// BasePageIndexY
+						// AbsoluteIndexY
+						return
+							1 << static_cast<int>(AddressingModeType::BasePageIndexY) |
+							1 << static_cast<int>(AddressingModeType::AbsoluteIndexY);
+					}
+					// <expression>, <expression>...
+					// BitBp
+					// BitBpRel
+					next = parse_optional_arg_label(parser, next, arg_labels[1]);
+					{
+						constexpr bool end_at_unmatched_right_parenthesis = false;
+						constexpr bool end_at_newline = true;
+						next = parser.parse_expression(next, end_at_unmatched_right_parenthesis, end_at_newline);
+					}
+					if (parser.is_operator(next, OperatorType::Comma)) {
+						// <expression>, <expression>, <expression>
+						// BitBpRel
+						next = parser.consume_next_token(); // comma
+						next = parse_optional_arg_label(parser, next, arg_labels[2]);
+						return 1 << static_cast<int>(AddressingModeType::BitBpRel);
+					}
+					
+					// <expression>, <expression>
+					// BitZp
+					return 1 << static_cast<int>(AddressingModeType::BitBp);
+				}
+				// (<expression>)<operator><expression>
+				// BasePageAddr
+				// AbsoluteAddr
+				// RelativeAddr
+				// RelativeWordAddr
+				return
+					1 << static_cast<int>(AddressingModeType::BasePageAddr) |
+					1 << static_cast<int>(AddressingModeType::AbsoluteAddr) |
+					1 << static_cast<int>(AddressingModeType::RelativeAddr) |
+					1 << static_cast<int>(AddressingModeType::RelativeWordAddr);
+			}
+			if (parser.is_operator(next, OperatorType::Comma)) {
+				// (<expression>),
+				// BasePageIndirectIndexY
+				// BasePageIndirectIndexZ
+
+				next = parser.skip_spaces_and_tabs(parser.consume_next_token());
+				if (next->type == TokenType::ProcessorKeyword && static_cast<ProcessorKeywordType>(next->processor_keyword_index) == ProcessorKeywordType::Y) {
+					// (<expression>),y
+					// BasePageIndirectIndexY
+					return 1 << static_cast<int>(AddressingModeType::BasePageIndirectIndexY);
+				}
+				if (next->type == TokenType::ProcessorKeyword && static_cast<ProcessorKeywordType>(next->processor_keyword_index) == ProcessorKeywordType::Z) {
+					// (<expression>),z
+					// BasePageIndirectIndexZ
+					return 1 << static_cast<int>(AddressingModeType::BasePageIndirectIndexZ);
+				}
+				// the index register is invalid
+				std::stringstream ss;
+				ss << "Invalid index register in addressing mode. Expected y or z but got " << token_to_string(*next);
+				throw AssemblyException(source_files, next->source_location, AssemblyErrorCodes::InvalidIndexRegisterInAddressingMode, ss.str());
+			}
+			// (<expression>)
+			// AbsoluteIndirect
+			return 1 << static_cast<int>(AddressingModeType::AbsoluteIndirect);
+		}
+
+		// no matching parenthesis was found
+		std::stringstream ss;
+		ss << "Unmatched left parenthesis in expression";
+		throw AssemblyException(source_files, t->source_location, AssemblyErrorCodes::UnmatchedLeftParenthesis, ss.str());
+	}
+
+	if (t->type == TokenType::Newline || parser.is_operator(t, OperatorType::Semicolon)) {
+		// Implied
+		return 1 << static_cast<int>(AddressingModeType::Implied);
+	}
+
+	// <expression>...
+	// BasePageAddr
+	// AbsoluteAddr
+	// BasePageIndexX
+	// AbsoluteIndexX
+	// BasePageIndexY
+	// AbsoluteIndexY
+	// RelativeAddr
+	// RelativeWordAddr
+	// BitBp
+	// BitBpRel
+	const Token *next;
+	{
+		constexpr bool end_at_unmatched_right_parenthesis = false;
+		constexpr bool end_at_newline = true;
+		next = parser.parse_expression(t, end_at_unmatched_right_parenthesis, end_at_newline);
+	}
+
+	if (parser.is_operator(next, OperatorType::Comma)) {
+		// <expression>,
+		// BasePageIndexX
+		// AbsoluteIndexX
+		// BasePageIndexY
+		// AbsoluteIndexY
+		// BitBp
+		// BitBpRel
+		next = parser.skip_spaces_and_tabs(parser.consume_next_token());
+		if (next->type == TokenType::ProcessorKeyword && static_cast<ProcessorKeywordType>(next->processor_keyword_index) == ProcessorKeywordType::X) {
+			// <expression>,x
+			// BasePageIndexX
+			// AbsoluteIndexX
+			return
+				1 << static_cast<int>(AddressingModeType::BasePageIndexX) |
+				1 << static_cast<int>(AddressingModeType::AbsoluteIndexX);
+		}
+		if (next->type == TokenType::ProcessorKeyword && static_cast<ProcessorKeywordType>(next->processor_keyword_index) == ProcessorKeywordType::Y) {
+			// <expression>,y
+			// BasePageIndexY
+			// AbsoluteIndexY
+			return
+				1 << static_cast<int>(AddressingModeType::BasePageIndexY) |
+				1 << static_cast<int>(AddressingModeType::AbsoluteIndexY);
+		}
+		// <expression>, <expression>...
+		// BitZp
+		// BitZpRel
+		next = parse_optional_arg_label(parser, next, arg_labels[1]);
+		{
+			constexpr bool end_at_unmatched_right_parenthesis = false;
+			constexpr bool end_at_newline = true;
+			next = parser.parse_expression(next, end_at_unmatched_right_parenthesis, end_at_newline);
+		}
+		if (parser.is_operator(next, OperatorType::Comma)) {
+			// <expression>, <expression>, <expression>
+			next = parser.consume_next_token();
+			next = parse_optional_arg_label(parser, next, arg_labels[2]);
+			return 1 << static_cast<int>(AddressingModeType::BitBpRel);
+		}
+		// <expression>, <expression>
+		// BitZp
+		return 1 << static_cast<int>(AddressingModeType::BitBp);
+	}
+	// <expression>
+	// BasePageAddr
+	// AbsoluteAddr
+	// RelativeAddr
+	// RelativeWordAddr
+	return
+		1 << static_cast<int>(AddressingModeType::BasePageAddr) |
+		1 << static_cast<int>(AddressingModeType::AbsoluteAddr) |
+		1 << static_cast<int>(AddressingModeType::RelativeAddr) |
+		1 << static_cast<int>(AddressingModeType::RelativeWordAddr);
+}
+
+void Processor65ce02::print_addressing_modes(std::stringstream &ss, uint32_t addressing_mode_mask)
+{
+	for (int i = 0; i < static_cast<int>(AddressingModeType::NumAddressingModes); ++i) {
+		if (((1U << i) & addressing_mode_mask) != 0)
+			ss << "\n  " << to_string(static_cast<AddressingModeType>(i));
+	}
+}
+
+const Token *Processor65ce02::parse_instruction(SyntaxParser &parser, const std::vector<std::string> &source_files, const Token *t, uint8_t /*InstructionType*/ instruction_index) const
+{
+	InstructionType instruction = static_cast<InstructionType>(instruction_index);
+	const Token *begin_token = t;
+
+	t = parser.consume_next_token(); // instruction token
+	t = parser.skip_spaces_and_tabs(t);
+
+	// determine possible used addressing modes and compare with existing
+	std::array<ArgLabel, 3> arg_labels;
+	uint32_t parsed_addressing_modes = try_parse_addressing_mode(parser, source_files, t, arg_labels);
+	uint32_t possible_addressing_modes = addressing_modes(instruction);
+	uint32_t selected_addressing_modes = parsed_addressing_modes & possible_addressing_modes;
+	if (selected_addressing_modes == 0) {
+		std::stringstream ss;
+		ss << "Invalid addressing mode used. Code indicates one of the following:";
+		print_addressing_modes(ss, parsed_addressing_modes);
+		ss << "\nbut possible addressing modes for " << to_string(instruction) << " are:";
+		print_addressing_modes(ss, possible_addressing_modes);
+		throw AssemblyException(source_files, t->source_location, AssemblyErrorCodes::InvalidAddressingMode, ss.str());
+	}
+	
+	// store the instruction with addressing mode mask in the output
+	InstructionToken &instruction_token = parser.reserve_token_space<InstructionToken>();
+	instruction_token.type = SyntaxTokenType::Instruction;
+	instruction_token.processor = ProcessorType::Csg65ce02;
+	instruction_token.size = sizeof(InstructionToken);
+	instruction_token.instruction = instruction;
+	instruction_token.addressing_modes = selected_addressing_modes;
+	instruction_token.source_location = begin_token->source_location;
+	instruction_token.has_instruction_data_label[0] = arg_labels[0].enabled;
+	instruction_token.has_instruction_data_label[1] = arg_labels[1].enabled;
+	instruction_token.has_instruction_data_label[2] = arg_labels[2].enabled;
+	instruction_token.global_data_label[0] = arg_labels[0].global;
+	instruction_token.global_data_label[1] = arg_labels[1].global;
+	instruction_token.global_data_label[2] = arg_labels[2].global;
+	instruction_token.address_label_location[0] = arg_labels[0].location;
+	instruction_token.address_label_location[1] = arg_labels[1].location;
+	instruction_token.address_label_location[2] = arg_labels[2].location;
+	instruction_token.data_label_symbol_hash[0] = arg_labels[0].symbol_hash;
+	instruction_token.data_label_symbol_hash[1] = arg_labels[1].symbol_hash;
+	instruction_token.data_label_symbol_hash[2] = arg_labels[2].symbol_hash;
+
+	// now we should be able to parse the operand of the instruction
+	if (selected_addressing_modes == Imp) {
+		if (arg_labels[0].enabled) {
+			std::stringstream ss;
+			ss << "Implied addressing modes cannot have label to instruction data. Add a newline or a semicolon before the label to resolve this.";
+			throw AssemblyException(source_files, arg_labels[0].location, AssemblyErrorCodes::AddressingModeCannotHaveDataLabel, ss.str());
+		}
+		return t;
+	}
+
+	t = skip_optional_arg_label(parser, t, arg_labels[0]);
+
+	if ((selected_addressing_modes & (Imm | ImmW)) != 0) {
+		assert(parser.is_operator(t, OperatorType::Hash));
+		t = parser.consume_next_token(); // hash
+		constexpr bool end_at_unmatched_parenthesis = false;
+		constexpr bool end_at_newline = true;
+		return parser.parse_and_output_expression(t, end_at_unmatched_parenthesis, end_at_newline);
+	}
+
+	// an indirect mode with x or sp inside parenthesis
+	if ((selected_addressing_modes & (BpIX | IndX | SpIY)) != 0) {
+		// skip parenthesis, parse address expression, skip comma and x or sp
+		assert(parser.is_operator(t, OperatorType::LeftParenthesis));
+		constexpr bool end_at_unmatched_parenthesis = false;
+		constexpr bool end_at_newline = true;
+		t = parser.parse_and_output_expression(parser.consume_next_token(), end_at_unmatched_parenthesis, end_at_newline);
+		assert(parser.is_operator(t, OperatorType::Comma));
+		t = parser.skip_spaces_and_tabs(parser.consume_next_token());
+		assert(t->type == TokenType::ProcessorKeyword && (static_cast<ProcessorKeywordType>(t->processor_keyword_index) == ProcessorKeywordType::X || static_cast<ProcessorKeywordType>(t->processor_keyword_index) == ProcessorKeywordType::SP));
+		t = parser.skip_spaces_and_tabs(parser.consume_next_token());
+		assert(parser.is_operator(t, OperatorType::RightParenthesis));
+		t = parser.consume_next_token();
+		
+		if ((selected_addressing_modes & SpIY) != 0) {
+			t = parser.skip_spaces_and_tabs(parser.consume_next_token());
+			assert(parser.is_operator(t, OperatorType::Comma));
+			t = parser.skip_spaces_and_tabs(parser.consume_next_token());
+			assert(t->type == TokenType::ProcessorKeyword && static_cast<ProcessorKeywordType>(t->processor_keyword_index) == ProcessorKeywordType::Y);
+			t = parser.skip_spaces_and_tabs(parser.consume_next_token());
+		}
+		return t;
+	}
+
+	// parse address expression
+	{
+		constexpr bool end_at_unmatched_parenthesis = false;
+		constexpr bool end_at_newline = true;
+		t = parser.parse_and_output_expression(t, end_at_unmatched_parenthesis, end_at_newline);
+	}
+
+	if ((selected_addressing_modes & (Ind | BpIY | BpIZ)) != 0) {
+		if ((selected_addressing_modes & (BpIY | BpIZ)) != 0) {
+			// skip comma and y or z
+			assert(parser.is_operator(t, OperatorType::Comma));
+			t = parser.skip_spaces_and_tabs(parser.consume_next_token());
+			assert(t->type == TokenType::ProcessorKeyword && (static_cast<ProcessorKeywordType>(t->processor_keyword_index) == ProcessorKeywordType::Y | static_cast<ProcessorKeywordType>(t->processor_keyword_index) == ProcessorKeywordType::Z));
+			t = parser.skip_spaces_and_tabs(parser.consume_next_token());
+		}
+		return t;
+	}
+	
+	if ((selected_addressing_modes & (Bp | Abs | Rel | RelW)) != 0) {
+		return t;
+	}
+	
+	if ((selected_addressing_modes & (Bpx | AbsX | Bpy | AbsY)) != 0) {
+		// skip comma and x or y
+		assert(parser.is_operator(t, OperatorType::Comma));
+		t = parser.skip_spaces_and_tabs(parser.consume_next_token());
+
+		assert(t->type == TokenType::ProcessorKeyword && (static_cast<ProcessorKeywordType>(t->processor_keyword_index) == ProcessorKeywordType::X | static_cast<ProcessorKeywordType>(t->processor_keyword_index) == ProcessorKeywordType::Y));
+		t = parser.skip_spaces_and_tabs(parser.consume_next_token());
+
+		return t;
+	}
+	
+	// at least two arguments
+	assert(parser.is_operator(t, OperatorType::Comma));
+	t = parser.consume_next_token(); // comma
+	
+	t = skip_optional_arg_label(parser, t, arg_labels[1]);
+
+	if ((selected_addressing_modes & Bb) != 0) {
+		constexpr bool end_at_unmatched_parenthesis = false;
+		constexpr bool end_at_newline = true;
+		t = parser.parse_and_output_expression(t, end_at_unmatched_parenthesis, end_at_newline);
+		return t;
+	}
+	assert((selected_addressing_modes & Bbr) != 0);
+
+	// at least three arguments
+	{
+		constexpr bool end_at_unmatched_parenthesis = false;
+		constexpr bool end_at_newline = true;
+		t = parser.parse_and_output_expression(t, end_at_unmatched_parenthesis, end_at_newline);
+	}
+
+	assert(parser.is_operator(t, OperatorType::Comma));
+	t = parser.consume_next_token(); // comma
+	
+	t = skip_optional_arg_label(parser, t, arg_labels[2]);
+
+	{
+		constexpr bool end_at_unmatched_parenthesis = false;
+		constexpr bool end_at_newline = true;
+		t = parser.parse_and_output_expression(t, end_at_unmatched_parenthesis, end_at_newline);
+	}
+	return t;
+}
+
+void Processor65ce02::generate_subroutine_instruction(Assembler &assembler, bool generate, int32_t address, const SourceLocation &source_location) const
+{
+	// instructions are only allowed within code sections.
+	bool instructions_allowed = assembler.in_code_section();
+	if (UNLIKELY(!instructions_allowed)) {
+		// this is an unrecoverable error
+		std::stringstream ss;
+		ss << "Instructions must be in a code section.";
+		assembler.report_fatal_error(source_location, AssemblyErrorCodes::CodeMustBeInCodeSection, ss.str());
+	}
+
+	// recursive data generation may not be safe
+	if (assembler._data_generation_depth != 0) {
+		// this is an unrecoverable error
+		std::stringstream ss;
+		ss << "Recursive data generation isn't allowed.";
+		assembler.report_fatal_error(source_location, AssemblyErrorCodes::RecursiveDataGenerationNotAllowed, ss.str());
+	}
+	
+	ScopeCounter<uint32_t> sc(assembler._data_generation_depth);
+
+	if (generate && address < 0) {
+		std::stringstream ss;
+		ss << "Addressing mode needs a positive argument. Argument value was evaluated to " << address << ".";
+		assembler.report_error(source_location, AssemblyErrorCodes::AddressingModeRequiresPositiveArgument, ss.str());
+	}
+
+	if (assembler._multi_bank_mode) {
+		// in this mode, addresses gets truncated to support memory banks
+		address &= 0xffff;
+	}
+
+	if (generate) {
+		if (address > 65535) {
+			std::stringstream ss;
+			ss << "Addressing mode needs a word size argument. Argument was evaluated to " << address << ".";
+			assembler.report_error(source_location, AssemblyErrorCodes::AddressingModeRequiresWordSizeArgument, ss.str());
+		}
+		Section::Contents ending_instruction = Section::Contents::ContinueExecutionInstruction;
+		auto &data = assembler._section->generated_data(ending_instruction);
+		data.push_back(opcode(InstructionType::Jsr, AddressingModeType::AbsoluteAddr));
+		data.push_back(static_cast<uint8_t>(address));
+		data.push_back(static_cast<uint8_t>(address >> 8));
+		if (assembler._hex_source_writer != nullptr) {
+			constexpr bool increase = true;
+			assembler._hex_source_writer->write_data(static_cast<uint32_t>(assembler._program_counter.integer_value), &data[data.size() - 3], increase, 3, source_location.file_index, source_location.row, source_location.row + 1);
+		}
+	}
+	assembler._program_counter.integer_value += 3;
+}
+
+void Processor65ce02::generate_instruction_data_label(Assembler &assembler, bool generate, bool export_enabled, const InstructionToken &token, uint8_t argument_index, int address, int offset, uint8_t size) const
+{
+	// exporting local variables is not allowed
+	if (generate && export_enabled && !token.global_data_label[argument_index]) {
+		std::stringstream ss;
+		ss << assembler.variable_name(token.data_label_symbol_hash[argument_index], token.global_data_label[argument_index]) << " cannot be exported since it is local.";
+		assembler.report_error(token.address_label_location[argument_index], AssemblyErrorCodes::ExportingLocalIsNotAllowed, ss.str());
+	}
+
+	if (assembler.create_label(generate, token.data_label_symbol_hash[argument_index], token.global_data_label[argument_index], StorageType::Constant, token.address_label_location[argument_index])) {
+		Value &new_label = assembler._current_pass.values.back();
+		if (size == 1) {
+			assembler.set_byte_offset(new_label, address, offset);
+		} else if (size == 2) {
+			assembler.set_word_offset(new_label, address, offset);
+		} else {
+			assert(false);
+		}
+		new_label.set_contains_address(true);
+		if (export_enabled) {
+			new_label.set_is_public(true);
+		}
+	}
+}
+
+const SyntaxToken *Processor65ce02::parse_instruction(Assembler &assembler, bool generate, const SyntaxToken *t, bool export_enabled) const
+{
+	assert(t->type == SyntaxTokenType::Instruction);
+	const InstructionToken &instruction_token = *static_cast<const InstructionToken *>(t);
+
+	// instructions are only allowed within code sections.
+	bool instructions_allowed = assembler.in_code_section();
+	if (UNLIKELY(!instructions_allowed)) {
+		// this is an unrecoverable error
+		std::stringstream ss;
+		ss << "Instructions must be in a code section.";
+		assembler.report_fatal_error(instruction_token.source_location, AssemblyErrorCodes::CodeMustBeInCodeSection, ss.str());
+	}
+
+	// recursive data generation may not be safe
+	if (assembler._data_generation_depth != 0) {
+		// this is an unrecoverable error
+		std::stringstream ss;
+		ss << "Recursive data generation isn't allowed.";
+		assembler.report_fatal_error(instruction_token.source_location, AssemblyErrorCodes::RecursiveDataGenerationNotAllowed, ss.str());
+	}
+	ScopeCounter<uint32_t> sc(assembler._data_generation_depth);
+
+	InstructionType instruction = instruction_token.instruction;
+	uint32_t addr_mode = instruction_token.addressing_modes;
+	Section::Contents ending_instruction = is_ending_instruction(instruction) ? Section::Contents::EndExecutionInstruction : Section::Contents::ContinueExecutionInstruction;
+
+	t = assembler.consume_next_token(); // instruction
+
+	// in the generation pass, the program counter is guaranteed to be an integer value
+	// so there is no need to verify this
+
+	if (addr_mode == AddressingModeMask::Imp) {
+		if (generate) {
+			auto &data = assembler._section->generated_data(ending_instruction);
+			data.push_back(opcode(instruction, AddressingModeType::Implied));
+			if (assembler._hex_source_writer != nullptr) {
+				constexpr bool increase = true;
+				assembler._hex_source_writer->write_data(static_cast<uint32_t>(assembler._program_counter.integer_value), &data[data.size() - 1], increase, 1, instruction_token.source_location.file_index, instruction_token.source_location.row, instruction_token.source_location.row + 1);
+			}
+		}
+		++assembler._program_counter.integer_value;
+		return t;
+	}
+
+	// in all other instructions, we have to parse the expression for the first argument
+	const ExpressionToken *expr = static_cast<const ExpressionToken *>(t);
+	const Value argument = assembler.evaluate_expression(generate, t);
+	t = assembler.consume_next_token();
+
+	// The argument is guaranteed to be a valid type in the generation pass.
+	// In an assembly pass this can be Unknown.
+	int32_t argument_value = 0;
+
+	// in case of an assembly pass, unknown will be converted to 0, which is ok for all addressing modes except relative
+	if (assembler.is_integer(argument)) {
+		argument_value = assembler.dereference_integer(argument);
+	} else if (!assembler.is_unknown(argument)) {
+		if (generate) {
+			std::stringstream ss;
+			ss << "Addressing mode needs an integer value. Argument type was " << to_string(assembler.type_of_value(argument)) << ".";
+			assembler.report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresIntegerArgument, ss.str());
+		}
+	}
+
+	if (addr_mode == AddressingModeMask::Imm) {
+		if (generate) {
+			// handle the case where the value doesn't fit in a byte
+			if (argument_value < -128 || argument_value > 255) {
+				std::stringstream ss;
+				ss << "Addressing mode needs a byte size argument. Argument was evaluated to " << argument_value << ".";
+				assembler.report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresByteSizeArgument, ss.str());
+			}
+			auto &data = assembler._section->generated_data(ending_instruction);
+			data.push_back(opcode(instruction, AddressingModeType::Immediate));
+			data.push_back(static_cast<uint8_t>(argument_value));
+			if (assembler._hex_source_writer != nullptr) {
+				constexpr bool increase = true;
+				assembler._hex_source_writer->write_data(static_cast<uint32_t>(assembler._program_counter.integer_value), &data[data.size() - 2], increase, 2, instruction_token.source_location.file_index, instruction_token.source_location.row, instruction_token.source_location.row + 1);
+			}
+		}
+		if (UNLIKELY(instruction_token.has_instruction_data_label[0])) {
+			generate_instruction_data_label(assembler, generate, export_enabled, instruction_token, 0, assembler._program_counter.integer_value + 1, 0, 1);
+		}
+
+		assembler._program_counter.integer_value += 2;
+		return t;
+	}
+	if (addr_mode == AddressingModeMask::ImmW) {
+		if (generate) {
+			// handle the case where the value doesn't fit in a word
+			if (argument_value < -32768 || argument_value > 65535) {
+				std::stringstream ss;
+				ss << "Addressing mode needs a word size argument. Argument was evaluated to " << argument_value << ".";
+				assembler.report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresWordSizeArgument, ss.str());
+			}
+			auto &data = assembler._section->generated_data(ending_instruction);
+			data.push_back(opcode(instruction, AddressingModeType::ImmediateWord));
+			data.push_back(static_cast<uint8_t>(argument_value));
+			data.push_back(static_cast<uint8_t>(argument_value >> 8));
+			if (assembler._hex_source_writer != nullptr) {
+				constexpr bool increase = true;
+				assembler._hex_source_writer->write_data(static_cast<uint32_t>(assembler._program_counter.integer_value), &data[data.size() - 3], increase, 3, instruction_token.source_location.file_index, instruction_token.source_location.row, instruction_token.source_location.row + 1);
+			}
+		}
+		if (UNLIKELY(instruction_token.has_instruction_data_label[0])) {
+			generate_instruction_data_label(assembler, generate, export_enabled, instruction_token, 0, assembler._program_counter.integer_value + 1, 0, 2);
+		}
+
+		assembler._program_counter.integer_value += 2;
+		return t;
+	}
+
+	if (generate && argument_value < 0) {
+		std::stringstream ss;
+		ss << "Addressing mode needs a positive argument. Argument value was evaluated to " << argument_value << ".";
+		assembler.report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresPositiveArgument, ss.str());
+	}
+
+	if (assembler._multi_bank_mode && (addr_mode != AddressingModeMask::Rel && addr_mode != AddressingModeMask::RelW)) {
+		// in this mode, addresses gets truncated to support memory banks
+		argument_value &= 0xffff;
+	}
+
+	if (addr_mode == (AddressingModeMask::Bp | AddressingModeMask::Abs)
+		|| addr_mode == (AddressingModeMask::Bpx | AddressingModeMask::AbsX)
+		|| addr_mode == (AddressingModeMask::Bpy | AddressingModeMask::AbsY)
+		|| addr_mode == (AddressingModeMask::BpIX | AddressingModeMask::IndX)
+	)
+	{
+		// mask off the zero page or absolute addressing mode regardless of modes
+		addr_mode = argument_value > 255 ? select_word_mode(addr_mode) : select_byte_mode(addr_mode);
+	}
+
+	if (addr_mode == AddressingModeMask::Bp
+		|| addr_mode == AddressingModeMask::Bpx
+		|| addr_mode == AddressingModeMask::Bpy
+		|| addr_mode == AddressingModeMask::BpIX
+		|| addr_mode == AddressingModeMask::BpIY
+		|| addr_mode == AddressingModeMask::BpIZ
+		|| addr_mode == AddressingModeMask::SpIY
+	)
+	{
+		if (generate) {
+			if (argument_value > 255) {
+				std::stringstream ss;
+				ss << "Addressing mode needs a byte size argument. Argument was evaluated to " << argument_value << ".";
+				assembler.report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresByteSizeArgument, ss.str());
+			}
+			auto &data = assembler._section->generated_data(ending_instruction);
+			data.push_back(opcode(instruction, mask_to_addressing_mode(addr_mode)));
+			data.push_back(static_cast<uint8_t>(argument_value));
+			if (assembler._hex_source_writer != nullptr) {
+				constexpr bool increase = true;
+				assembler._hex_source_writer->write_data(static_cast<uint32_t>(assembler._program_counter.integer_value), &data[data.size() - 2], increase, 2, instruction_token.source_location.file_index, instruction_token.source_location.row, instruction_token.source_location.row + 1);
+			}
+		}
+		if (UNLIKELY(instruction_token.has_instruction_data_label[0])) {
+			generate_instruction_data_label(assembler, generate, export_enabled, instruction_token, 0, assembler._program_counter.integer_value + 1, 0, 1);
+		}
+		assembler._program_counter.integer_value += 2;
+		return t;
+	}
+
+	if (addr_mode == AddressingModeMask::Abs
+		|| addr_mode == AddressingModeMask::AbsX
+		|| addr_mode == AddressingModeMask::AbsY
+		|| addr_mode == AddressingModeMask::Ind
+		|| addr_mode == AddressingModeMask::IndX
+	)
+	{
+		if (generate) {
+			if (argument_value > 65535) {
+				std::stringstream ss;
+				ss << "Addressing mode needs a word size argument. Argument was evaluated to " << argument_value << ".";
+				assembler.report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresWordSizeArgument, ss.str());
+			}
+			auto &data = assembler._section->generated_data(ending_instruction);
+			data.push_back(opcode(instruction, mask_to_addressing_mode(addr_mode)));
+			data.push_back(static_cast<uint8_t>(argument_value));
+			data.push_back(static_cast<uint8_t>(argument_value >> 8));
+			if (assembler._hex_source_writer != nullptr) {
+				constexpr bool increase = true;
+				assembler._hex_source_writer->write_data(static_cast<uint32_t>(assembler._program_counter.integer_value), &data[data.size() - 3], increase, 3, instruction_token.source_location.file_index, instruction_token.source_location.row, instruction_token.source_location.row + 1);
+			}
+		}
+		if (UNLIKELY(instruction_token.has_instruction_data_label[0])) {
+			generate_instruction_data_label(assembler, generate, export_enabled, instruction_token, 0, assembler._program_counter.integer_value + 1, 0, 2);
+		}
+		assembler._program_counter.integer_value += 3;
+		return t;
+	}
+
+	if (addr_mode == (AddressingModeMask::Rel | AddressingModeMask::RelW)) {
+		int32_t reference_addr = assembler._program_counter.integer_value + 2; // move past the (short) instruction
+		int32_t relative_addr = argument_value - reference_addr;
+		// mask off the zero page or absolute addressing mode regardless of modes
+		addr_mode = (relative_addr < -128 || relative_addr > 127) ? select_word_mode(addr_mode) : select_byte_mode(addr_mode);
+	}
+
+	if (addr_mode == AddressingModeMask::Rel) {
+		if (generate) {
+			int32_t reference_addr = assembler._program_counter.integer_value + 2; // move past the instruction
+			int32_t relative_addr = argument_value - reference_addr;
+			auto &data = assembler._section->generated_data(ending_instruction);
+			data.push_back(opcode(instruction, mask_to_addressing_mode(addr_mode)));
+			data.push_back(static_cast<uint8_t>(relative_addr));
+			if (assembler._hex_source_writer != nullptr) {
+				constexpr bool increase = true;
+				assembler._hex_source_writer->write_data(static_cast<uint32_t>(assembler._program_counter.integer_value), &data[data.size() - 2], increase, 2, instruction_token.source_location.file_index, instruction_token.source_location.row, instruction_token.source_location.row + 1);
+			}
+		}
+		if (UNLIKELY(instruction_token.has_instruction_data_label[0])) {
+			generate_instruction_data_label(assembler, generate, export_enabled, instruction_token, 0, assembler._program_counter.integer_value + 1, 0, 1);
+		}
+		assembler._program_counter.integer_value += 2;
+		return t;
+	}
+	if (addr_mode == AddressingModeMask::RelW) {
+		if (generate) {
+			int32_t reference_addr = assembler._program_counter.integer_value + 3; // move past the instruction
+			int32_t relative_addr = argument_value - reference_addr;
+			if (relative_addr < -32768 || relative_addr > 32767) {
+				std::stringstream ss;
+				ss << "Relative address out of range. Offset is " << relative_addr << " and needs to be in a [-32768..32767] range.";
+				assembler.report_error(expr->source_location, AssemblyErrorCodes::RelativeAddressOutOfRange, ss.str());
+			}
+			auto &data = assembler._section->generated_data(ending_instruction);
+			data.push_back(opcode(instruction, mask_to_addressing_mode(addr_mode)));
+			data.push_back(static_cast<uint8_t>(relative_addr));
+			data.push_back(static_cast<uint8_t>(relative_addr >> 8));
+			if (assembler._hex_source_writer != nullptr) {
+				constexpr bool increase = true;
+				assembler._hex_source_writer->write_data(static_cast<uint32_t>(assembler._program_counter.integer_value), &data[data.size() - 3], increase, 3, instruction_token.source_location.file_index, instruction_token.source_location.row, instruction_token.source_location.row + 1);
+			}
+		}
+		if (UNLIKELY(instruction_token.has_instruction_data_label[0])) {
+			generate_instruction_data_label(assembler, generate, export_enabled, instruction_token, 0, assembler._program_counter.integer_value + 1, 0, 2);
+		}
+		assembler._program_counter.integer_value += 3;
+		return t;
+	}
+
+	// Bb and Bbr left, which both use bit and zero page arguments
+	assert(t->type == SyntaxTokenType::Expression);
+	const ExpressionToken *expr2 = static_cast<const ExpressionToken *>(t);
+	const Value argument2 = assembler.evaluate_expression(generate, t);
+	t = assembler.consume_next_token();
+
+	int32_t argument2_value = 0;
+	// in case of an assembly pass, unknown will be converted to 0, which is ok for all addressing modes
+	if (assembler.is_integer(argument2)) {
+		argument2_value = assembler.dereference_integer(argument2);
+	} else {
+		if (generate) {
+			std::stringstream ss;
+			ss << "Addressing mode needs an integer value. Argument type was " << to_string(assembler.type_of_value(argument2)) << ".";
+			assembler.report_error(expr2->source_location, AssemblyErrorCodes::AddressingModeRequiresIntegerArgument, ss.str());
+		}
+	}
+	
+	if (generate) {
+		if (UNLIKELY(instruction_token.has_instruction_data_label[0])) {
+			std::stringstream ss;
+			ss << "Addressing mode argument cannot have label to instruction data.";
+			assembler.report_error(expr->source_location, AssemblyErrorCodes::AddressingModeArgumentCannotHaveDataLabel, ss.str());
+		}
+		
+		if (argument_value > 7) {
+			std::stringstream ss;
+			ss << "Addressing mode needs a bit size argument. Argument was evaluated to " << argument_value << ".";
+			assembler.report_error(expr->source_location, AssemblyErrorCodes::AddressingModeRequiresBitSizeArgument, ss.str());
+		}
+
+		if (argument2_value < 0) {
+			std::stringstream ss;
+			ss << "Addressing mode needs a positive argument. Argument value was evaluated to " << argument2_value << ".";
+			assembler.report_error(expr2->source_location, AssemblyErrorCodes::AddressingModeRequiresPositiveArgument, ss.str());
+		}
+
+		if (argument2_value > 255) {
+			std::stringstream ss;
+			ss << "Addressing mode needs a byte size argument. Argument was evaluated to " << argument2_value << ".";
+			assembler.report_error(expr2->source_location, AssemblyErrorCodes::AddressingModeRequiresByteSizeArgument, ss.str());
+		}
+	}
+	
+	if (UNLIKELY(instruction_token.has_instruction_data_label[1])) {
+		generate_instruction_data_label(assembler, generate, export_enabled, instruction_token, 1, assembler._program_counter.integer_value + 1, 0, 1);
+	}
+
+	if (addr_mode == AddressingModeMask::Bb) {
+		if (generate) {
+			auto &data = assembler._section->generated_data(ending_instruction);
+			data.push_back(static_cast<uint8_t>(opcode(instruction, mask_to_addressing_mode(addr_mode)) | (argument_value << 4)));
+			data.push_back(static_cast<uint8_t>(argument2_value));
+			if (assembler._hex_source_writer != nullptr) {
+				constexpr bool increase = true;
+				assembler._hex_source_writer->write_data(static_cast<uint32_t>(assembler._program_counter.integer_value), &data[data.size() - 2], increase, 2, instruction_token.source_location.file_index, instruction_token.source_location.row, instruction_token.source_location.row + 1);
+			}
+		}
+		assembler._program_counter.integer_value += 2;
+		return t;
+	}
+
+	// Just Bbr left
+	assert(t->type == SyntaxTokenType::Expression);
+	const ExpressionToken *expr3 = static_cast<const ExpressionToken *>(t);
+	const Value argument3 = assembler.evaluate_expression(generate, t);
+	t = assembler.consume_next_token();
+
+	int32_t argument3_value = 0;
+	if (assembler.is_integer(argument3)) {
+		argument3_value = assembler.dereference_integer(argument3);
+	} else {
+		if (generate) {
+			std::stringstream ss;
+			ss << "Addressing mode needs an integer value. Argument type was " << to_string(assembler.type_of_value(argument3)) << ".";
+			assembler.report_error(expr3->source_location, AssemblyErrorCodes::AddressingModeRequiresIntegerArgument, ss.str());
+		}
+	}
+
+	if (generate) {
+		int32_t reference_addr = assembler._program_counter.integer_value + 3; // move past the instruction
+		int32_t relative_addr = argument3_value - reference_addr;
+		if (relative_addr < -128 || relative_addr > 127) {
+			std::stringstream ss;
+			ss << "Relative address out of range. Offset is " << relative_addr << " and needs to be in a [-128..127] range.";
+			assembler.report_error(expr->source_location, AssemblyErrorCodes::RelativeAddressOutOfRange, ss.str());
+		}
+		auto &data = assembler._section->generated_data(ending_instruction);
+		data.push_back(static_cast<uint8_t>(opcode(instruction, mask_to_addressing_mode(addr_mode)) | (argument_value << 4)));
+		data.push_back(static_cast<uint8_t>(argument2_value));
+		data.push_back(static_cast<uint8_t>(relative_addr));
+		if (assembler._hex_source_writer != nullptr) {
+			constexpr bool increase = true;
+			assembler._hex_source_writer->write_data(static_cast<uint32_t>(assembler._program_counter.integer_value), &data[data.size() - 3], increase, 3, instruction_token.source_location.file_index, instruction_token.source_location.row, instruction_token.source_location.row + 1);
+		}
+	}
+	if (UNLIKELY(instruction_token.has_instruction_data_label[2])) {
+		generate_instruction_data_label(assembler, generate, export_enabled, instruction_token, 2, assembler._program_counter.integer_value + 2, 0, 1);
+	}
+	assembler._program_counter.integer_value += 3;
+	return t;
+}
+
+	}
+}

          
A => jasm/processor/65ce02/processor_65ce02.h +55 -0
@@ 0,0 1,55 @@ 
+#pragma once
+
+#include <processor/processor.h>
+#include <tokenize/source_location.h>
+
+namespace jasm
+{
+	namespace csg65ce02
+	{
+
+struct InstructionToken;
+
+class Processor65ce02 : public Processor
+{
+public:
+	virtual void register_processor_keywords(std::vector<std::string> &keywords) override;
+	virtual void register_processor_instructions(bool pseudo_instructions) override;
+	virtual bool allow_processor_keyword_with_prim(uint64_t &keyword_hash) const override;
+	
+	virtual std::string token_to_string(const Token &t) const override;
+	virtual const Token *parse_instruction(SyntaxParser &parser, const std::vector<std::string> &source_files, const Token *t, uint8_t /*InstructionType*/ instruction_index) const override;
+	
+	virtual void generate_subroutine_instruction(Assembler &assembler, bool generate, int32_t address, const SourceLocation &source_location) const override;
+	virtual const SyntaxToken *parse_instruction(Assembler &assembler, bool generate, const SyntaxToken *t, bool export_enabled) const override;
+
+private:
+	struct ArgLabel
+	{
+		ArgLabel()
+			: enabled(false)
+			, global(false)
+			, symbol_hash(0)
+		{}
+		
+		bool enabled;
+		bool global;
+		SourceLocation location;
+		uint64_t symbol_hash;
+	};
+
+	const Token *parse_optional_arg_label(SyntaxParser &parser, const Token *t, ArgLabel &label) const;
+	const Token *skip_optional_arg_label(SyntaxParser &parser, const Token *t, const ArgLabel &label) const;
+	
+	/// Try to parse as much as needed to determine all possible addressing modes.
+	/// @return A mask with possible addressing modes.
+	uint32_t try_parse_addressing_mode(SyntaxParser &parser, const std::vector<std::string> &source_files, const Token *t, std::array<ArgLabel, 3> &arg_labels) const;
+
+	static void print_addressing_modes(std::stringstream &ss, uint32_t addressing_mode_mask);
+
+	void generate_instruction_data_label(Assembler &assembler, bool generate, bool export_enabled, const InstructionToken &token, uint8_t argument_index, int address, int offset, uint8_t size) const;
+};
+		
+		
+	}
+}

          
A => jasm/processor/65ce02/processor_keywords_65ce02.cpp +26 -0
@@ 0,0 1,26 @@ 
+#include "pch.h"
+
+#include <processor/65ce02/processor_keywords_65ce02.h>
+
+namespace jasm
+{
+	namespace csg65ce02
+	{
+
+std::string_view to_string(ProcessorKeywordType type)
+{
+	static const std::string_view names[] = {
+		// instruction registers
+		std::string_view("x"),
+		std::string_view("y"),
+		std::string_view("z"),
+		std::string_view("sp"),
+	};
+	static_assert(sizeof(names) / sizeof(names[0]) == static_cast<size_t>(ProcessorKeywordType::NumTypes), "Number of registers/conditions doesn't match number of strings");
+
+	assert(type < ProcessorKeywordType::NumTypes);
+	return names[static_cast<size_t>(type)];
+}
+
+	} // namespace csg65ce02
+} // namespace jasm

          
A => jasm/processor/65ce02/processor_keywords_65ce02.h +27 -0
@@ 0,0 1,27 @@ 
+#pragma once
+
+namespace jasm
+{
+	namespace csg65ce02
+	{
+
+/// @addtogroup tokenize
+/// @{
+
+/// All different registers.
+enum class ProcessorKeywordType : uint8_t
+{
+	// instruction registers
+	X,
+	Y,
+	Z,
+	SP,
+	NumTypes,
+};
+
+std::string_view to_string(ProcessorKeywordType type);
+
+/// @}
+
+	} // namespace csg65ce02
+} // namespace jasm

          
M jasm/processor/instructions.h +1 -0
@@ 2,6 2,7 @@ 
 
 #include <processor/6502/instructions_6502.h>
 #include <processor/65c02/instructions_65c02.h>
+#include <processor/65ce02/instructions_65ce02.h>
 #include <processor/z80/instructions_z80.h>
 
 namespace jasm

          
M jasm/processor/processor.cpp +7 -0
@@ 3,6 3,7 @@ 
 #include <core/collections/array_helper.h>
 #include <processor/6502/processor_6502.h>
 #include <processor/65c02/processor_65c02.h>
+#include <processor/65ce02/processor_65ce02.h>
 #include <processor/processor.h>
 #include <processor/processor_unspecified.h>
 #include <processor/z80/processor_z80.h>

          
@@ 21,6 22,7 @@ namespace {
 		std::string_view("6510"),
 		std::string_view("8502"),
 		std::string_view("65c02"),
+		std::string_view("65ce02"),
 		std::string_view("z80"),
 	};
 }

          
@@ 154,6 156,8 @@ ProcessorCatalogue::ProcessorCatalogue(b
 	_mos6502->init(pseudo_instructions);
 	_wdc65c02 = std::make_unique<wdc65c02::Processor65c02>();
 	_wdc65c02->init(pseudo_instructions);
+	_csg65ce02 = std::make_unique<csg65ce02::Processor65ce02>();
+	_csg65ce02->init(pseudo_instructions);
 	_z80 = std::make_unique<z80::ProcessorZ80>();
 	_z80->init(pseudo_instructions);
 }

          
@@ 173,6 177,9 @@ const Processor *ProcessorCatalogue::pro
 		case ProcessorType::Wdc65c02:
 			return _wdc65c02.get();
 
+		case ProcessorType::Csg65ce02:
+			return _csg65ce02.get();
+
 		case ProcessorType::Zilog80:
 			return _z80.get();
 	}

          
M jasm/processor/processor.h +2 -0
@@ 23,6 23,7 @@ enum class ProcessorType : uint8_t
 	Mos6510,
 	Mos8502,
 	Wdc65c02,
+	Csg65ce02,
 	Zilog80,
 	NumProcessors
 };

          
@@ 134,6 135,7 @@ private:
 	std::unique_ptr<Processor> _unspecified;
 	std::unique_ptr<Processor> _mos6502;
 	std::unique_ptr<Processor> _wdc65c02;
+	std::unique_ptr<Processor> _csg65ce02;
 	std::unique_ptr<Processor> _z80;
 };
 

          
M jasm/syntax/syntax_parser.cpp +12 -0
@@ 260,6 260,18 @@ const Token *SyntaxParser::parse_operato
 	throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedOperator, ss.str());
 }
 
+const Token *SyntaxParser::parse_operator_on_same_line(const Token *t, OperatorType expected_operator)
+{
+	t = skip_spaces_and_tabs(t);
+
+	if (is_operator(t, expected_operator))
+		return consume_next_token();
+
+	std::stringstream ss;
+	ss << "Expected operator " << to_string(expected_operator) << " but got " << _processor->token_to_string(*t);
+	throw AssemblyException(_source_files, t->source_location, AssemblyErrorCodes::ExpectedOperator, ss.str());
+}
+
 const Token *SyntaxParser::parse_keyword(const Token *t, KeywordType expected_keyword)
 {
 	t = skip_whitespaces(t);

          
M jasm/syntax/syntax_parser.h +2 -0
@@ 133,6 133,8 @@ public:
 
 		/// Parse an expected operator.
 	const Token *parse_operator(const Token *t, OperatorType expected_operator);
+		/// Parse an expected operator but don't consume newlines.
+	const Token *parse_operator_on_same_line(const Token *t, OperatorType expected_operator);
 
 private:
 	void setup_operator_precedence();

          
M jasm/unit_test.py +1 -1
@@ 43,7 43,7 @@ def run_test(input_path, stdout_path, st
 	if exe == None:
 		return False
 
-	processors = ["6502", "65c02", "z80", "unspecified"]
+	processors = ["6502", "65c02", "65ce02", "z80", "unspecified"]
 	if not processor in processors:
 		raise Exception("Unsupported processor %s." % processor)
 

          
A => jasm/unit_tests/results/test_addressing_mode_branch_too_long_1_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_branch_too_long_1_65ce02.asm(5,6) : Error 3009 : Relative address out of range. Offset is -32769 and needs to be in a [-32768..32767] range.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_branch_too_long_2_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_branch_too_long_2_65ce02.asm(5,6) : Error 3009 : Relative address out of range. Offset is 32768 and needs to be in a [-32768..32767] range.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_expected_x_in_indirect_65ce02.stdout +1 -0
@@ 0,0 1,1 @@ 
+unit_tests/test_addressing_mode_expected_x_in_indirect_65ce02.asm(4,10) : Error 2026 : Expected x or sp for indirect addressing mode, but got symbol

          
A => jasm/unit_tests/results/test_addressing_mode_expected_y_in_indirect_65c02.stdout +1 -0
@@ 0,0 1,1 @@ 
+unit_tests/test_addressing_mode_expected_y_in_indirect_65c02.asm(4,11) : Error 2026 : Invalid index register in addressing mode. Expected y but got integer

          
A => jasm/unit_tests/results/test_addressing_mode_expected_y_or_z_in_indirect_65ce02.stdout +1 -0
@@ 0,0 1,1 @@ 
+unit_tests/test_addressing_mode_expected_y_or_z_in_indirect_65ce02.asm(4,11) : Error 2026 : Invalid index register in addressing mode. Expected y or z but got integer

          
A => jasm/unit_tests/results/test_addressing_mode_immediate_value_too_large_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_immediate_value_too_large_65ce02.asm(5,7) : Error 3008 : Addressing mode needs a word size argument. Argument was evaluated to 65536.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_immediate_value_too_small_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_immediate_value_too_small_65ce02.asm(5,7) : Error 3008 : Addressing mode needs a word size argument. Argument was evaluated to -32769.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_is_illegal_65ce02.stdout +5 -0
@@ 0,0 1,5 @@ 
+unit_tests/test_addressing_mode_is_illegal_65ce02.asm(5,5) : Error 2031 : Invalid addressing mode used. Code indicates one of the following:
+  implied
+but possible addressing modes for bne are:
+  byte relative address
+  word relative address

          
A => jasm/unit_tests/results/test_addressing_mode_needs_bit_size_argument_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_needs_bit_size_argument_65ce02.asm(4,6) : Error 3113 : Addressing mode needs a bit size argument. Argument was evaluated to 8.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_needs_byte_argument_1_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_needs_byte_argument_1_65ce02.asm(4,7) : Error 3007 : Addressing mode needs a byte size argument. Argument was evaluated to 256.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_needs_byte_argument_2_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_needs_byte_argument_2_65ce02.asm(5,7) : Error 3007 : Addressing mode needs a byte size argument. Argument was evaluated to 3072.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_needs_byte_argument_3_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_needs_byte_argument_3_65ce02.asm(4,9) : Error 3007 : Addressing mode needs a byte size argument. Argument was evaluated to 256.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_needs_integer_argument_1_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_needs_integer_argument_1_65ce02.asm(4,7) : Error 3029 : Addressing mode needs an integer value. Argument type was float.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_needs_integer_argument_2_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_needs_integer_argument_2_65ce02.asm(4,9) : Error 3029 : Addressing mode needs an integer value. Argument type was string.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_needs_integer_argument_3_65ce02.stdout +3 -0
@@ 0,0 1,3 @@ 
+unit_tests/test_addressing_mode_needs_integer_argument_3_65ce02.asm(4,12) : Error 3029 : Addressing mode needs an integer value. Argument type was string.
+unit_tests/test_addressing_mode_needs_integer_argument_3_65ce02.asm(4,6) : Error 3009 : Relative address out of range. Offset is -32771 and needs to be in a [-128..127] range.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_needs_integer_argument_4_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_needs_integer_argument_4_65ce02.asm(4,6) : Error 3029 : Addressing mode needs an integer value. Argument type was string.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_needs_positive_argument_1_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_needs_positive_argument_1_65ce02.asm(5,6) : Error 3006 : Addressing mode needs a positive argument. Argument value was evaluated to -1.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_needs_positive_argument_2_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_needs_positive_argument_2_65ce02.asm(4,9) : Error 3006 : Addressing mode needs a positive argument. Argument value was evaluated to -1.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_needs_word_size_argument_1_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_needs_word_size_argument_1_65ce02.asm(5,6) : Error 3008 : Addressing mode needs a word size argument. Argument was evaluated to 786432.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_addressing_mode_needs_word_size_argument_2_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_addressing_mode_needs_word_size_argument_2_65ce02.asm(4,6) : Error 3008 : Addressing mode needs a word size argument. Argument was evaluated to 786432.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_bank_mode_truncates_address_instructions_65ce02.bin +1 -0
@@ 0,0 1,1 @@ 
+`
  No newline at end of file

          
A => jasm/unit_tests/results/test_generate_data_in_instruction_1_65ce02.stdout +3 -0
@@ 0,0 1,3 @@ 
+unit_tests/test_generate_data_in_instruction_1_65ce02.asm(7,3) : Error 3092 : Recursive data generation isn't allowed.
+unit_tests/test_generate_data_in_instruction_1_65ce02.asm(10,15) : Invoked from here
+Fatal error, aborting assembly.

          
A => jasm/unit_tests/results/test_instruction_data_label_cant_have_implied_addressing_mode_65ce02.stdout +1 -0
@@ 0,0 1,1 @@ 
+unit_tests/test_instruction_data_label_cant_have_implied_addressing_mode_65ce02.asm(5,6) : Error 2046 : Implied addressing modes cannot have label to instruction data. Add a newline or a semicolon before the label to resolve this.

          
A => jasm/unit_tests/results/test_instruction_data_label_for_wrong_argument_type_3_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_instruction_data_label_for_wrong_argument_type_3_65ce02.asm(4,11) : Error 3099 : Addressing mode argument cannot have label to instruction data.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_instruction_data_label_has_lo_hi_properties_65ce02.bin +1 -0
@@ 0,0 1,1 @@ 
+L
  No newline at end of file

          
A => jasm/unit_tests/results/test_instruction_data_label_with_export_65ce02.bin +1 -0
@@ 0,0 1,1 @@ 
+``
  No newline at end of file

          
A => jasm/unit_tests/results/test_instruction_data_label_with_local_export_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_instruction_data_label_with_local_export_65ce02.asm(11,14) : Error 3064 : .addr cannot be exported since it is local.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_instruction_ends_at_newline_2_65ce02.stdout +1 -0
@@ 0,0 1,1 @@ 
+unit_tests/test_instruction_ends_at_newline_2_65ce02.asm(6,7) : Error 2009 : Expected expression value but got newline

          
A => jasm/unit_tests/results/test_instructions_must_be_in_code_sections_1_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_instructions_must_be_in_code_sections_1_65ce02.asm(3,1) : Error 3057 : Instructions must be in a code section.
+Fatal error, aborting assembly.

          
A => jasm/unit_tests/results/test_instructions_must_be_in_code_sections_2_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_instructions_must_be_in_code_sections_2_65ce02.asm(4,2) : Error 3057 : Instructions must be in a code section.
+Fatal error, aborting assembly.

          
M jasm/unit_tests/results/test_processor_with_invalid_name.stdout +1 -1
@@ 1,1 1,1 @@ 
-unit_tests/test_processor_with_invalid_name.asm(3,11) : Error 1013 : Unsupported processor type "test". Supported types are "6502", "6510", "8502", "65c02", "z80"
+unit_tests/test_processor_with_invalid_name.asm(3,11) : Error 1013 : Unsupported processor type "test". Supported types are "6502", "6510", "8502", "65c02", "65ce02", "z80"

          
A => jasm/unit_tests/results/test_pseudo_instructions_for_branching_65ce02.bin +1 -0
@@ 0,0 1,1 @@ 
+
  No newline at end of file

          
A => jasm/unit_tests/results/test_pseudo_instructions_for_incrementing_65ce02.bin +1 -0
@@ 0,0 1,1 @@ 
+:
  No newline at end of file

          
A => jasm/unit_tests/results/test_pseudo_instructions_in_standard_mode_65ce02.stdout +9 -0
@@ 0,0 1,9 @@ 
+unit_tests/test_pseudo_instructions_in_standard_mode_65ce02.asm(5,2) : Error 3004 : Reference to undefined symbol bhs
+unit_tests/test_pseudo_instructions_in_standard_mode_65ce02.asm(6,2) : Error 3004 : Reference to undefined symbol blt
+unit_tests/test_pseudo_instructions_in_standard_mode_65ce02.asm(5,6) : Error 3000 : Operator * is not defined for left hand side unknown type.
+unit_tests/test_pseudo_instructions_in_standard_mode_65ce02.asm(7,2) : Error 3004 : Reference to undefined symbol bra
+unit_tests/test_pseudo_instructions_in_standard_mode_65ce02.asm(6,6) : Error 3000 : Operator * is not defined for left hand side unknown type.
+unit_tests/test_pseudo_instructions_in_standard_mode_65ce02.asm(8,2) : Error 3004 : Reference to undefined symbol dea
+unit_tests/test_pseudo_instructions_in_standard_mode_65ce02.asm(7,6) : Error 3000 : Operator * is not defined for left hand side unknown type.
+unit_tests/test_pseudo_instructions_in_standard_mode_65ce02.asm(9,2) : Error 3004 : Reference to undefined symbol ina
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_pseudo_instructions_use_names_in_standard_mode_65ce02.bin +1 -0
@@ 0,0 1,1 @@ 
+`
  No newline at end of file

          
A => jasm/unit_tests/results/test_register_names_cant_be_used_as_global_variables_65ce02.stdout +1 -0
@@ 0,0 1,1 @@ 
+unit_tests/test_register_names_cant_be_used_as_global_variables_65ce02.asm(5,8) : Error 2007 : Expected symbol name but got processor keyword x

          
A => jasm/unit_tests/results/test_subroutine_call_65ce02.bin +1 -0
@@ 0,0 1,1 @@ 
+ `
  No newline at end of file

          
A => jasm/unit_tests/results/test_subroutine_call_must_be_in_code_section_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_subroutine_call_must_be_in_code_section_65ce02.asm(3,5) : Error 3057 : Instructions must be in a code section.
+Fatal error, aborting assembly.

          
A => jasm/unit_tests/results/test_subroutine_call_negative_argument_65ce02.stdout +3 -0
@@ 0,0 1,3 @@ 
+unit_tests/test_subroutine_call_negative_argument_65ce02.asm(3,23) : Error 3013 : Section start cannot be negative. It is evaluated to -4.
+unit_tests/test_subroutine_call_negative_argument_65ce02.asm(5,6) : Error 3006 : Addressing mode needs a positive argument. Argument value was evaluated to -1.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_subroutine_call_recursive_data_generation_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_subroutine_call_recursive_data_generation_65ce02.asm(5,11) : Error 3092 : Recursive data generation isn't allowed.
+Fatal error, aborting assembly.

          
A => jasm/unit_tests/results/test_subroutine_call_too_large_argument_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_subroutine_call_too_large_argument_65ce02.asm(5,6) : Error 3008 : Addressing mode needs a word size argument. Argument was evaluated to 65536.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_subroutine_call_with_arguments_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_subroutine_call_with_arguments_65ce02.asm(5,6) : Error 3108 : Subroutine calls don't support arguments.
+Assembly ended with errors.

          
A => jasm/unit_tests/results/test_subroutine_falls_through_1_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_subroutine_falls_through_1_65ce02.asm(5,13) : Warning 3500 : Code in subroutine test falls through at end of subroutine.
+$8000 - $8001 ($0001) code: main

          
A => jasm/unit_tests/results/test_subroutine_falls_through_2_65ce02.stdout +2 -0
@@ 0,0 1,2 @@ 
+unit_tests/test_subroutine_falls_through_2_65ce02.asm(5,13) : Warning 3500 : Code in subroutine test falls through at end of subroutine.
+$8000 - $8002 ($0002) code: main

          
A => jasm/unit_tests/results/test_subroutine_falls_through_3_65ce02.stdout +1 -0
@@ 0,0 1,1 @@ 
+$8000 - $8001 ($0001) code: main

          
A => jasm/unit_tests/results/test_subroutine_falls_through_4_65ce02.stdout +1 -0
@@ 0,0 1,1 @@ 
+$8000 - $8003 ($0003) code: main

          
A => jasm/unit_tests/results/test_subroutine_falls_through_5_65ce02.stdout +1 -0
@@ 0,0 1,1 @@ 
+$8000 - $8002 ($0002) code: main

          
A => jasm/unit_tests/test_addressing_mode_branch_too_long_1_65ce02.asm +6 -0
@@ 0,0 1,6 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000
+{
+	bne 2
+}

          
A => jasm/unit_tests/test_addressing_mode_branch_too_long_2_65ce02.asm +6 -0
@@ 0,0 1,6 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $1000
+{
+	bne $9003
+}

          
A => jasm/unit_tests/test_addressing_mode_expected_x_in_indirect_65ce02.asm +5 -0
@@ 0,0 1,5 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000 {
+	lda (55,q
+}

          
A => jasm/unit_tests/test_addressing_mode_expected_y_in_indirect_65c02.asm +5 -0
@@ 0,0 1,5 @@ 
+// assembler command line arguments: 65c02 [-v0 -hla]
+
+section code, "main", $8000 {
+	lda (55),1
+}

          
A => jasm/unit_tests/test_addressing_mode_expected_y_or_z_in_indirect_65ce02.asm +5 -0
@@ 0,0 1,5 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000 {
+	lda (55),1
+}

          
A => jasm/unit_tests/test_addressing_mode_immediate_value_too_large_65ce02.asm +6 -0
@@ 0,0 1,6 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $1000
+{
+	phw #$10000
+}

          
A => jasm/unit_tests/test_addressing_mode_immediate_value_too_small_65ce02.asm +6 -0
@@ 0,0 1,6 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $1000
+{
+	phw #-32769
+}

          
A => jasm/unit_tests/test_addressing_mode_is_illegal_65ce02.asm +6 -0
@@ 0,0 1,6 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000
+{
+	bne;
+}

          
A => jasm/unit_tests/test_addressing_mode_needs_bit_size_argument_65ce02.asm +5 -0
@@ 0,0 1,5 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000 {
+	rmb 8,0
+}

          
A => jasm/unit_tests/test_addressing_mode_needs_byte_argument_1_65ce02.asm +7 -0
@@ 0,0 1,7 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000 {
+	lda #256
+	sta $c000
+	rts
+}

          
A => jasm/unit_tests/test_addressing_mode_needs_byte_argument_2_65ce02.asm +7 -0
@@ 0,0 1,7 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000 {
+	ldx #0
+	lda ($c00,x)
+	rts
+}

          
A => jasm/unit_tests/test_addressing_mode_needs_byte_argument_3_65ce02.asm +5 -0
@@ 0,0 1,5 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000 {
+	rmb 0, 256
+}

          
A => jasm/unit_tests/test_addressing_mode_needs_integer_argument_1_65ce02.asm +6 -0
@@ 0,0 1,6 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $1000, $2000 {
+	lda #5.5
+	rts
+}

          
A => jasm/unit_tests/test_addressing_mode_needs_integer_argument_2_65ce02.asm +5 -0
@@ 0,0 1,5 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000 {
+	smb 0, "H"
+}

          
A => jasm/unit_tests/test_addressing_mode_needs_integer_argument_3_65ce02.asm +5 -0
@@ 0,0 1,5 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000 {
+	bbr 0, 0, "H"
+}

          
A => jasm/unit_tests/test_addressing_mode_needs_integer_argument_4_65ce02.asm +5 -0
@@ 0,0 1,5 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000 {
+	smb "H", 0
+}

          
A => jasm/unit_tests/test_addressing_mode_needs_positive_argument_1_65ce02.asm +7 -0
@@ 0,0 1,7 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000 {
+	lda #0
+	sta -1
+	rts
+}

          
A => jasm/unit_tests/test_addressing_mode_needs_positive_argument_2_65ce02.asm +5 -0
@@ 0,0 1,5 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000 {
+	smb 0, -1
+}

          
A => jasm/unit_tests/test_addressing_mode_needs_word_size_argument_1_65ce02.asm +7 -0
@@ 0,0 1,7 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000 {
+	ldx #0
+	lda $c0000,x
+	rts
+}

          
A => jasm/unit_tests/test_addressing_mode_needs_word_size_argument_2_65ce02.asm +5 -0
@@ 0,0 1,5 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000 {
+	jmp ($c0000)
+}

          
A => jasm/unit_tests/test_all_instructions_65ce02.asm +282 -0
@@ 0,0 1,282 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+const address nn = $01
+const address nnnn = $0302
+
+section code, "mainn", $1000
+{
+	// 6502 compatible
+	adc #0
+	adc nn
+	adc nn,x
+	adc nn,y
+	adc nnnn
+	adc nnnn,x
+	adc nnnn,y
+	adc (nn,x)
+	adc (nn),y
+	and #0
+	and nn
+	and nn,x
+	and nn,y
+	and nnnn
+	and nnnn,x
+	and nnnn,y
+	and (nn,x)
+	and (nn),y
+	asl
+	asl nn
+	asl nn,x
+	asl nnnn
+	asl nnnn,x
+	bcc *
+	bcs *
+	beq *
+	bit nn
+	bit nnnn
+	bmi *
+	bne *
+	bpl *
+	brk
+	bvc *
+	bvs *
+	clc
+	cld
+	cli
+	clv
+	cmp #0
+	cmp nn
+	cmp nn,x
+	cmp nn,y
+	cmp nnnn
+	cmp nnnn,x
+	cmp nnnn,y
+	cmp (nn,x)
+	cmp (nn),y
+	cpx #0
+	cpx nn
+	cpx nnnn
+	cpy #0
+	cpy nn
+	cpy nnnn
+	dec nn
+	dec nn,x
+	dec nnnn
+	dec nnnn,x
+	dex
+	dey
+	eor #0
+	eor nn
+	eor nn,x
+	eor nn,y
+	eor nnnn
+	eor nnnn,x
+	eor nnnn,y
+	eor (nn,x)
+	eor (nn),y
+	inc nn
+	inc nn,x
+	inc nnnn
+	inc nnnn,x
+	inx
+	iny
+	jmp nn
+	jmp nnnn
+	jmp (nnnn)
+	jsr nn
+	jsr nnnn
+	lda #0
+	lda nn
+	lda nn,x
+	lda nn,y
+	lda nnnn
+	lda nnnn,x
+	lda nnnn,y
+	lda (nn,x)
+	lda (nn),y
+	ldx #0
+	ldx nn
+	ldx nn,y
+	ldx nnnn
+	ldx nnnn,y
+	ldy #0
+	ldy nn
+	ldy nn,x
+	ldy nnnn
+	ldy nnnn,x
+	lsr
+	lsr nn
+	lsr nn,x
+	lsr nnnn
+	lsr nnnn,x
+	nop
+	ora #0
+	ora nn
+	ora nn,x
+	ora nn,y
+	ora nnnn
+	ora nnnn,x
+	ora nnnn,y
+	ora (nn,x)
+	ora (nn),y
+	pha
+	php
+	pla
+	plp
+	rol
+	rol nn
+	rol nn,x
+	rol nnnn
+	rol nnnn,x
+	ror
+	ror nn
+	ror nn,x
+	ror nnnn
+	ror nnnn,x
+	rti
+	rts
+	sbc #0
+	sbc nn
+	sbc nn,x
+	sbc nn,y
+	sbc nnnn
+	sbc nnnn,x
+	sbc nnnn,y
+	sbc (nn,x)
+	sbc (nn),y
+	sec
+	sed
+	sei
+	sta nn
+	sta nn,x
+	sta nn,y
+	sta nnnn
+	sta nnnn,x
+	sta nnnn,y
+	sta (nn,x)
+	sta (nn),y
+	stx nn
+	stx nn,y
+	stx nnnn
+	sty nn
+	sty nn,x
+	sty nnnn
+	tax
+	tay
+	tsx
+	txa
+	txs
+	tya
+
+	// 65c02 specific
+	bit #0
+	bit nn,x
+	bit nnnn,x
+	dec
+	inc
+	jmp (nnnn,x)
+	phx
+	phy
+	plx
+	ply
+	stz nn
+	stz nn,x
+	stz nnnn
+	stz nnnn,x
+	trb nn
+	trb nnnn
+	tsb nn
+	tsb nnnn
+	bbr 0,nn,*
+	bbr 1,nn,*
+	bbr 2,nn,*
+	bbr 3,nn,*
+	bbr 4,nn,*
+	bbr 5,nn,*
+	bbr 6,nn,*
+	bbr 7,nn,*
+	bbs 0,nn,*
+	bbs 1,nn,*
+	bbs 2,nn,*
+	bbs 3,nn,*
+	bbs 4,nn,*
+	bbs 5,nn,*
+	bbs 6,nn,*
+	bbs 7,nn,*
+	rmb 0,nn
+	rmb 1,nn
+	rmb 2,nn
+	rmb 3,nn
+	rmb 4,nn
+	rmb 5,nn
+	rmb 6,nn
+	rmb 7,nn
+	smb 0,nn
+	smb 1,nn
+	smb 2,nn
+	smb 3,nn
+	smb 4,nn
+	smb 5,nn
+	smb 6,nn
+	smb 7,nn
+
+	// 65ce02 specific
+	adc (nn),z
+	and (nn),z
+	asr
+	asr nn
+	asr nn,x
+	asw nnnn
+	bcc 0
+	bcs 0
+	beq 0
+	bmi 0
+	bne 0
+	bpl 0
+	bru *
+	bru 0
+	bsr *
+	bvc 0
+	bvs 0
+	cle
+	cmp (nn),z
+	cpz #0
+	cpz nn
+	cpz nnnn
+	dew nn
+	dez
+	eor (nn),z
+	inw nn
+	inz
+	jsr (nnnn)
+	jsr (nnnn,x)
+	lda (nn),z
+	lda (nn,sp),y
+	ldz #0
+	ldz nnnn
+	ldz nnnn,x
+	neg
+	ora (nn),z
+	phw #nnnn
+	phw nnnn
+	phz
+	plz
+	row nnnn
+	rtn #0
+	sbc (nn),z
+	see
+	sta (nn),z
+	sta (nn,sp),y
+	stx nnnn,y
+	sty nnnn,x
+	stz nn
+	stz nn,x
+	stz nnnn
+	stz nnnn,x
+	tab
+	taz
+	tba
+	tsy
+	tys
+	tza
+}

          
A => jasm/unit_tests/test_bank_mode_truncates_address_instructions_65ce02.asm +8 -0
@@ 0,0 1,8 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla -bm]
+
+section code, "main", $10203
+{
+.start:
+	lda .start
+	rts
+}

          
A => jasm/unit_tests/test_generate_data_in_instruction_1_65ce02.asm +11 -0
@@ 0,0 1,11 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000
+{
+	macro generate()
+	{
+		nop
+		return 0
+	}
+	lda #generate()
+}

          
A => jasm/unit_tests/test_instruction_data_global_label_65ce02.asm +8 -0
@@ 0,0 1,8 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000
+{
+	lda bulle:#0
+	ldx bulle
+	rts
+}

          
A => jasm/unit_tests/test_instruction_data_label_cant_have_implied_addressing_mode_65ce02.asm +7 -0
@@ 0,0 1,7 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000
+{
+	nop bulle:
+	rts
+}

          
A => jasm/unit_tests/test_instruction_data_label_for_wrong_argument_type_3_65ce02.asm +5 -0
@@ 0,0 1,5 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000 {
+	bbr .lbl:0, 0, *
+}

          
A => jasm/unit_tests/test_instruction_data_label_has_lo_hi_properties_65ce02.asm +8 -0
@@ 0,0 1,8 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000
+{
+	lda .lbl.lo
+	lda .lbl.hi
+	jmp .lbl:*
+}

          
A => jasm/unit_tests/test_instruction_data_label_offsets_65ce02.asm +86 -0
@@ 0,0 1,86 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+const n = 2
+const nn = $1234
+
+section code,	 "main",	 $8000 {
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		lda .lbl:#0
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		lda .lbl:n
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		lda .lbl:n,x
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		ldx .lbl:n,y
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		lda .lbl:nn
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		lda .lbl:nn,x
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		lda .lbl:nn,y
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		bcc .lbl:*
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		lda .lbl:(n,x)
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		lda .lbl:(n),y
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		jmp .lbl:(nn)
+	}
+
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		jmp .lbl:(nn,x)
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		bcc .lbl:*-1000
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		lda .lbl:(n),z
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		lda .lbl:(n,sp),y
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		phw .lbl:#$ffff
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		bbr 0,.lbl:n,*
+	}
+	{
+		static_assert(.lbl == * + 2, "wrong instruction data offset")
+		bbr 0,n,.lbl:*
+	}
+	{
+		static_assert(.lbl == * + 1, "wrong instruction data offset")
+		rmb 0,.lbl:n
+	}
+
+
+}

          
A => jasm/unit_tests/test_instruction_data_label_sizes_65ce02.asm +84 -0
@@ 0,0 1,84 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+const n = 2
+const nn = $1234
+
+section code,	 "main",	 $8000 {
+	{
+		static_assert(sizeof(.lbl) == 1, "wrong instruction data size")
+		lda .lbl:#0
+	}
+	{
+		static_assert(sizeof(.lbl) == 1, "wrong instruction data size")
+		lda .lbl:n
+	}
+	{
+		static_assert(sizeof(.lbl) == 1, "wrong instruction data size")
+		lda .lbl:n,x
+	}
+	{
+		static_assert(sizeof(.lbl) == 1, "wrong instruction data size")
+		ldx .lbl:n,y
+	}
+	{
+		static_assert(sizeof(.lbl) == 2, "wrong instruction data size")
+		lda .lbl:nn
+	}
+	{
+		static_assert(sizeof(.lbl) == 2, "wrong instruction data size")
+		lda .lbl:nn,x
+	}
+	{
+		static_assert(sizeof(.lbl) == 2, "wrong instruction data size")
+		lda .lbl:nn,y
+	}
+	{
+		static_assert(sizeof(.lbl) == 1, "wrong instruction data size")
+		bcc .lbl:*
+	}
+	{
+		static_assert(sizeof(.lbl) == 1, "wrong instruction data size")
+		lda .lbl:(n,x)
+	}
+	{
+		static_assert(sizeof(.lbl) == 1, "wrong instruction data size")
+		lda .lbl:(n),y
+	}
+	{
+		static_assert(sizeof(.lbl) == 2, "wrong instruction data size")
+		jmp .lbl:(nn)
+	}
+
+	{
+		static_assert(sizeof(.lbl) == 2, "wrong instruction data size")
+		jmp .lbl:(nn,x)
+	}
+	{
+		static_assert(sizeof(.lbl) == 2, "wrong instruction data size")
+		bcc .lbl:*-1000
+	}
+	{
+		static_assert(sizeof(.lbl) == 1, "wrong instruction data size")
+		lda .lbl:(n),z
+	}
+	{
+		static_assert(sizeof(.lbl) == 1, "wrong instruction data size")
+		lda .lbl:(n,sp),y
+	}
+	{
+		static_assert(sizeof(.lbl) == 2, "wrong instruction data size")
+		phw .lbl:#$ffff
+	}
+	{
+		static_assert(sizeof(.lbl) == 1, "wrong instruction data size")
+		bbr 0,.lbl:n,*
+	}
+	{
+		static_assert(sizeof(.lbl) == 1, "wrong instruction data size")
+		bbr 0,n,.lbl:*
+	}
+	{
+		static_assert(sizeof(.lbl) == 1, "wrong instruction data size")
+		rmb 0,.lbl:n
+	}
+}

          
A => jasm/unit_tests/test_instruction_data_label_with_export_65ce02.asm +16 -0
@@ 0,0 1,16 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000
+{
+	lda testmod::addr
+	rts
+}
+
+module testmod
+{
+	section part, "main"
+	{
+		export lda addr:$ffff
+		rts
+	}
+}

          
A => jasm/unit_tests/test_instruction_data_label_with_local_export_65ce02.asm +14 -0
@@ 0,0 1,14 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000
+{
+}
+
+module testmod
+{
+	section part, "main"
+	{
+		export lda .addr:$ffff
+		rts
+	}
+}

          
A => jasm/unit_tests/test_instruction_data_local_label_65ce02.asm +8 -0
@@ 0,0 1,8 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section code, "main", $8000
+{
+	lda .bulle: $ffff
+	ldx .bulle
+	rts
+}

          
A => jasm/unit_tests/test_instruction_ends_at_newline_1_65ce02.asm +13 -0
@@ 0,0 1,13 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+var a = 1
+
+section code, "main", $8000 {
+	lda #a
+	+a + sin(0) // function looks like side effect so it tricks the assembler to not trigger the error "statement must have side effect"
+	lda a
+	+a + sin(0)
+	rol
+	+a + sin(0)
+	rts
+}

          
A => jasm/unit_tests/test_instruction_ends_at_newline_2_65ce02.asm +9 -0
@@ 0,0 1,9 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+var a = 1
+
+section code, "main", $8000 {
+	lda #
+	+a
+	rts
+}

          
A => jasm/unit_tests/test_instruction_names_can_be_used_in_local_variables_65ce02.asm +7 -0
@@ 0,0 1,7 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $1000
+{
+	const .inc = 0
+	define byte = .inc
+}

          
A => jasm/unit_tests/test_instructions_must_be_in_code_sections_1_65ce02.asm +3 -0
@@ 0,0 1,3 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+rol

          
A => jasm/unit_tests/test_instructions_must_be_in_code_sections_2_65ce02.asm +5 -0
@@ 0,0 1,5 @@ 
+// assembler command line arguments: 65ce02 [-v0 -hla]
+
+section bss, "data", $8000 {
+	rol
+}
  No newline at end of file

          
A => jasm/unit_tests/test_pseudo_instructions_for_branching_65ce02.asm +8 -0
@@ 0,0 1,8 @@ 
+// assembler command line arguments: 65ce02 [-v0 -pi]
+
+section code, "main", $8000
+{
+	bhs *
+	blt *
+	bra *
+}

          
A => jasm/unit_tests/test_pseudo_instructions_for_incrementing_65ce02.asm +7 -0
@@ 0,0 1,7 @@ 
+// assembler command line arguments: 65ce02 [-v0 -pi]
+
+section code, "main", $8000
+{
+	dea
+	ina
+}

          
A => jasm/unit_tests/test_pseudo_instructions_in_standard_mode_65ce02.asm +10 -0
@@ 0,0 1,10 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000
+{
+	bhs *
+	blt *
+	bra *
+	dea
+	ina
+}

          
A => jasm/unit_tests/test_pseudo_instructions_use_names_in_standard_mode_65ce02.asm +7 -0
@@ 0,0 1,7 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000
+{
+bhs:
+	rts
+}

          
A => jasm/unit_tests/test_register_names_can_be_used_in_local_names_65ce02.asm +10 -0
@@ 0,0 1,10 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $1000
+{
+	const .x = 0
+	const .y = 1
+
+	define byte = .x
+	define byte = .y
+}

          
A => jasm/unit_tests/test_register_names_cant_be_used_as_global_variables_65ce02.asm +7 -0
@@ 0,0 1,7 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $1000
+{
+	const x = 0
+	define byte = x
+}

          
A => jasm/unit_tests/test_subroutine_call_65ce02.asm +11 -0
@@ 0,0 1,11 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000, $9000
+{
+	test()
+
+	subroutine test
+	{
+		rts
+	}
+}

          
A => jasm/unit_tests/test_subroutine_call_must_be_in_code_section_65ce02.asm +11 -0
@@ 0,0 1,11 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+test()
+
+section code, "main", $8000, $9000
+{
+	subroutine test
+	{
+		rts
+	}
+}

          
A => jasm/unit_tests/test_subroutine_call_negative_argument_65ce02.asm +11 -0
@@ 0,0 1,11 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", -4, $9000
+{
+	test()
+
+	subroutine test
+	{
+		rts
+	}
+}

          
A => jasm/unit_tests/test_subroutine_call_recursive_data_generation_65ce02.asm +11 -0
@@ 0,0 1,11 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000, $9000
+{
+	lda #test()
+	
+	subroutine test
+	{
+		rts
+	}
+}

          
A => jasm/unit_tests/test_subroutine_call_too_large_argument_65ce02.asm +11 -0
@@ 0,0 1,11 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $fffd
+{
+	test()
+
+	subroutine test
+	{
+		rts
+	}
+}

          
A => jasm/unit_tests/test_subroutine_call_with_arguments_65ce02.asm +11 -0
@@ 0,0 1,11 @@ 
+// assembler command line arguments: 65ce02 [-v0]
+
+section code, "main", $8000
+{
+	test(1)
+
+	subroutine test
+	{
+		rts
+	}
+}

          
A => jasm/unit_tests/test_subroutine_falls_through_1_65ce02.asm +10 -0
@@ 0,0 1,10 @@ 
+// assembler command line arguments: 65ce02 [-v2 -hla]
+
+section code, "main", $8000 {
+
+	subroutine test
+	{
+	}
+
+	rts
+}

          
A => jasm/unit_tests/test_subroutine_falls_through_2_65ce02.asm +11 -0
@@ 0,0 1,11 @@ 
+// assembler command line arguments: 65ce02 [-v2 -hla]
+
+section code, "main", $8000 {
+
+	subroutine test
+	{
+		nop
+	}
+
+	rts
+}

          
A => jasm/unit_tests/test_subroutine_falls_through_3_65ce02.asm +9 -0
@@ 0,0 1,9 @@ 
+// assembler command line arguments: 65ce02 [-v2 -hla]
+
+section code, "main", $8000 {
+
+	subroutine test
+	{
+		rts
+	}
+}

          
A => jasm/unit_tests/test_subroutine_falls_through_4_65ce02.asm +9 -0
@@ 0,0 1,9 @@ 
+// assembler command line arguments: 65ce02 [-v2 -hla]
+
+section code, "main", $8000 {
+
+	subroutine test
+	{
+		jmp test
+	}
+}

          
A => jasm/unit_tests/test_subroutine_falls_through_5_65ce02.asm +9 -0
@@ 0,0 1,9 @@ 
+// assembler command line arguments: 65ce02 [-v2 -hla]
+
+section code, "main", $8000 {
+
+	subroutine test
+	{
+		bru test
+	}
+}

          
M jasm/version.h +1 -1
@@ 1,1 1,1 @@ 
-1,27
+1,28

          
M jasm/website/site/docs/index.html +51 -1
@@ 14,7 14,7 @@ 
 
 <hr />
 
-<p>This is the documentation for the 6502 and Z80 assembler jAsm. It was written in 2015 by me, Jonas Hult&eacute;n, because I used DAsm before and over the years it started to feel outdated. I missed namespaces and I was annoyed by some bugs, like its inability to use local variables as macro arguments. It felt a bit slow on my slow laptop computer as well, although that wasn't a strong argument. Also, I hadn't written a language before and it felt like an interesting challenge.</p>
+<p>This is the documentation for the 6502, 65C02, 65CE02 and Z80 assembler jAsm. It was written in 2015 by me, Jonas Hult&eacute;n, because I used DAsm before and over the years it started to feel outdated. I missed namespaces and I was annoyed by some bugs, like its inability to use local variables as macro arguments. It felt a bit slow on my slow laptop computer as well, although that wasn't a strong argument. Also, I hadn't written a language before and it felt like an interesting challenge.</p>
 
 <p>jAsm was written with two main goals. It should be fast enough to assemble a large program in under a second and it should support everything DAsm can do and more. To reach the required speed it tries to use memory as linearly as possible and it proved to be faster than DAsm in the end.</p>
 

          
@@ 35,6 35,7 @@ 
 <ul>
 <li><a href="#m6502">6502</a></li>
 <li><a href="#wdc65c02">65c02</a></li>
+<li><a href="#csg65ce02">65ce02</a></li>
 <li><a href="#z80">Z80</a></li>
 </ul></li>
 <li><a href="#starter-guide">Starter Guide</a>

          
@@ 77,6 78,7 @@ 
 <ul>
 <li><a href="#6502-pseudo-instructions">6502 Pseudo Instructions</a></li>
 <li><a href="#65c02-pseudo-instructions">65c02 Pseudo Instructions</a></li>
+<li><a href="#65ce02-pseudo-instructions">65ce02 Pseudo Instructions</a></li>
 <li><a href="#z80-pseudo-instructions">Z80 Pseudo Instructions</a></li>
 </ul></li>
 <li><a href="#verboseness">Verboseness</a></li>

          
@@ 183,6 185,31 @@ 
 <span class="instruction">smb</span> <span class="literal">3</span>, zp
 </code></pre>
 
+<div id="csg65ce02"></div>
+
+<h2>65CE02</h2>
+
+<p>jAsm supports all regular instructions of the Commodore Semiconductor Group 65CE02. Instructions are written in lower case.</p>
+
+<pre><code><span class="instruction">ldz</span> <span class="literal">$d020</span>
+<span class="instruction">bru</span> loop
+</code></pre>
+
+<p>Just like 65C02, the bit operation instructions don't have the bit in the instruction name as some assemblers do. Instead it is a separate argument. To follow convention, there is no '#' before the bit number to indicate immediate mode, even if that would be more consistent.</p>
+
+<pre><code><span class="instruction">bbr</span> <span class="literal">0</span>, zp, label
+<span class="instruction">bbs</span> <span class="literal">1</span>, zp, label
+<span class="instruction">rmb</span> <span class="literal">2</span>, zp
+<span class="instruction">smb</span> <span class="literal">3</span>, zp
+</code></pre>
+
+<p>The aug instruction isn't available since that's intended to extend the processor with more instructions in the future.</p>
+
+<p>The stack pointer relative access addressing mode is written like this.</p>
+
+<pre><code><span class="instruction">lda</span> <span class="special">(</span><span class="literal">$55</span>,sp<span class="special">)</span>,y
+</code></pre>
+
 <div id="z80"></div>
 
 <h2>Z80</h2>

          
@@ 1322,6 1349,29 @@ jasm --define DEFAULT_NAME=bobo input.ja
 
 <p>These are equivalent to the implied mode <code><span class="instruction">dec</span></code> and <code><span class="instruction">inc</span></code>, respectively.</p>
 
+<div id="65ce02-pseudo-instructions"></div>
+
+<h3>65CE02 pseudo instructions</h3>
+
+<p>These are the pseudo instructions for 65CE02.</p>
+
+<pre><code><span class="instruction">bhs</span> addr <span class="comment">// branch if higher or same</span>
+<span class="instruction">blt</span> addr <span class="comment">// branch if lower</span>
+</code></pre>
+
+<p>These are equivalent to <code><span class="instruction">bcs</span></code> and <code><span class="instruction">bcc</span></code>, respectively.</p>
+
+<pre><code><span class="instruction">dea</span> <span class="comment">// decrement A register</span>
+<span class="instruction">ina</span> <span class="comment">// increment A register</span>