mirror of
https://github.com/fadden/6502bench.git
synced 2024-12-26 04:30:52 +00:00
dfd5bcab1b
Early data sheets listed BRK as one byte, but RTI after a BRK skips the following byte, effectively making BRK a 2-byte instruction. Sometimes, such as when diassembling Apple /// SOS code, it's handy to treat it that way explicitly. This change makes two-byte BRKs optional, controlled by a checkbox in the project settings. In the system definitions it defaults to true for Apple ///, false for all others. ACME doesn't allow BRK to have an arg, and cc65 only allows it for 65816 code (?), so it's emitted as a hex blob for those assemblers. Anyone wishing to target those assemblers should stick to 1-byte mode. Extension scripts have to switch between formatting one byte of inline data and formatting an instruction with a one-byte operand. A helper function has been added to the plugin Util class. To get some regression test coverage, 2022-extension-scripts has been configured to use two-byte BRK. Also, added/corrected some SOS constants. See also issue #44.
172 lines
7.1 KiB
C#
172 lines
7.1 KiB
C#
/*
|
|
* Copyright 2019 faddenSoft
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
|
|
using Asm65;
|
|
using TextScanMode = SourceGen.ProjectProperties.AnalysisParameters.TextScanMode;
|
|
|
|
namespace SourceGen {
|
|
/// <summary>
|
|
/// Helper functions for extracting values from a SystemDef instance.
|
|
/// </summary>
|
|
public static class SystemDefaults {
|
|
private const string LOAD_ADDRESS = "load-address";
|
|
private const string ENTRY_FLAGS = "entry-flags";
|
|
private const string UNDOCUMENTED_OPCODES = "undocumented-opcodes";
|
|
private const string TWO_BYTE_BRK = "two-byte-brk";
|
|
private const string FIRST_WORD_IS_LOAD_ADDR = "first-word-is-load-addr";
|
|
private const string DEFAULT_TEXT_ENCODING = "default-text-encoding";
|
|
|
|
private const string ENTRY_FLAG_EMULATION = "emulation";
|
|
private const string ENTRY_FLAG_NATIVE_LONG = "native-long";
|
|
private const string ENTRY_FLAG_NATIVE_SHORT = "native-short";
|
|
|
|
private const string TEXT_ENCODING_C64_PETSCII = "c64-petscii";
|
|
|
|
|
|
/// <summary>
|
|
/// Gets the default load address.
|
|
/// </summary>
|
|
/// <param name="sysDef">SystemDef instance.</param>
|
|
/// <returns>Specified load address, or 0x1000 if nothing defined.</returns>
|
|
public static int GetLoadAddress(SystemDef sysDef) {
|
|
Dictionary<string, string> parms = sysDef.Parameters;
|
|
int retVal = 0x1000;
|
|
|
|
if (parms.TryGetValue(LOAD_ADDRESS, out string valueStr)) {
|
|
valueStr = valueStr.Trim();
|
|
if (Number.TryParseInt(valueStr, out int parseVal, out int unused)) {
|
|
retVal = parseVal;
|
|
} else {
|
|
Debug.WriteLine("WARNING: bad value for " + LOAD_ADDRESS + ": " + valueStr);
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the default entry processor status flags.
|
|
/// </summary>
|
|
/// <param name="sysDef">SystemDef instance.</param>
|
|
/// <returns>Status flags.</returns>
|
|
public static StatusFlags GetEntryFlags(SystemDef sysDef) {
|
|
Dictionary<string, string> parms = sysDef.Parameters;
|
|
StatusFlags retFlags = StatusFlags.AllIndeterminate;
|
|
|
|
// On 65802/65816, this selects emulation mode. On 8-bit CPUs, these have
|
|
// no effect, but this reflects how the CPU behaves (short regs, emu mode).
|
|
retFlags.E = retFlags.M = retFlags.X = 1;
|
|
|
|
// Decimal mode is rarely used, and interrupts are generally enabled. Projects
|
|
// that need to assume otherwise can alter the entry flags. I want to start
|
|
// with decimal mode clear because it affects the cycle timing display on a
|
|
// number of 65C02 instructions.
|
|
retFlags.D = retFlags.I = 0;
|
|
|
|
if (parms.TryGetValue(ENTRY_FLAGS, out string valueStr)) {
|
|
switch (valueStr) {
|
|
case ENTRY_FLAG_EMULATION:
|
|
break;
|
|
case ENTRY_FLAG_NATIVE_LONG:
|
|
retFlags.E = retFlags.M = retFlags.X = 0;
|
|
break;
|
|
case ENTRY_FLAG_NATIVE_SHORT:
|
|
retFlags.E = 0;
|
|
break;
|
|
default:
|
|
Debug.WriteLine("WARNING: bad value for " + ENTRY_FLAGS +
|
|
": " + valueStr);
|
|
break;
|
|
}
|
|
}
|
|
return retFlags;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the default setting for undocumented opcode support.
|
|
/// </summary>
|
|
/// <param name="sysDef">SystemDef instance.</param>
|
|
/// <returns>Enable/disable value.</returns>
|
|
public static bool GetUndocumentedOpcodes(SystemDef sysDef) {
|
|
return GetBoolParam(sysDef, UNDOCUMENTED_OPCODES, false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the default setting for two-byte BRKs.
|
|
/// </summary>
|
|
/// <param name="sysDef">SystemDef instance.</param>
|
|
/// <returns>Enable/disable value.</returns>
|
|
public static bool GetTwoByteBrk(SystemDef sysDef) {
|
|
return GetBoolParam(sysDef, TWO_BYTE_BRK, false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the default setting for using the first two bytes of the file as the
|
|
/// load address.
|
|
///
|
|
/// This is primarily for C64 PRG files. Apple II DOS 3.3 binary files also put the
|
|
/// load address first, followed by the length, but that's typically stripped out when
|
|
/// the file is extracted.
|
|
/// </summary>
|
|
/// <param name="sysDef">SystemDef instance.</param>
|
|
/// <returns>True if the first word holds the load address.</returns>
|
|
public static bool GetFirstWordIsLoadAddr(SystemDef sysDef) {
|
|
return GetBoolParam(sysDef, FIRST_WORD_IS_LOAD_ADDR, false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the default setting for the text scan encoding mode.
|
|
/// </summary>
|
|
/// <param name="sysDef">SystemDef instance.</param>
|
|
/// <returns>Preferred text scan mode.</returns>
|
|
public static TextScanMode GetTextScanMode(SystemDef sysDef) {
|
|
Dictionary<string, string> parms = sysDef.Parameters;
|
|
TextScanMode mode = TextScanMode.LowHighAscii;
|
|
|
|
if (parms.TryGetValue(DEFAULT_TEXT_ENCODING, out string valueStr)) {
|
|
if (valueStr == TEXT_ENCODING_C64_PETSCII) {
|
|
mode = TextScanMode.C64Petscii;
|
|
}
|
|
}
|
|
return mode;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Looks for a parameter with a matching name and a boolean value.
|
|
/// </summary>
|
|
/// <param name="sysDef">SystemDef reference.</param>
|
|
/// <param name="paramName">Name of parameter to look for.</param>
|
|
/// <param name="defVal">Default value.</param>
|
|
/// <returns>Parsed value, or defVal if the parameter doesn't exist or the value is not
|
|
/// a boolean string.</returns>
|
|
private static bool GetBoolParam(SystemDef sysDef, string paramName, bool defVal) {
|
|
Dictionary<string, string> parms = sysDef.Parameters;
|
|
bool retVal = defVal;
|
|
|
|
if (parms.TryGetValue(paramName, out string valueStr)) {
|
|
if (bool.TryParse(valueStr, out bool parseVal)) {
|
|
retVal = parseVal;
|
|
} else {
|
|
Debug.WriteLine("WARNING: bad value for " + paramName + ": " + valueStr);
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
}
|
|
}
|