From b60dc4fee4810a93a49613c955afb4ed74737b80 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Sat, 10 Oct 2020 15:33:08 -0700 Subject: [PATCH] Add W65C02S support, part 1 We were claiming W65C02S, but it turns out that CPU has the Rockwell extensions and the STP/WAI instructions. We need to change existing references to be "WDC 65C02", and add a new CPU definition for the actual W65C02S chip. This adds the new CPU definition, the instruction definitions for the Rockwell extensions, and updates the selectors in project properties and the instruction chart tool. This change shouldn't affect any existing projects. Still more to do before W65C02 works though, mostly because the Rockwell instructions introduced a new two-argument address mode that has to be handled in various places. --- Asm65/CpuDef.cs | 283 +++++++++++++++++- Asm65/Formatter.cs | 1 + Asm65/OpDef.cs | 229 +++++++++++++- Asm65/OpDescription.cs | 82 +++++ Asm65/OpName.cs | 41 ++- SourceGen/RuntimeData/Help/settings.html | 15 +- SourceGen/Tools/WpfGui/InstructionChart.xaml | 3 +- .../Tools/WpfGui/InstructionChart.xaml.cs | 3 + SourceGen/WpfGui/EditProjectProperties.xaml | 3 +- .../WpfGui/EditProjectProperties.xaml.cs | 1 + 10 files changed, 647 insertions(+), 14 deletions(-) diff --git a/Asm65/CpuDef.cs b/Asm65/CpuDef.cs index b854deb..3c0eb29 100644 --- a/Asm65/CpuDef.cs +++ b/Asm65/CpuDef.cs @@ -85,6 +85,7 @@ namespace Asm65 { Cpu65C02, // Apple //e Cpu65SC02, // Atari Lynx + CpuW65C02, // ? Cpu65802, // ? Cpu65816, // Apple IIgs @@ -107,6 +108,7 @@ namespace Asm65 { case "2A03": return CpuType.Cpu2A03; case "65C02": return CpuType.Cpu65C02; case "65SC02": return CpuType.Cpu65SC02; + case "W65C02": return CpuType.CpuW65C02; case "65802": return CpuType.Cpu65802; case "65816": return CpuType.Cpu65816; case "5A22": return CpuType.Cpu5A22; @@ -131,6 +133,7 @@ namespace Asm65 { case CpuType.Cpu2A03: return "2A03"; case CpuType.Cpu65C02: return "65C02"; case CpuType.Cpu65SC02: return "65SC02"; + case CpuType.CpuW65C02: return "W65C02"; case CpuType.Cpu65802: return "65802"; case CpuType.Cpu65816: return "65816"; case CpuType.Cpu5A22: return "5A22"; @@ -149,12 +152,14 @@ namespace Asm65 { public static CpuDef GetBestMatch(CpuType type, bool includeUndocumented, bool twoByteBrk) { // Many 65xx variants boil down to a 6502, 65C02, or 65816, at least as far as - // a disassembler needs to know. These do not, and would need full definitions: + // a disassembler needs to know. WDC's W65C02 has the Rockwell extensions plus + // a couple more, so it works for the extended 65C02 variants. + // + // These don't strictly fit, and would need full definitions: // // Hudson Soft HuC6280 (PC Engine / TurboGrafx) // Commodore CSG 4510 / CSG 65CE02 (Amiga A2232 serial port; 4510 has one // additional instruction, so use that as archetype) - // Rockwell R65C02 (used in ???) // Jeri's 65DTV02 (used in C64DTV single-chip computer); same as 6502 with // some differences in illegal opcodes // Eloraam 65EL02 (defined in a Minecraft-based emulator) @@ -170,6 +175,9 @@ namespace Asm65 { case CpuType.Cpu65SC02: cpuDef = Cpu65C02; break; + case CpuType.CpuW65C02: + cpuDef = CpuW65C02; + break; default: // 6502, 6502B, 6502C, 6507, 6510, 8502, 2A03 cpuDef = Cpu6502; @@ -349,6 +357,7 @@ namespace Asm65 { public static bool DebugValidate() { InternalValidate(Cpu6502); InternalValidate(Cpu65C02); + InternalValidate(CpuW65C02); InternalValidate(Cpu65816); Debug.WriteLine("CpuDefs okay"); return true; @@ -696,8 +705,8 @@ namespace Asm65 { }; - // WDC's 65C02, with new opcodes and a handful of slightly strange NOPs. - private static CpuDef Cpu65C02 { get; } = new CpuDef("WDC W65C02S", (1 << 16) - 1, false) { + // Original 65C02, with new opcodes and a handful of slightly strange NOPs. + private static CpuDef Cpu65C02 { get; } = new CpuDef("WDC 65C02", (1 << 16) - 1, false) { Type = CpuType.Cpu65C02, mOpDefs = new OpDef[] { OpDef.OpBRK_Implied, // 0x00 @@ -960,6 +969,272 @@ namespace Asm65 { }; + // WDC's W65C02, with the Rockwell extensions and STP/WAI. I'm assuming that the + // behavior of the undocumented instructions remains unchanged, which is probably unwise + // but I have no information to the contrary. + private static CpuDef CpuW65C02 { get; } = new CpuDef("WDC W65C02S", (1 << 16) - 1, false) { + Type = CpuType.Cpu65C02, + mOpDefs = new OpDef[] { + OpDef.OpBRK_Implied, // 0x00 + OpDef.OpORA_DPIndexXInd, + OpDef.GenerateUndoc(0x02, OpDef.OpLDD_Imm), + OpDef.GenerateUndoc(0x03, OpDef.OpNOP_65C02), + OpDef.OpTSB_DP, + OpDef.OpORA_DP, + OpDef.OpASL_DP, + OpDef.OpRMB0_DP, + OpDef.OpPHP_StackPush, // 0x08 + OpDef.OpORA_Imm, + OpDef.OpASL_Acc, + OpDef.GenerateUndoc(0x0b, OpDef.OpNOP_65C02), + OpDef.OpTSB_Abs, + OpDef.OpORA_Abs, + OpDef.OpASL_Abs, + OpDef.OpBBR0_DPPCRel, + OpDef.OpBPL_PCRel, // 0x10 + OpDef.OpORA_DPIndIndexY, + OpDef.OpORA_DPInd, + OpDef.GenerateUndoc(0x13, OpDef.OpNOP_65C02), + OpDef.OpTRB_DP, + OpDef.OpORA_DPIndexX, + OpDef.OpASL_DPIndexX, + OpDef.OpRMB1_DP, + OpDef.OpCLC_Implied, // 0x18 + OpDef.OpORA_AbsIndexY, + OpDef.OpINC_Acc, + OpDef.GenerateUndoc(0x1b, OpDef.OpNOP_65C02), + OpDef.OpTRB_Abs, + OpDef.OpORA_AbsIndexX, + OpDef.OpASL_AbsIndexX, + OpDef.OpBBR1_DPPCRel, + OpDef.OpJSR_Abs, // 0x20 + OpDef.OpAND_DPIndexXInd, + OpDef.GenerateUndoc(0x22, OpDef.OpLDD_Imm), + OpDef.GenerateUndoc(0x23, OpDef.OpNOP_65C02), + OpDef.OpBIT_DP, + OpDef.OpAND_DP, + OpDef.OpROL_DP, + OpDef.OpRMB2_DP, + OpDef.OpPLP_StackPull, // 0x28 + OpDef.OpAND_Imm, + OpDef.OpROL_Acc, + OpDef.GenerateUndoc(0x2b, OpDef.OpNOP_65C02), + OpDef.OpBIT_Abs, + OpDef.OpAND_Abs, + OpDef.OpROL_Abs, + OpDef.OpBBR2_DPPCRel, + OpDef.OpBMI_PCRel, // 0x30 + OpDef.OpAND_DPIndIndexY, + OpDef.OpAND_DPInd, + OpDef.GenerateUndoc(0x33, OpDef.OpNOP_65C02), + OpDef.OpBIT_DPIndexX, + OpDef.OpAND_DPIndexX, + OpDef.OpROL_DPIndexX, + OpDef.OpRMB3_DP, + OpDef.OpSEC_Implied, // 0x38 + OpDef.OpAND_AbsIndexY, + OpDef.OpDEC_Acc, + OpDef.GenerateUndoc(0x3b, OpDef.OpNOP_65C02), + OpDef.OpBIT_AbsIndexX, + OpDef.OpAND_AbsIndexX, + OpDef.OpROL_AbsIndexX, + OpDef.OpBBR3_DPPCRel, + OpDef.OpRTI_StackRTI, // 0x40 + OpDef.OpEOR_DPIndexXInd, + OpDef.GenerateUndoc(0x42, OpDef.OpLDD_Imm), + OpDef.GenerateUndoc(0x43, OpDef.OpNOP_65C02), + OpDef.GenerateUndoc(0x44, OpDef.OpLDD_DP), + OpDef.OpEOR_DP, + OpDef.OpLSR_DP, + OpDef.OpRMB4_DP, + OpDef.OpPHA_StackPush, // 0x48 + OpDef.OpEOR_Imm, + OpDef.OpLSR_Acc, + OpDef.GenerateUndoc(0x4b, OpDef.OpNOP_65C02), + OpDef.OpJMP_Abs, + OpDef.OpEOR_Abs, + OpDef.OpLSR_Abs, + OpDef.OpBBR4_DPPCRel, + OpDef.OpBVC_PCRel, // 0x50 + OpDef.OpEOR_DPIndIndexY, + OpDef.OpEOR_DPInd, + OpDef.GenerateUndoc(0x53, OpDef.OpNOP_65C02), + OpDef.GenerateUndoc(0x54, OpDef.OpLDD_DPIndexX), + OpDef.OpEOR_DPIndexX, + OpDef.OpLSR_DPIndexX, + OpDef.OpRMB5_DP, + OpDef.OpCLI_Implied, // 0x58 + OpDef.OpEOR_AbsIndexY, + OpDef.OpPHY_StackPush, + OpDef.GenerateUndoc(0x5b, OpDef.OpNOP_65C02), + OpDef.GenerateUndoc(0x5c, OpDef.OpLDD_Weird), + OpDef.OpEOR_AbsIndexX, + OpDef.OpLSR_AbsIndexX, + OpDef.OpBBR5_DPPCRel, + OpDef.OpRTS_StackRTS, // 0x60 + OpDef.OpADC_DPIndexXInd, + OpDef.GenerateUndoc(0x62, OpDef.OpLDD_Imm), + OpDef.GenerateUndoc(0x63, OpDef.OpNOP_65C02), + OpDef.OpSTZ_DP, + OpDef.OpADC_DP, + OpDef.OpROR_DP, + OpDef.OpRMB6_DP, + OpDef.OpPLA_StackPull, // 0x68 + OpDef.OpADC_Imm, + OpDef.OpROR_Acc, + OpDef.GenerateUndoc(0x6b, OpDef.OpNOP_65C02), + OpDef.OpJMP_AbsInd, + OpDef.OpADC_Abs, + OpDef.OpROR_Abs, + OpDef.OpBBR6_DPPCRel, + OpDef.OpBVS_PCRel, // 0x70 + OpDef.OpADC_DPIndIndexY, + OpDef.OpADC_DPInd, + OpDef.GenerateUndoc(0x73, OpDef.OpNOP_65C02), + OpDef.OpSTZ_DPIndexX, + OpDef.OpADC_DPIndexX, + OpDef.OpROR_DPIndexX, + OpDef.OpRMB7_DP, + OpDef.OpSEI_Implied, // 0x78 + OpDef.OpADC_AbsIndexY, + OpDef.OpPLY_StackPull, + OpDef.GenerateUndoc(0x7b, OpDef.OpNOP_65C02), + OpDef.OpJMP_AbsIndexXInd, + OpDef.OpADC_AbsIndexX, + OpDef.OpROR_AbsIndexX, + OpDef.OpBBR7_DPPCRel, + OpDef.OpBRA_PCRel, // 0x80 + OpDef.OpSTA_DPIndexXInd, + OpDef.GenerateUndoc(0x82, OpDef.OpLDD_Imm), + OpDef.GenerateUndoc(0x83, OpDef.OpNOP_65C02), + OpDef.OpSTY_DP, + OpDef.OpSTA_DP, + OpDef.OpSTX_DP, + OpDef.OpSMB0_DP, + OpDef.OpDEY_Implied, // 0x88 + OpDef.OpBIT_Imm, + OpDef.OpTXA_Implied, + OpDef.GenerateUndoc(0x8b, OpDef.OpNOP_65C02), + OpDef.OpSTY_Abs, + OpDef.OpSTA_Abs, + OpDef.OpSTX_Abs, + OpDef.OpBBS0_DPPCRel, + OpDef.OpBCC_PCRel, // 0x90 + OpDef.OpSTA_DPIndIndexY, + OpDef.OpSTA_DPInd, + OpDef.GenerateUndoc(0x93, OpDef.OpNOP_65C02), + OpDef.OpSTY_DPIndexX, + OpDef.OpSTA_DPIndexX, + OpDef.OpSTX_DPIndexY, + OpDef.OpSMB1_DP, + OpDef.OpTYA_Implied, // 0x98 + OpDef.OpSTA_AbsIndexY, + OpDef.OpTXS_Implied, + OpDef.GenerateUndoc(0x9b, OpDef.OpNOP_65C02), + OpDef.OpSTZ_Abs, + OpDef.OpSTA_AbsIndexX, + OpDef.OpSTZ_AbsIndexX, + OpDef.OpBBS1_DPPCRel, + OpDef.OpLDY_Imm, // 0xa0 + OpDef.OpLDA_DPIndexXInd, + OpDef.OpLDX_Imm, + OpDef.GenerateUndoc(0xa3, OpDef.OpNOP_65C02), + OpDef.OpLDY_DP, + OpDef.OpLDA_DP, + OpDef.OpLDX_DP, + OpDef.OpSMB2_DP, + OpDef.OpTAY_Implied, // 0xa8 + OpDef.OpLDA_Imm, + OpDef.OpTAX_Implied, + OpDef.GenerateUndoc(0xab, OpDef.OpNOP_65C02), + OpDef.OpLDY_Abs, + OpDef.OpLDA_Abs, + OpDef.OpLDX_Abs, + OpDef.OpBBS2_DPPCRel, + OpDef.OpBCS_PCRel, // 0xb0 + OpDef.OpLDA_DPIndIndexY, + OpDef.OpLDA_DPInd, + OpDef.GenerateUndoc(0xb3, OpDef.OpNOP_65C02), + OpDef.OpLDY_DPIndexX, + OpDef.OpLDA_DPIndexX, + OpDef.OpLDX_DPIndexY, + OpDef.OpSMB3_DP, + OpDef.OpCLV_Implied, // 0xb8 + OpDef.OpLDA_AbsIndexY, + OpDef.OpTSX_Implied, + OpDef.GenerateUndoc(0xbb, OpDef.OpNOP_65C02), + OpDef.OpLDY_AbsIndexX, + OpDef.OpLDA_AbsIndexX, + OpDef.OpLDX_AbsIndexY, + OpDef.OpBBS3_DPPCRel, + OpDef.OpCPY_Imm, // 0xc0 + OpDef.OpCMP_DPIndexXInd, + OpDef.GenerateUndoc(0xc2, OpDef.OpLDD_Imm), + OpDef.GenerateUndoc(0xc3, OpDef.OpNOP_65C02), + OpDef.OpCPY_DP, + OpDef.OpCMP_DP, + OpDef.OpDEC_DP, + OpDef.OpSMB4_DP, + OpDef.OpINY_Implied, // 0xc8 + OpDef.OpCMP_Imm, + OpDef.OpDEX_Implied, + OpDef.OpWAI_Implied, + OpDef.OpCPY_Abs, + OpDef.OpCMP_Abs, + OpDef.OpDEC_Abs, + OpDef.OpBBS4_DPPCRel, + OpDef.OpBNE_PCRel, // 0xd0 + OpDef.OpCMP_DPIndIndexY, + OpDef.OpCMP_DPInd, + OpDef.GenerateUndoc(0xd3, OpDef.OpNOP_65C02), + OpDef.GenerateUndoc(0xd4, OpDef.OpLDD_DPIndexX), + OpDef.OpCMP_DPIndexX, + OpDef.OpDEC_DPIndexX, + OpDef.OpSMB5_DP, + OpDef.OpCLD_Implied, // 0xd8 + OpDef.OpCMP_AbsIndexY, + OpDef.OpPHX_StackPush, + OpDef.OpSTP_Implied, + OpDef.GenerateUndoc(0xdc, OpDef.OpLDD_Absolute), + OpDef.OpCMP_AbsIndexX, + OpDef.OpDEC_AbsIndexX, + OpDef.OpBBS5_DPPCRel, + OpDef.OpCPX_Imm, // 0xe0 + OpDef.OpSBC_DPIndexXInd, + OpDef.GenerateUndoc(0xe2, OpDef.OpLDD_Imm), + OpDef.GenerateUndoc(0xe3, OpDef.OpNOP_65C02), + OpDef.OpCPX_DP, + OpDef.OpSBC_DP, + OpDef.OpINC_DP, + OpDef.OpSMB6_DP, + OpDef.OpINX_Implied, // 0xe8 + OpDef.OpSBC_Imm, + OpDef.OpNOP_Implied, + OpDef.GenerateUndoc(0xeb, OpDef.OpNOP_65C02), + OpDef.OpCPX_Abs, + OpDef.OpSBC_Abs, + OpDef.OpINC_Abs, + OpDef.OpBBS6_DPPCRel, + OpDef.OpBEQ_PCRel, // 0xf0 + OpDef.OpSBC_DPIndIndexY, + OpDef.OpSBC_DPInd, + OpDef.GenerateUndoc(0xf3, OpDef.OpNOP_65C02), + OpDef.GenerateUndoc(0xf4, OpDef.OpLDD_DPIndexX), + OpDef.OpSBC_DPIndexX, + OpDef.OpINC_DPIndexX, + OpDef.OpSMB7_DP, + OpDef.OpSED_Implied, // 0xf8 + OpDef.OpSBC_AbsIndexY, + OpDef.OpPLX_StackPull, + OpDef.GenerateUndoc(0xfb, OpDef.OpNOP_65C02), + OpDef.GenerateUndoc(0xfc, OpDef.OpLDD_Absolute), + OpDef.OpSBC_AbsIndexX, + OpDef.OpINC_AbsIndexX, + OpDef.OpBBS7_DPPCRel, + } + }; + + // WDC 65802 and 65816. No undocumented opcodes -- all 256 are used. private static CpuDef Cpu65816 { get; } = new CpuDef("WDC W65C816S", (1 << 24) - 1, true) { Type = CpuType.Cpu65816, diff --git a/Asm65/Formatter.cs b/Asm65/Formatter.cs index 6e28140..43e1228 100644 --- a/Asm65/Formatter.cs +++ b/Asm65/Formatter.cs @@ -805,6 +805,7 @@ namespace Asm65 { case AddressMode.BlockMove: case AddressMode.StackAbs: case AddressMode.DP: + case AddressMode.DPPCRel: case AddressMode.PCRel: case AddressMode.PCRelLong: // BRL case AddressMode.StackInt: // COP and two-byte BRK diff --git a/Asm65/OpDef.cs b/Asm65/OpDef.cs index af96638..7808406 100644 --- a/Asm65/OpDef.cs +++ b/Asm65/OpDef.cs @@ -74,6 +74,7 @@ namespace Asm65 { DPIndexX, // OP dp,X 2 DPIndexXInd, // OP (dp,X) 2 DPIndexY, // OP dp,Y 2 + DPPCRel, // OP dp,label 3 (BBR/BBS) Imm, // OP #const8 2 ImmLongA, // OP #const8/16 2 or 3, depending on 'm' flag ImmLongXY, // OP #const8/16 2 or 3, depending on 'x' flag @@ -526,6 +527,7 @@ namespace Asm65 { case AddressMode.AbsInd: case AddressMode.AbsIndLong: case AddressMode.BlockMove: + case AddressMode.DPPCRel: case AddressMode.PCRelLong: case AddressMode.StackAbs: case AddressMode.StackPCRelLong: @@ -607,7 +609,7 @@ namespace Asm65 { } /// - /// Get the raw operand value. + /// Gets the raw operand value. /// /// 65xx code. /// Offset of opcode. @@ -3543,6 +3545,231 @@ namespace Asm65 { #endregion Undocumented + #region Rockwell extensions + + // ====================================================================================== + // Rockwell extensions to the 65C02. + // + // These are declared separately because they overlap with 65816 instructions. The + // 32 opcodes occupy the numbers $x7 and $xf. + // + + private static OpDef OpBBR = new OpDef() { + Mnemonic = "???", + Effect = FlowEffect.ConditionalBranch, + BaseMemEffect = MemoryEffect.None + }; + private static OpDef OpBBS = new OpDef() { + Mnemonic = "???", + Effect = FlowEffect.ConditionalBranch, + BaseMemEffect = MemoryEffect.None + }; + private static OpDef OpRMB = new OpDef() { + Mnemonic = "???", + Effect = FlowEffect.Cont, + BaseMemEffect = MemoryEffect.ReadModifyWrite + }; + private static OpDef OpSMB = new OpDef() { + Mnemonic = "???", + Effect = FlowEffect.Cont, + BaseMemEffect = MemoryEffect.ReadModifyWrite + }; + + public static readonly OpDef OpBBR0_DPPCRel = new OpDef(OpBBR) { + Mnemonic = OpName.BBR0, + Opcode = 0x0f, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBR1_DPPCRel = new OpDef(OpBBR) { + Mnemonic = OpName.BBR1, + Opcode = 0x1f, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBR2_DPPCRel = new OpDef(OpBBR) { + Mnemonic = OpName.BBR2, + Opcode = 0x2f, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBR3_DPPCRel = new OpDef(OpBBR) { + Mnemonic = OpName.BBR3, + Opcode = 0x3f, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBR4_DPPCRel = new OpDef(OpBBR) { + Mnemonic = OpName.BBR4, + Opcode = 0x4f, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBR5_DPPCRel = new OpDef(OpBBR) { + Mnemonic = OpName.BBR5, + Opcode = 0x5f, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBR6_DPPCRel = new OpDef(OpBBR) { + Mnemonic = OpName.BBR6, + Opcode = 0x6f, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBR7_DPPCRel = new OpDef(OpBBR) { + Mnemonic = OpName.BBR7, + Opcode = 0x7f, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBS0_DPPCRel = new OpDef(OpBBS) { + Mnemonic = OpName.BBS0, + Opcode = 0x8f, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBS1_DPPCRel = new OpDef(OpBBS) { + Mnemonic = OpName.BBS1, + Opcode = 0x9f, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBS2_DPPCRel = new OpDef(OpBBS) { + Mnemonic = OpName.BBS2, + Opcode = 0xaf, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBS3_DPPCRel = new OpDef(OpBBS) { + Mnemonic = OpName.BBS3, + Opcode = 0xbf, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBS4_DPPCRel = new OpDef(OpBBS) { + Mnemonic = OpName.BBS4, + Opcode = 0xcf, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBS5_DPPCRel = new OpDef(OpBBS) { + Mnemonic = OpName.BBS5, + Opcode = 0xdf, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBS6_DPPCRel = new OpDef(OpBBS) { + Mnemonic = OpName.BBS6, + Opcode = 0xef, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpBBS7_DPPCRel = new OpDef(OpBBS) { + Mnemonic = OpName.BBS7, + Opcode = 0xff, + AddrMode = AddressMode.DPPCRel, + CycDef = 5 + }; + public static readonly OpDef OpRMB0_DP = new OpDef(OpRMB) { + Mnemonic = OpName.RMB0, + Opcode = 0x07, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpRMB1_DP = new OpDef(OpRMB) { + Mnemonic = OpName.RMB1, + Opcode = 0x17, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpRMB2_DP = new OpDef(OpRMB) { + Mnemonic = OpName.RMB2, + Opcode = 0x27, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpRMB3_DP = new OpDef(OpRMB) { + Mnemonic = OpName.RMB3, + Opcode = 0x37, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpRMB4_DP = new OpDef(OpRMB) { + Mnemonic = OpName.RMB4, + Opcode = 0x47, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpRMB5_DP = new OpDef(OpRMB) { + Mnemonic = OpName.RMB5, + Opcode = 0x57, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpRMB6_DP = new OpDef(OpRMB) { + Mnemonic = OpName.RMB6, + Opcode = 0x67, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpRMB7_DP = new OpDef(OpRMB) { + Mnemonic = OpName.RMB7, + Opcode = 0x77, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpSMB0_DP = new OpDef(OpSMB) { + Mnemonic = OpName.SMB0, + Opcode = 0x87, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpSMB1_DP = new OpDef(OpSMB) { + Mnemonic = OpName.SMB1, + Opcode = 0x97, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpSMB2_DP = new OpDef(OpSMB) { + Mnemonic = OpName.SMB2, + Opcode = 0xa7, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpSMB3_DP = new OpDef(OpSMB) { + Mnemonic = OpName.SMB3, + Opcode = 0xb7, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpSMB4_DP = new OpDef(OpSMB) { + Mnemonic = OpName.SMB4, + Opcode = 0xc7, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpSMB5_DP = new OpDef(OpSMB) { + Mnemonic = OpName.SMB5, + Opcode = 0xd7, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpSMB6_DP = new OpDef(OpSMB) { + Mnemonic = OpName.SMB6, + Opcode = 0xe7, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + public static readonly OpDef OpSMB7_DP = new OpDef(OpSMB) { + Mnemonic = OpName.SMB7, + Opcode = 0xf7, + AddrMode = AddressMode.DP, + CycDef = 5 + }; + + #endregion Rockwell extensions + /// /// Generates one of the multiply-defined opcodes from a prototype. This is diff --git a/Asm65/OpDescription.cs b/Asm65/OpDescription.cs index b88576f..c6b9ab5 100644 --- a/Asm65/OpDescription.cs +++ b/Asm65/OpDescription.cs @@ -117,6 +117,7 @@ namespace Asm65 { /// shorter than those in the CPU data sheet. /// private static Dictionary sShort_enUS = new Dictionary() { + // 65816 instructions. { OpName.ADC, "Add With Carry" }, { OpName.AND, "AND Accumulator With Memory" }, { OpName.ASL, "Shift Memory or Accumulator Left" }, @@ -236,6 +237,40 @@ namespace Asm65 { // WDC 65C02 undocumented { OpName.LDD, "Load and Discard" }, + + // Rockwell 65C02 extensions + { OpName.BBR0, "Branch on Bit Reset" }, + { OpName.BBR1, "Branch on Bit Reset" }, + { OpName.BBR2, "Branch on Bit Reset" }, + { OpName.BBR3, "Branch on Bit Reset" }, + { OpName.BBR4, "Branch on Bit Reset" }, + { OpName.BBR5, "Branch on Bit Reset" }, + { OpName.BBR6, "Branch on Bit Reset" }, + { OpName.BBR7, "Branch on Bit Reset" }, + { OpName.BBS0, "Branch on Bit Set" }, + { OpName.BBS1, "Branch on Bit Set" }, + { OpName.BBS2, "Branch on Bit Set" }, + { OpName.BBS3, "Branch on Bit Set" }, + { OpName.BBS4, "Branch on Bit Set" }, + { OpName.BBS5, "Branch on Bit Set" }, + { OpName.BBS6, "Branch on Bit Set" }, + { OpName.BBS7, "Branch on Bit Set" }, + { OpName.RMB0, "Reset Memory Bit" }, + { OpName.RMB1, "Reset Memory Bit" }, + { OpName.RMB2, "Reset Memory Bit" }, + { OpName.RMB3, "Reset Memory Bit" }, + { OpName.RMB4, "Reset Memory Bit" }, + { OpName.RMB5, "Reset Memory Bit" }, + { OpName.RMB6, "Reset Memory Bit" }, + { OpName.RMB7, "Reset Memory Bit" }, + { OpName.SMB0, "Set Memory Bit" }, + { OpName.SMB1, "Set Memory Bit" }, + { OpName.SMB2, "Set Memory Bit" }, + { OpName.SMB3, "Set Memory Bit" }, + { OpName.SMB4, "Set Memory Bit" }, + { OpName.SMB5, "Set Memory Bit" }, + { OpName.SMB6, "Set Memory Bit" }, + { OpName.SMB7, "Set Memory Bit" }, }; /// @@ -677,8 +712,54 @@ namespace Asm65 { "Load and Discard. Usually a no-op, but the activity on the address bus " + "can affect memory-mapped I/O." }, + + // + // Rockwell 65C02 extensions. + // + { OpName.BBR0, BBR_DESC }, + { OpName.BBR1, BBR_DESC }, + { OpName.BBR2, BBR_DESC }, + { OpName.BBR3, BBR_DESC }, + { OpName.BBR4, BBR_DESC }, + { OpName.BBR5, BBR_DESC }, + { OpName.BBR6, BBR_DESC }, + { OpName.BBR7, BBR_DESC }, + { OpName.BBS0, BBS_DESC }, + { OpName.BBS1, BBS_DESC }, + { OpName.BBS2, BBS_DESC }, + { OpName.BBS3, BBS_DESC }, + { OpName.BBS4, BBS_DESC }, + { OpName.BBS5, BBS_DESC }, + { OpName.BBS6, BBS_DESC }, + { OpName.BBS7, BBS_DESC }, + { OpName.RMB0, RMB_DESC }, + { OpName.RMB1, RMB_DESC }, + { OpName.RMB2, RMB_DESC }, + { OpName.RMB3, RMB_DESC }, + { OpName.RMB4, RMB_DESC }, + { OpName.RMB5, RMB_DESC }, + { OpName.RMB6, RMB_DESC }, + { OpName.RMB7, RMB_DESC }, + { OpName.SMB0, SMB_DESC }, + { OpName.SMB1, SMB_DESC }, + { OpName.SMB2, SMB_DESC }, + { OpName.SMB3, SMB_DESC }, + { OpName.SMB4, SMB_DESC }, + { OpName.SMB5, SMB_DESC }, + { OpName.SMB6, SMB_DESC }, + { OpName.SMB7, SMB_DESC }, }; + private static string BBR_DESC = + "Branches to a relative address if the specified bit in memory is zero."; + private static string BBS_DESC = + "Branches to a relative address if the specified bit in memory is one."; + private static string RMB_DESC = + "Clears a bit in memory."; + private static string SMB_DESC = + "Sets a bit in memory."; + + /// /// Address mode short descriptions, USA English. /// @@ -702,6 +783,7 @@ namespace Asm65 { { OpDef.AddressMode.DPIndexX, "Direct Page Indexed X" }, { OpDef.AddressMode.DPIndexXInd, "Direct Page Indexed X Indirect" }, { OpDef.AddressMode.DPIndexY, "Direct Page Indexed Y" }, + { OpDef.AddressMode.DPPCRel, "Direct Page / PC Relative" }, { OpDef.AddressMode.Imm, "Immediate" }, { OpDef.AddressMode.ImmLongA, "Immediate" }, { OpDef.AddressMode.ImmLongXY, "Immediate" }, diff --git a/Asm65/OpName.cs b/Asm65/OpName.cs index 7bc7fd0..f06418f 100644 --- a/Asm65/OpName.cs +++ b/Asm65/OpName.cs @@ -21,9 +21,12 @@ namespace Asm65 { /// must be lower-case. /// public static class OpName { - // NOTE: these all happen to be three characters, but I don't think we want to - // guarantee that. On the 65816 some mnemonics are extended (e.g. LDAL for LDA with + // NOTE: these are generally three characters, but the pattern breaks with the Rockwell + // extensions unless we want to show the bit index as a 3rd argument (which some + // assemblers do). On the 65816 some mnemonics are extended (e.g. LDAL for LDA with // a 24-bit operand), but that's assembler-specific and handled elsewhere. + // + // Bottom line: don't assume these will be 3 characters. public const string Unknown = "???"; public const string ADC = "adc"; public const string AND = "and"; @@ -143,5 +146,39 @@ namespace Asm65 { // Undocumented 65C02 instructions. public const string LDD = "ldd"; + + // Rockwell extensions + public const string BBR0 = "bbr0"; + public const string BBR1 = "bbr1"; + public const string BBR2 = "bbr2"; + public const string BBR3 = "bbr3"; + public const string BBR4 = "bbr4"; + public const string BBR5 = "bbr5"; + public const string BBR6 = "bbr6"; + public const string BBR7 = "bbr7"; + public const string BBS0 = "bbs0"; + public const string BBS1 = "bbs1"; + public const string BBS2 = "bbs2"; + public const string BBS3 = "bbs3"; + public const string BBS4 = "bbs4"; + public const string BBS5 = "bbs5"; + public const string BBS6 = "bbs6"; + public const string BBS7 = "bbs7"; + public const string RMB0 = "rmb0"; + public const string RMB1 = "rmb1"; + public const string RMB2 = "rmb2"; + public const string RMB3 = "rmb3"; + public const string RMB4 = "rmb4"; + public const string RMB5 = "rmb5"; + public const string RMB6 = "rmb6"; + public const string RMB7 = "rmb7"; + public const string SMB0 = "smb0"; + public const string SMB1 = "smb1"; + public const string SMB2 = "smb2"; + public const string SMB3 = "smb3"; + public const string SMB4 = "smb4"; + public const string SMB5 = "smb5"; + public const string SMB6 = "smb6"; + public const string SMB7 = "smb7"; } } diff --git a/SourceGen/RuntimeData/Help/settings.html b/SourceGen/RuntimeData/Help/settings.html index d88d877..cb124cc 100644 --- a/SourceGen/RuntimeData/Help/settings.html +++ b/SourceGen/RuntimeData/Help/settings.html @@ -235,17 +235,22 @@ you later hit Cancel, but the changes are not applied immediately.

The choice of CPU determines the set of available instructions, as well as cycle costs and register widths. There are many variations on the 6502, but from the perspective of a disassembler most can be -treated as one of these three:

+treated as one of these four:

  1. MOS 6502. The original 8-bit instruction set.
  2. -
  3. WDC W65C02S. Expanded the instruction set and smoothed +
  4. WDC 65C02. Expanded the instruction set and smoothed some rough edges.
  5. +
  6. WDC W65C02S. An enhanced version of the 65C02, with some + additional instructions introduced by Rockwell (R65C02), as well + as WDC's STP and WAI instructions. The Rockwell additions overlap + with 65816 instructions, so code that uses them will not work on + 16-bit CPUs.
  7. WDC W65C816S. Expanded instruction set, 24-bit address space, and 16-bit registers.
-

The Rockwell R65C02, Hudson Soft HuC6280, and Commodore CSG 4510 / 65CE02 -have instruction sets that expand on the 6502/65C02, but aren't compatible -with the 65816. These are not yet supported by SourceGen.

+

The Hudson Soft HuC6280 and Commodore CSG 4510 / 65CE02 are very +similar, but they have additional instructions and some fundamental +architectural changes. These are not currently supported by SourceGen.

If "enable undocumented instructions" is checked, some additional opcodes are recognized on the 6502 and 65C02. These instructions are diff --git a/SourceGen/Tools/WpfGui/InstructionChart.xaml b/SourceGen/Tools/WpfGui/InstructionChart.xaml index 0e7542e..6527e0b 100644 --- a/SourceGen/Tools/WpfGui/InstructionChart.xaml +++ b/SourceGen/Tools/WpfGui/InstructionChart.xaml @@ -30,7 +30,8 @@ limitations under the License. MOS 6502 - WDC W65C02S + WDC 65C02 + WDC W65C02S WDC W65C816S diff --git a/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs b/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs index f6e5cd5..5f0c652 100644 --- a/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs +++ b/SourceGen/Tools/WpfGui/InstructionChart.xaml.cs @@ -105,6 +105,7 @@ namespace SourceGen.Tools.WpfGui { CpuItems = new CpuItem[] { new CpuItem((string)FindResource("str_6502"), CpuDef.CpuType.Cpu6502), new CpuItem((string)FindResource("str_65C02"), CpuDef.CpuType.Cpu65C02), + new CpuItem((string)FindResource("str_W65C02"), CpuDef.CpuType.CpuW65C02), new CpuItem((string)FindResource("str_65816"), CpuDef.CpuType.Cpu65816), }; } @@ -162,6 +163,8 @@ namespace SourceGen.Tools.WpfGui { string sampleValue = "$12"; if (op.AddrMode == OpDef.AddressMode.BlockMove) { sampleValue = "#$12,#$34"; + } else if (op.AddrMode == OpDef.AddressMode.DPPCRel) { + sampleValue = "$12,$1234"; } else if (opLen == 3) { sampleValue = "$1234"; } else if (opLen == 4) { diff --git a/SourceGen/WpfGui/EditProjectProperties.xaml b/SourceGen/WpfGui/EditProjectProperties.xaml index 083121a..157d703 100644 --- a/SourceGen/WpfGui/EditProjectProperties.xaml +++ b/SourceGen/WpfGui/EditProjectProperties.xaml @@ -38,7 +38,8 @@ limitations under the License. MOS 6502 - WDC W65C02S + WDC 65C02 + WDC W65C02S WDC W65C816S None (disabled) diff --git a/SourceGen/WpfGui/EditProjectProperties.xaml.cs b/SourceGen/WpfGui/EditProjectProperties.xaml.cs index a21e12a..8e13066 100644 --- a/SourceGen/WpfGui/EditProjectProperties.xaml.cs +++ b/SourceGen/WpfGui/EditProjectProperties.xaml.cs @@ -126,6 +126,7 @@ namespace SourceGen.WpfGui { CpuItems = new CpuItem[] { new CpuItem((string)FindResource("str_6502"), CpuDef.CpuType.Cpu6502), new CpuItem((string)FindResource("str_65C02"), CpuDef.CpuType.Cpu65C02), + new CpuItem((string)FindResource("str_W65C02"), CpuDef.CpuType.CpuW65C02), new CpuItem((string)FindResource("str_65816"), CpuDef.CpuType.Cpu65816), }; DefaultTextScanModeItems = new DefaultTextScanMode[] {