mirror of
https://github.com/fadden/6502bench.git
synced 2024-08-14 18:28:57 +00:00
- Added SOS parameter block formatting. - Normalized SOS call names to values in SOS Reference Manual. - Added SOS call error code constants. - (from robjustice) Added more to A3-IO.sym65. Also, rearranged the ProDOS code slightly. (issue #85)
253 lines
10 KiB
C#
253 lines
10 KiB
C#
/*
|
|
* Copyright 2018 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 PluginCommon;
|
|
|
|
/*
|
|
JSR $BF00
|
|
DFB command_code
|
|
DW parm_block
|
|
|
|
parm_block
|
|
dfb parm_count
|
|
parameters...
|
|
*/
|
|
|
|
namespace RuntimeData.Apple {
|
|
/// <summary>
|
|
/// Identify and format ProDOS-8 system calls.
|
|
/// </summary>
|
|
public class ProDOS8 : MarshalByRefObject, IPlugin, IPlugin_SymbolList, IPlugin_InlineJsr {
|
|
private const string P8_MLI_TAG = "ProDOS8-MLI-Functions"; // tag used in .sym65 file
|
|
private bool VERBOSE = false;
|
|
|
|
#region Parameter block defs
|
|
|
|
private class Param {
|
|
public DataType Type { get; private set; }
|
|
public DataSubType SubType { get; private set; }
|
|
public int Length { get; private set; }
|
|
|
|
public Param(DataType type, DataSubType subType, int length) {
|
|
Type = type;
|
|
SubType = subType;
|
|
Length = length;
|
|
}
|
|
}
|
|
private static Param PARAM_COUNT = new Param(DataType.NumericLE, DataSubType.Decimal, 1);
|
|
private static Param PATHNAME = new Param(DataType.NumericLE, DataSubType.Address, 2);
|
|
private static Param BUFFER = new Param(DataType.NumericLE, DataSubType.Address, 2);
|
|
private static Param CODEPTR = new Param(DataType.NumericLE, DataSubType.Address, 2);
|
|
private static Param ACCESS = new Param(DataType.NumericLE, DataSubType.Hex, 1);
|
|
private static Param FILE_TYPE = new Param(DataType.NumericLE, DataSubType.Hex, 1);
|
|
private static Param AUX_TYPE = new Param(DataType.NumericLE, DataSubType.Hex, 2);
|
|
private static Param STORAGE_TYPE = new Param(DataType.NumericLE, DataSubType.Hex, 1);
|
|
private static Param DATE = new Param(DataType.NumericLE, DataSubType.Hex, 2);
|
|
private static Param TIME = new Param(DataType.NumericLE, DataSubType.Hex, 2);
|
|
private static Param BLOCKS_USED = new Param(DataType.NumericLE, DataSubType.Hex, 2);
|
|
private static Param UNIT_NUM = new Param(DataType.NumericLE, DataSubType.Hex, 1);
|
|
private static Param REF_NUM = new Param(DataType.NumericLE, DataSubType.Decimal, 1);
|
|
private static Param COUNT = new Param(DataType.NumericLE, DataSubType.Hex, 2);
|
|
private static Param BLOCK_NUM = new Param(DataType.NumericLE, DataSubType.Hex, 2);
|
|
private static Param POSITION = new Param(DataType.NumericLE, DataSubType.Hex, 3);
|
|
private static Param MISC1 = new Param(DataType.NumericLE, DataSubType.Hex, 1);
|
|
private static Param MISC2 = new Param(DataType.NumericLE, DataSubType.Hex, 2);
|
|
private static Param NULL3 = new Param(DataType.NumericLE, DataSubType.Hex, 3);
|
|
|
|
private Dictionary<int, Param[]> mParamDescrs = new Dictionary<int, Param[]>() {
|
|
{ 0x40, // ALLOC_INTERRUPT
|
|
new Param[] { PARAM_COUNT, MISC1, CODEPTR }
|
|
},
|
|
{ 0x41, // DEALLOC_INTERRUPT
|
|
new Param[] { PARAM_COUNT, MISC1 }
|
|
},
|
|
{ 0x65, // QUIT
|
|
new Param[] { PARAM_COUNT, MISC1, MISC2, MISC1, MISC2 }
|
|
},
|
|
{ 0x80, // READ_BLOCK
|
|
new Param[] { PARAM_COUNT, UNIT_NUM, BUFFER, BLOCK_NUM }
|
|
},
|
|
{ 0x81, // WRITE_BLOCK
|
|
new Param[] { PARAM_COUNT, UNIT_NUM, BUFFER, BLOCK_NUM }
|
|
},
|
|
// 0x82 GET_TIME has no parameter list
|
|
{ 0xc0, // CREATE
|
|
new Param[] { PARAM_COUNT, PATHNAME, ACCESS, FILE_TYPE, AUX_TYPE, STORAGE_TYPE,
|
|
DATE, TIME }
|
|
},
|
|
{ 0xc1, // DESTROY
|
|
new Param[] { PARAM_COUNT, PATHNAME }
|
|
},
|
|
{ 0xc2, // RENAME
|
|
new Param[] { PARAM_COUNT, PATHNAME, PATHNAME }
|
|
},
|
|
{ 0xc3, // SET_FILE_INFO
|
|
new Param[] { PARAM_COUNT, PATHNAME, ACCESS, FILE_TYPE, AUX_TYPE, NULL3,
|
|
DATE, TIME }
|
|
},
|
|
{ 0xc4, // GET_FILE_INFO
|
|
new Param[] { PARAM_COUNT, PATHNAME, ACCESS, FILE_TYPE, AUX_TYPE, STORAGE_TYPE,
|
|
BLOCKS_USED, DATE, TIME, DATE, TIME }
|
|
},
|
|
{ 0xc5, // ON_LINE
|
|
new Param[] { PARAM_COUNT, UNIT_NUM, BUFFER }
|
|
},
|
|
{ 0xc6, // SET_PREFIX
|
|
new Param[] { PARAM_COUNT, PATHNAME }
|
|
},
|
|
{ 0xc7, // GET_PREFIX
|
|
new Param[] { PARAM_COUNT, PATHNAME }
|
|
},
|
|
{ 0xc8, // OPEN
|
|
new Param[] { PARAM_COUNT, PATHNAME, BUFFER, REF_NUM }
|
|
},
|
|
{ 0xc9, // NEWLINE
|
|
new Param[] { PARAM_COUNT, REF_NUM, MISC1, MISC1 }
|
|
},
|
|
{ 0xca, // READ
|
|
new Param[] { PARAM_COUNT, REF_NUM, BUFFER, COUNT, COUNT }
|
|
},
|
|
{ 0xcb, // WRITE
|
|
new Param[] { PARAM_COUNT, REF_NUM, BUFFER, COUNT, COUNT }
|
|
},
|
|
{ 0xcc, // CLOSE
|
|
new Param[] { PARAM_COUNT, REF_NUM }
|
|
},
|
|
{ 0xcd, // FLUSH
|
|
new Param[] { PARAM_COUNT, REF_NUM }
|
|
},
|
|
{ 0xce, // SET_MARK
|
|
new Param[] { PARAM_COUNT, REF_NUM, POSITION }
|
|
},
|
|
{ 0xcf, // GET_MARK
|
|
new Param[] { PARAM_COUNT, REF_NUM, POSITION }
|
|
},
|
|
{ 0xd0, // SET_EOF
|
|
new Param[] { PARAM_COUNT, REF_NUM, POSITION }
|
|
},
|
|
{ 0xd1, // GET_EOF
|
|
new Param[] { PARAM_COUNT, REF_NUM, POSITION }
|
|
},
|
|
{ 0xd2, // SET_BUF
|
|
new Param[] { PARAM_COUNT, REF_NUM, BUFFER }
|
|
},
|
|
{ 0xd3, // GET_BUF
|
|
new Param[] { PARAM_COUNT, REF_NUM, BUFFER }
|
|
},
|
|
};
|
|
|
|
#endregion Parameter block defs
|
|
|
|
private IApplication mAppRef;
|
|
private byte[] mFileData;
|
|
private Dictionary<int, PlSymbol> mFunctionList;
|
|
private AddressTranslate mAddrTrans;
|
|
|
|
public string Identifier {
|
|
get { return "Apple II ProDOS 8 MLI call handler"; }
|
|
}
|
|
|
|
public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
|
|
mAppRef = appRef;
|
|
mFileData = fileData;
|
|
mAddrTrans = addrTrans;
|
|
|
|
mAppRef.DebugLog("ProDOS(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
|
|
//System.Diagnostics.Debugger.Break();
|
|
}
|
|
|
|
public void Unprepare() {
|
|
mAppRef = null;
|
|
mFileData = null;
|
|
mAddrTrans = null;
|
|
}
|
|
|
|
public void UpdateSymbolList(List<PlSymbol> plSyms) {
|
|
// Extract the list of function name constants from the platform symbol file.
|
|
mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, P8_MLI_TAG, mAppRef);
|
|
}
|
|
public bool IsLabelSignificant(string beforeLabel, string afterLabel) {
|
|
return false;
|
|
}
|
|
|
|
public void CheckJsr(int offset, int operand, out bool noContinue) {
|
|
const int MLI_ENTRY = 0xbf00;
|
|
|
|
noContinue = false;
|
|
if (offset + 6 < mFileData.Length && operand == MLI_ENTRY) {
|
|
// match!
|
|
|
|
byte req = mFileData[offset + 3];
|
|
if (VERBOSE) {
|
|
int blockAddr = Util.GetWord(mFileData, offset + 4, 2, false);
|
|
mAppRef.DebugLog("P8 MLI call detected at +" + offset.ToString("x6") +
|
|
", cmd=$" + req.ToString("x2") + " addr=$" + blockAddr.ToString("x4"));
|
|
}
|
|
|
|
PlSymbol sym;
|
|
if (mFunctionList.TryGetValue(req, out sym)) {
|
|
mAppRef.SetInlineDataFormat(offset + 3, 1, DataType.NumericLE,
|
|
DataSubType.Symbol, sym.Label);
|
|
} else {
|
|
mAppRef.SetInlineDataFormat(offset + 3, 1, DataType.NumericLE,
|
|
DataSubType.None, null);
|
|
}
|
|
mAppRef.SetInlineDataFormat(offset + 4, 2, DataType.NumericLE,
|
|
DataSubType.Address, null);
|
|
|
|
Param[] parms;
|
|
if (mParamDescrs.TryGetValue(req, out parms)) {
|
|
FormatParameterBlock(offset, parms);
|
|
}
|
|
|
|
if (req == 0x65) { // QUIT call
|
|
noContinue = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void FormatParameterBlock(int offset, Param[] parms) {
|
|
int blockAddr = Util.GetWord(mFileData, offset + 4, 2, false);
|
|
|
|
// Try to format the parameter block. Start by figuring out how long it is.
|
|
int blockLen = 0;
|
|
foreach (Param parm in parms) {
|
|
blockLen += parm.Length;
|
|
}
|
|
|
|
// Locate it and verify that the entire thing fits in the file.
|
|
int blockOff = mAddrTrans.AddressToOffset(offset, blockAddr);
|
|
if (Util.IsInBounds(mFileData, blockOff, blockLen)) {
|
|
if (VERBOSE) {
|
|
mAppRef.DebugLog("Formatting P8 block at +" + blockOff.ToString("x6"));
|
|
}
|
|
|
|
foreach (Param parm in parms) {
|
|
// We could try to dereference pathname buffers to see if it's a
|
|
// fixed value and not an empty buffer, but it's hard for us to
|
|
// reliably tell the difference between a length-limited pathname
|
|
// and junk. If the length byte is bad, we run the risk of lumping
|
|
// a bunch of stuff into the pathname buffer.
|
|
mAppRef.SetInlineDataFormat(blockOff, parm.Length, parm.Type,
|
|
parm.SubType, null);
|
|
blockOff += parm.Length;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|