diff --git a/SourceGen/RuntimeData/Apple/ProDOS8.cs b/SourceGen/RuntimeData/Apple/ProDOS8.cs index 9d0ad33..806f0e0 100644 --- a/SourceGen/RuntimeData/Apple/ProDOS8.cs +++ b/SourceGen/RuntimeData/Apple/ProDOS8.cs @@ -33,9 +33,127 @@ namespace RuntimeData.Apple { 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 ParamDescrs = new Dictionary() { + { 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 mFunctionList; + private AddressTranslate mAddrTrans; public string Identifier { get { @@ -47,10 +165,12 @@ namespace RuntimeData.Apple { List plSyms) { mAppRef = appRef; mFileData = fileData; + mAddrTrans = addrTrans; mAppRef.DebugLog("ProDOS(id=" + AppDomain.CurrentDomain.Id + "): prepare()"); //System.Diagnostics.Debugger.Break(); + // Extract the list of function name constants from the platform symbol file. mFunctionList = PlSymbol.GeneratePlatformValueList(plSyms, P8_MLI_TAG, appRef); } @@ -61,10 +181,10 @@ namespace RuntimeData.Apple { // match! byte req = mFileData[offset + 3]; + int blockAddr = Util.GetWord(mFileData, offset + 4, 2, false); if (VERBOSE) { - int addr = Util.GetWord(mFileData, offset + 4, 2, false); mAppRef.DebugLog("P8 MLI call detected at +" + offset.ToString("x6") + - ", cmd=$" + req.ToString("x2") + " addr=$" + addr.ToString("x4")); + ", cmd=$" + req.ToString("x2") + " addr=$" + blockAddr.ToString("x4")); } PlSymbol sym; @@ -78,6 +198,34 @@ namespace RuntimeData.Apple { mAppRef.SetInlineDataFormat(offset + 4, 2, DataType.NumericLE, DataSubType.Address, null); + Param[] parms; + if (ParamDescrs.TryGetValue(req, out parms)) { + // 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; + } + } + } + if (req == 0x65) { // QUIT call noContinue = true; } diff --git a/SourceGen/Tools/WpfGui/ShowText.xaml b/SourceGen/Tools/WpfGui/ShowText.xaml index d92cfd4..04dbcb5 100644 --- a/SourceGen/Tools/WpfGui/ShowText.xaml +++ b/SourceGen/Tools/WpfGui/ShowText.xaml @@ -26,7 +26,8 @@ limitations under the License. ShowInTaskbar="False" WindowStartupLocation="CenterOwner" PreviewKeyDown="Window_KeyEventHandler"> -