From a6700e9062a87bf4ab6d2712f0aaa0bf9feff1ad Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Fri, 3 Jul 2020 18:58:20 -0700 Subject: [PATCH] Format GS/OS parameter blocks Similar to the ProDOS 8 formatter, but slightly more complex due to the variable-length parameter block layout. Also, added Orca shell call numbers to the list of constants. --- SourceGen/RuntimeData/Apple/GSOS.cs | 274 ++++++++++++++++++++++++- SourceGen/RuntimeData/Apple/GSOS.sym65 | 64 +++++- 2 files changed, 335 insertions(+), 3 deletions(-) diff --git a/SourceGen/RuntimeData/Apple/GSOS.cs b/SourceGen/RuntimeData/Apple/GSOS.cs index ffa34e8..1cb9459 100644 --- a/SourceGen/RuntimeData/Apple/GSOS.cs +++ b/SourceGen/RuntimeData/Apple/GSOS.cs @@ -38,9 +38,215 @@ namespace RuntimeData.Apple { private const string GSOS_FUNC_TAG = "AppleIIgs-GSOS-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, 2); + private static Param REF_NUM = new Param(DataType.NumericLE, DataSubType.Decimal, 2); + private static Param DEV_NUM = new Param(DataType.NumericLE, DataSubType.Decimal, 2); + private static Param PATHNAME = new Param(DataType.NumericLE, DataSubType.Address, 4); + private static Param BUFFER = new Param(DataType.NumericLE, DataSubType.Address, 4); + private static Param PROC_POINTER = new Param(DataType.NumericLE, DataSubType.Address, 4); + private static Param ACCESS = new Param(DataType.NumericLE, DataSubType.Hex, 2); + private static Param FILE_TYPE = new Param(DataType.NumericLE, DataSubType.Hex, 2); + private static Param AUX_TYPE = new Param(DataType.NumericLE, DataSubType.Hex, 4); + private static Param STORAGE_TYPE = new Param(DataType.NumericLE, DataSubType.Hex, 2); + private static Param FILE_OFFSET = new Param(DataType.NumericLE, DataSubType.Hex, 4); + private static Param DATE_TIME = new Param(DataType.Dense, DataSubType.None, 8); + private static Param MISC2 = new Param(DataType.NumericLE, DataSubType.Hex, 2); + private static Param MISC4 = new Param(DataType.NumericLE, DataSubType.Hex, 4); + private static Param RESULT2 = new Param(DataType.NumericLE, DataSubType.Hex, 2); + private static Param RESULT4 = new Param(DataType.NumericLE, DataSubType.Hex, 4); + + private Dictionary ParamDescrs = new Dictionary() { + { 0x2034, // AddNotifyProcGS + new Param[] { PARAM_COUNT, PROC_POINTER } + }, + { 0x201d, // BeginSessionGS + new Param[] { PARAM_COUNT } + }, + { 0x2031, // BindIntGS + new Param[] { PARAM_COUNT, RESULT2, MISC2, MISC4 } + }, + { 0x2004, // ChangePathGS + new Param[] { PARAM_COUNT, PATHNAME, PATHNAME } + }, + { 0x200b, // ClearBackupBitGS + new Param[] { PARAM_COUNT, PATHNAME } + }, + { 0x2014, // CloseGS + new Param[] { PARAM_COUNT, REF_NUM } + }, + { 0x2001, // CreateGS + new Param[] { PARAM_COUNT, PATHNAME, ACCESS, FILE_TYPE, AUX_TYPE, + STORAGE_TYPE, FILE_OFFSET, FILE_OFFSET } + }, + { 0x202e, // DControlGS (has a bunch of sub-calls) + new Param[] { PARAM_COUNT, DEV_NUM, MISC2, BUFFER, PARAM_COUNT, RESULT4 } + }, + { 0x2035, // DelNotifyProcGS + new Param[] { PARAM_COUNT, PROC_POINTER } + }, + { 0x2002, // DestroyGS + new Param[] { PARAM_COUNT, PATHNAME } + }, + { 0x202c, // DInfoGS + new Param[] { PARAM_COUNT, DEV_NUM, PATHNAME, MISC2, MISC4, MISC2, MISC2, + MISC2, MISC2, MISC2, MISC2, BUFFER } + }, + { 0x202f, // DReadGS + new Param[] { PARAM_COUNT, DEV_NUM, BUFFER, MISC4, MISC4, MISC2, MISC4 } + }, + { 0x2036, // DRenameGS + new Param[] { PARAM_COUNT, DEV_NUM, PATHNAME } + }, + { 0x202d, // DStatus (has a bunch of sub-calls) + new Param[] { PARAM_COUNT, DEV_NUM, MISC2, BUFFER, MISC4, MISC4 } + }, + { 0x2030, // DWriteGS + new Param[] { PARAM_COUNT, DEV_NUM, BUFFER, MISC4, MISC4, MISC2, MISC4 } + }, + { 0x201e, // EndSessionGS + new Param[] { PARAM_COUNT } + }, + { 0x2025, // EraseDiskGS + new Param[] { PARAM_COUNT, PATHNAME, PATHNAME, MISC2, MISC2 } + }, + { 0x200e, // ExpandPathGS + new Param[] { PARAM_COUNT, PATHNAME, PATHNAME, MISC2 } + }, + { 0x2015, // FlushGS + new Param[] { PARAM_COUNT, REF_NUM } + }, + { 0x2024, // FormatGS + new Param[] { PARAM_COUNT, PATHNAME, PATHNAME, MISC2, MISC2 } + }, + { 0x2033, // FSTSpecific + new Param[] { PARAM_COUNT, MISC2, MISC2 /*...*/ } + }, + { 0x2028, // GetBootVolGS + new Param[] { PARAM_COUNT, BUFFER } + }, + { 0x2020, // GetDevNumberGS + new Param[] { PARAM_COUNT, PATHNAME, DEV_NUM } + }, + { 0x201c, // GetDirEntryGS + new Param[] { PARAM_COUNT, REF_NUM, MISC2, MISC2, MISC2, PATHNAME, MISC2, + FILE_TYPE, FILE_OFFSET, MISC4, DATE_TIME, DATE_TIME, ACCESS, AUX_TYPE, MISC2, + BUFFER, FILE_OFFSET, MISC4 } + }, + { 0x2019, // GetEOFGS + new Param[] { PARAM_COUNT, REF_NUM, FILE_OFFSET } + }, + { 0x2006, // GetFileInfoGS + new Param[] { PARAM_COUNT, PATHNAME, ACCESS, FILE_TYPE, AUX_TYPE, STORAGE_TYPE, + DATE_TIME, DATE_TIME, BUFFER, FILE_OFFSET, MISC4, FILE_OFFSET, MISC4 } + }, + { 0x202b, // GetFSTInfoGS + new Param[] { PARAM_COUNT, MISC2, MISC2, PATHNAME, MISC2, MISC2, MISC2, + MISC4, MISC4} + }, + { 0x201b, // GetLevelGS + new Param[] { PARAM_COUNT, MISC2 } + }, + { 0x2017, // GetMarkGS + new Param[] { PARAM_COUNT, REF_NUM, FILE_OFFSET } + }, + { 0x2027, // GetNameGS + new Param[] { PARAM_COUNT, BUFFER } + }, + { 0x200a, // GetPrefixGS + new Param[] { PARAM_COUNT, MISC2, PATHNAME } + }, + { 0x2039, // GetRefInfoGS + new Param[] { PARAM_COUNT, REF_NUM, ACCESS, PATHNAME } + }, + { 0x2038, // GetRefNumGS + new Param[] { PARAM_COUNT, PATHNAME, REF_NUM, ACCESS, MISC2, MISC2, MISC2 } + }, + { 0x2037, // GetStdRefNumGS + new Param[] { PARAM_COUNT, MISC2, REF_NUM } + }, + { 0x200f, // GetSysPrefsGS + new Param[] { PARAM_COUNT, MISC2 } + }, + { 0x202a, // GetVersionGS + new Param[] { PARAM_COUNT, MISC2 } + }, + { 0x2011, // NewLine + new Param[] { PARAM_COUNT, REF_NUM, MISC2, MISC2, BUFFER } + }, + { 0x200d, // NullGS + new Param[] { PARAM_COUNT } + }, + { 0x2010, // OpenGS + new Param[] { PARAM_COUNT, REF_NUM, PATHNAME, ACCESS, MISC2, ACCESS, FILE_TYPE, + AUX_TYPE, STORAGE_TYPE, DATE_TIME, DATE_TIME, BUFFER, FILE_OFFSET, MISC4, + FILE_OFFSET, MISC4 } + }, + { 0x2003, // OSShutdownGS + new Param[] { PARAM_COUNT, MISC2 } + }, + { 0x2029, // QuitGS + new Param[] { PARAM_COUNT, PATHNAME, MISC2 } + }, + { 0x2012, // ReadGS + new Param[] { PARAM_COUNT, REF_NUM, BUFFER, MISC4, MISC4, MISC2 } + }, + { 0x2026, // ResetCacheGS + new Param[] { PARAM_COUNT } + }, + { 0x201f, // SessionStatusGS + new Param[] { PARAM_COUNT, MISC2 } + }, + { 0x2018, // SetEOFGS + new Param[] { PARAM_COUNT, REF_NUM, MISC2, FILE_OFFSET } + }, + { 0x2005, // SetFileInfoGS + new Param[] { PARAM_COUNT, PATHNAME, ACCESS, FILE_TYPE, AUX_TYPE, MISC2, + DATE_TIME, DATE_TIME, BUFFER, MISC4, MISC4, MISC4, MISC4 } + }, + { 0x201a, // SetLevelGS + new Param[] { PARAM_COUNT, MISC2 } + }, + { 0x2016, // SetMarkGS + new Param[] { PARAM_COUNT, REF_NUM, MISC2, FILE_OFFSET } + }, + { 0x2009, // SetPrefixGS + new Param[] { PARAM_COUNT, MISC2, PATHNAME } + }, + { 0x200c, // SetSysPrefsGS + new Param[] { PARAM_COUNT, MISC2 } + }, + { 0x2032, // UnbindIntGS + new Param[] { PARAM_COUNT, MISC2 } + }, + { 0x2008, // VolumeGS + new Param[] { PARAM_COUNT, PATHNAME, PATHNAME, MISC4, MISC4, MISC2, MISC2 } + }, + { 0x2013, // WriteGS + new Param[] { PARAM_COUNT, REF_NUM, BUFFER, MISC4, MISC4, MISC2 } + }, + + // TODO: ProDOS 16 calls + }; + + #endregion Parameter block defs + private IApplication mAppRef; private byte[] mFileData; private Dictionary mFunctionList; + private AddressTranslate mAddrTrans; public string Identifier { get { @@ -51,6 +257,7 @@ namespace RuntimeData.Apple { public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) { mAppRef = appRef; mFileData = fileData; + mAddrTrans = addrTrans; mAppRef.DebugLog("GSOS(id=" + AppDomain.CurrentDomain.Id + "): prepare()"); //System.Diagnostics.Debugger.Break(); @@ -59,6 +266,7 @@ namespace RuntimeData.Apple { public void Unprepare() { mAppRef = null; mFileData = null; + mAddrTrans = null; } public void UpdateSymbolList(List plSyms) { @@ -77,10 +285,10 @@ namespace RuntimeData.Apple { // match! int req = Util.GetWord(mFileData, offset + 4, 2, false); + int blockAddr = Util.GetWord(mFileData, offset + 6, 4, false); if (VERBOSE) { - int addr = Util.GetWord(mFileData, offset + 6, 4, false); mAppRef.DebugLog("GSOS call detected at +" + offset.ToString("x6") + - ", cmd=$" + req.ToString("x4") + " addr=$" + addr.ToString("x6")); + ", cmd=$" + req.ToString("x4") + " addr=$" + blockAddr.ToString("x6")); } PlSymbol sym; @@ -93,6 +301,68 @@ namespace RuntimeData.Apple { } mAppRef.SetInlineDataFormat(offset + 6, 4, DataType.NumericLE, DataSubType.Address, null); + + FormatParameterBlock(offset, req, blockAddr); + + // Try to format parameter block. + if (req == 0x2029) { // QuitGS call + noContinue = true; + } + + } + } + + /// + /// Attempts to format the parameter block that is passed into the GS/OS call. + /// + /// + /// All "class 1" GS/OS calls have a parameter block that begins with a parameter + /// count. The count indicates how many parameters are provided after the pCount + /// field. This is a field count, not a byte count, and may be zero. + /// + private void FormatParameterBlock(int offset, int req, int blockAddr) { + Param[] parms; + if (!ParamDescrs.TryGetValue(req, out parms)) { + // We don't have a parameter list for this call. + return; + } + + // Confirm we can at least get the parameter count. + int blockOff = mAddrTrans.AddressToOffset(offset, blockAddr); + if (!Util.IsInBounds(mFileData, blockOff, 2)) { + return; + } + int pCount = Util.GetWord(mFileData, blockOff, 2, false); + if (pCount >= parms.Length) { + // Might be uninitialized data. Whatever the case, it's not something we + // can deal with. + return; + } + + int paramCount = pCount + 1; // add 1 for pCount itself + + // Compute parameter block length in bytes. + int blockLen = 0; + for (int i = 0; i < paramCount; i++) { + blockLen += parms[i].Length; + } + + // Confirm that the entire thing fits in the file. + if (!Util.IsInBounds(mFileData, blockOff, blockLen)) { + return; + } + + if (VERBOSE) { + mAppRef.DebugLog("Formatting GS/OS call block at +" + blockOff.ToString("x6") + + ", count=" + paramCount); + } + + // Format each entry. + for (int i = 0; i < paramCount; i++) { + Param parm = parms[i]; + mAppRef.SetInlineDataFormat(blockOff, parm.Length, parm.Type, + parm.SubType, null); + blockOff += parm.Length; } } } diff --git a/SourceGen/RuntimeData/Apple/GSOS.sym65 b/SourceGen/RuntimeData/Apple/GSOS.sym65 index 73e2f27..e7ae4b8 100644 --- a/SourceGen/RuntimeData/Apple/GSOS.sym65 +++ b/SourceGen/RuntimeData/Apple/GSOS.sym65 @@ -1,7 +1,7 @@ ; Copyright 2018 faddenSoft. All Rights Reserved. ; See the LICENSE.txt file for distribution terms (Apache 2.0). ; -; Source: GS/OS Reference Manual +; Source: GS/OS Reference Manual and Orca/M 2.0 assembler manual. *SYNOPSIS GS/OS public addresses and constants. @@ -103,3 +103,65 @@ SetSysPrefsGS = $200C UnbindIntGS = $2032 VolumeGS = $2008 WriteGS = $2013 + +; Orca shell calls. These are used just like GS/OS calls. See chapter 24 +; in the Orca/M 2.0 manual and M16.Shell. +OSH_ChangeVector = $010C +OSH_ConsoleOut = $011A +OSH_Direction = $010F +OSH_Error = $0105 +OSH_Execute = $010D +OSH_ExpandDevices = $0114 +OSH_Export = $0116 +OSH_FastFile = $010E +OSH_GetCommand = $011D +OSH_GetIODevices = $011C +OSH_GetLang = $0103 +OSH_GetLInfo = $0101 +OSH_InitWildcard = $0109 +OSH_Keypress = $011E +OSH_NextWildcard = $010A +OSH_PopVariables = $0117 +OSH_PushVariables = $0118 +OSH_ReadIndexed = $0108 +OSH_ReadKey = $011f +OSH_ReadVariable = $010B +OSH_Redirect = $0110 +OSH_Set = $0106 +OSH_SetIODevices = $011B +OSH_SetLang = $0104 +OSH_SetLInfo = $0102 +OSH_SetStopFlag = $0119 +OSH_Stop = $0113 +OSH_UnsetVariable = $0115 +OSH_Version = $0107 + +OSH_ChangeVectorGS = $014C +OSH_ConsoleOutGS = $015A +OSH_DirectionGS = $014F +OSH_ErrorGS = $0145 +OSH_ExecuteGS = $014D +OSH_ExpandDevicesGS = $0154 +OSH_ExportGS = $0156 +OSH_FastFileGS = $014E +OSH_GetCommandGS = $015D +OSH_GetIODevicesGS = $015C +OSH_GetLangGS = $0143 +OSH_GetLInfoGS = $0141 +OSH_InitWildcardGS = $0149 +OSH_KeypressGS = $015E +OSH_NextWildcardGS = $014A +OSH_PopVariablesGS = $0157 +OSH_PushVariablesGS = $0158 +OSH_ReadIndexedGS = $0148 +OSH_ReadKeyGS = $015f +OSH_ReadVariableGS = $014B +OSH_RedirectGS = $0150 +OSH_SetGS = $0146 +OSH_SetIODevicesGS = $015B +OSH_SetLangGS = $0144 +OSH_SetLInfoGS = $0142 +OSH_SetStopFlagGS = $0159 +OSH_StopGS = $0153 +OSH_UnsetVariableGS = $0155 +OSH_VersionGS = $0147