1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-12 08:29:29 +00:00

Update Apple /// SOS definitions

- 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)
This commit is contained in:
Andy McFadden 2020-08-22 13:56:57 -07:00
parent 2ec2917da5
commit 53857089e9
4 changed files with 548 additions and 63 deletions

View File

@ -6,12 +6,32 @@
*SYNOPSIS Symbols from hardware I/O areas
KBD @ $C000 ;last key pressed
KBDFLG @ $C008 ;
KBD @ $C000 ;last key pressed (KA Data)
KBDBFLG @ $C008 ;KB data
KBDSTRB @ $C010 ;RW keyboard strobe
SPKR @ $C030 ;RW toggle speaker (Apple II type)
SPKRIII @ $C040 ;RW beeps speaker (Apple /// type)
JOYRDY @ $C066 ;
CLRTEXTGR @ $C050 ;Clear TEXT/GR mode
SETTEXTGR @ $C051 ;Set TEXT/GR mode
CLRMIX @ $C052 ;Clear MIX mode
SETMIX @ $C053 ;Set MIX mode
CLRPAGE2 @ $C054 ;Clear PAGE2 mode
SETPAGE2 @ $C055 ;Set PAGE2 mode
CLRHIRES @ $C056 ;Clear HIRES mode
SETHIRES @ $C057 ;Set HIRES mode
CLRPDL0 @ $C058 ;Clear PDL0 (A/D Addr 0)
SETPDL0 @ $C059 ;Set PDL0 (A/D Addr 0)
CLRPDL2 @ $C05A ;Clear PDL2 (A/D Addr 2)
SETPDL2 @ $C05B ;Set PDL2 (A/D Addr 2)
CLRPDLEN @ $C05C ;Clear PDLEN (A/D Ramp Start)
SETPDLEN @ $C05D ;Set PDLEN (A/D Ramp Start)
CLRPDL1 @ $C05E ;Clear PDL1 (A/D Addr 1)
SETPDL1 @ $C05F ;Set PDL1 (A/D Addr 1)
READSW0 @ $C060 ;Read SW0
READSW1 @ $C061 ;Read SW1/MGNSW
READSW2 @ $C062 ;Read SW2
READSW3 @ $C063 ;Read SW3/SCO
JOYRDY @ $C066 ;Read PDLOT (A/D Ramp Stop)
CLOCK @ $C070 ;clock
PHASOFF @ $C080 ;
PHASON @ $C081 ;
@ -22,24 +42,53 @@ DRV1EN @ $C08B ;
Q6L @ $C08C ;
Q6H @ $C08D ;
Q7L @ $C08E ;
ACIASTAT @ $C0F1 ;status of ACIA
CLRDSA0 @ $C0D0 ;Clear Drive Select A0
SETDSA0 @ $C0D1 ;Set Drive Select A0
CLRDSA1 @ $C0D2 ;Clear Drive Select A1
SETDSA1 @ $C0D3 ;Set Drive Select A1
CLREN1INT @ $C0D4 ;
SETEN1INT @ $C0D5 ;
CLRSIDE2 @ $C0D6 ;
SETSIDE2 @ $C0D7 ;
CLRSCR @ $C0D8 ;Clear Smooth Scroll (to turn smooth scroll off)
SETSCR @ $C0D9 ;Set Smooth Scroll (to turn smooth scroll on)
CLRENCWRT @ $C0DA ;Clear Char Set writing
SETENCWRT @ $C0DB ;Set Char Set writing
CLRENSEL @ $C0DC ;Clear enable silentype port (ENSEL)
SETENSEL @ $C0DD ;Set enable silentype port (ENSEL)
CLRENSIO @ $C0DE ;Clear enable silentype port (ENSIO)
SETENSIO @ $C0DF ;Set enable silentype port (ENSIO)
ACIADATA @ $C0F0 ;ACIA DATA REGISTER
ACIASTAT @ $C0F1 ;ACIA STATUS REGISTER
ACIACMD @ $C0F2 ;ACIA COMMAND REGISTER
ACIACTL @ $C0F3 ;ACIA CONTROL REGISTER
; Other hardware registers
Z_REG @ $FFD0 ;zero page register
D_DDRB @ $FFD2 ;data direction register B
D_DDRA @ $FFD3 ;data direction register A
TIMER1L @ $FFD8
TIMLATCH @ $FFD9
D_ACR @ $FFDB
D_PCR @ $FFDC
D_IFR @ $FFDD
D_IER @ $FFDE
E_REG @ $FFDF ;environment register
E_IORB @ $FFE0
E_DDRB @ $FFE2
E_DDRA @ $FFE3
E_ACR @ $FFEB
E_PCR @ $FFEC
E_IFR @ $FFED
E_IER @ $FFEE
B_REG @ $FFEF ;bank switch register
Z_REG @ $FFD0 ;zero page register
D_DDRB @ $FFD2 ;data direction register B
D_DDRA @ $FFD3 ;data direction register A
D_TIMER1C_L @ $FFD4
D_TIMER1C_H @ $FFD5
D_TIMER1L_L @ $FFD6
D_TIMER1L_H @ $FFD7
D_TIMER2C_L @ $FFD8
D_TIMER2C_H @ $FFD9
D_ACR @ $FFDB
D_PCR @ $FFDC
D_IFR @ $FFDD
D_IER @ $FFDE
E_REG @ $FFDF ;environment register
E_IORB @ $FFE0
E_DDRB @ $FFE2
E_DDRA @ $FFE3
E_TIMER1C_L @ $FFE6
E_TIMER1C_H @ $FFE7
E_TIMER1L_L @ $FFE6
E_TIMER1L_H @ $FFE7
E_TIMER2C_L @ $FFE8
E_TIMER2C_H @ $FFE9
E_ACR @ $FFEB
E_PCR @ $FFEC
E_IFR @ $FFED
E_IER @ $FFEE
B_REG @ $FFEF ;bank switch register

View File

@ -15,7 +15,6 @@
*/
using System;
using System.Collections.Generic;
using PluginCommon;
/*
@ -69,7 +68,7 @@ namespace RuntimeData.Apple {
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[]> ParamDescrs = new Dictionary<int, Param[]>() {
private Dictionary<int, Param[]> mParamDescrs = new Dictionary<int, Param[]>() {
{ 0x40, // ALLOC_INTERRUPT
new Param[] { PARAM_COUNT, MISC1, CODEPTR }
},
@ -193,8 +192,8 @@ namespace RuntimeData.Apple {
// match!
byte req = mFileData[offset + 3];
int blockAddr = Util.GetWord(mFileData, offset + 4, 2, false);
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"));
}
@ -211,31 +210,8 @@ namespace RuntimeData.Apple {
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 (mParamDescrs.TryGetValue(req, out parms)) {
FormatParameterBlock(offset, parms);
}
if (req == 0x65) { // QUIT call
@ -243,5 +219,34 @@ namespace RuntimeData.Apple {
}
}
}
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;
}
}
}
}
}

View File

@ -31,11 +31,288 @@ parm_block
namespace RuntimeData.Apple {
public class SOS : MarshalByRefObject, IPlugin, IPlugin_SymbolList, IPlugin_InlineBrk {
private const string SOS_MLI_TAG = "SOS-MLI-Functions"; // tag used in .sym65 file
private bool VERBOSE = true;
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[] NO_PARAMS = new Param[0];
private class ParamSet {
public Param[] Required { get; private set; }
public Param[] Optional { get; private set; }
public ParamSet(Param[] required, Param[] optional) {
Required = required;
Optional = optional;
}
}
private static Param PARAM_COUNT = new Param(DataType.NumericLE, DataSubType.Decimal, 1);
private static Param OPTION_LIST = new Param(DataType.NumericLE, DataSubType.Address, 2);
private static Param OPTION_LENGTH = new Param(DataType.NumericLE, DataSubType.Decimal, 1);
private static Param SEG_ADDR = new Param(DataType.NumericLE, DataSubType.Hex, 2);
private static Param SEG_ID = new Param(DataType.NumericLE, DataSubType.Hex, 1);
private static Param SEG_NUM = new Param(DataType.NumericLE, DataSubType.Hex, 1);
private static Param PATHNAME = new Param(DataType.NumericLE, DataSubType.Address, 2);
private static Param TIME_PTR = new Param(DataType.NumericLE, DataSubType.Address, 2);
private static Param POINTER = new Param(DataType.NumericLE, DataSubType.Address, 2);
private static Param REF_NUM = new Param(DataType.NumericLE, DataSubType.Decimal, 1);
private static Param ACCESS = new Param(DataType.NumericLE, DataSubType.Hex, 1);
private static Param FILE_POS = new Param(DataType.NumericLE, DataSubType.Hex, 4);
private static Param DATE_TIME = new Param(DataType.NumericLE, DataSubType.Hex, 4);
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 MISC4 = new Param(DataType.NumericLE, DataSubType.Hex, 4);
private static Param UNUSED7 = new Param(DataType.Dense, DataSubType.None, 7);
private Dictionary<int, ParamSet> mParamDescrs = new Dictionary<int, ParamSet>() {
{ 0x40, // SOS_REQUEST_SEG
new ParamSet(
new Param[] { PARAM_COUNT, SEG_ADDR, SEG_ADDR, SEG_ID, SEG_NUM },
NO_PARAMS
)
},
{ 0x41, // SOS_FIND_SEG
new ParamSet(
new Param[] { PARAM_COUNT, MISC1, SEG_ID, MISC2, SEG_ADDR, SEG_ADDR, SEG_NUM },
NO_PARAMS
)
},
{ 0x42, // SOS_CHANGE_SEG
new ParamSet(
new Param[] { PARAM_COUNT, SEG_NUM, MISC1, MISC2 },
NO_PARAMS
)
},
{ 0x43, // SOS_GET_SEG_INFO
new ParamSet(
new Param[] { PARAM_COUNT, SEG_NUM, SEG_ADDR, SEG_ADDR, MISC2, SEG_ID },
NO_PARAMS
)
},
{ 0x44, // SOS_GET_SEG_NUM
new ParamSet(
new Param[] { PARAM_COUNT, SEG_ADDR, SEG_NUM },
NO_PARAMS
)
},
{ 0x45, // SOS_RELEASE_SEG
new ParamSet(
new Param[] { PARAM_COUNT, SEG_NUM },
NO_PARAMS
)
},
{ 0x60, // SOS_SET_FENCE
new ParamSet(
new Param[] { PARAM_COUNT, MISC1 },
NO_PARAMS
)
},
{ 0x61, // SOS_GET_FENCE
new ParamSet(
new Param[] { PARAM_COUNT, MISC1 },
NO_PARAMS
)
},
{ 0x62, // SOS_SET_TIME
new ParamSet(
new Param[] { PARAM_COUNT, TIME_PTR },
NO_PARAMS
)
},
{ 0x63, // SOS_GET_TIME
new ParamSet(
new Param[] { PARAM_COUNT, TIME_PTR },
NO_PARAMS
)
},
{ 0x64, // SOS_GET_ANALOG
new ParamSet(
new Param[] { PARAM_COUNT, MISC1, MISC4 },
NO_PARAMS
)
},
{ 0x65, // SOS_TERMINATE
new ParamSet(
NO_PARAMS,
NO_PARAMS
)
},
{ 0x80, // SOS_D_READ
new ParamSet(
new Param[] { PARAM_COUNT, MISC1, POINTER, MISC2, MISC2, MISC2 },
NO_PARAMS
)
},
{ 0x81, // SOS_D_WRITE
new ParamSet(
new Param[] { PARAM_COUNT, MISC1, POINTER, MISC2, MISC2 },
NO_PARAMS
)
},
{ 0x82, // SOS_D_STATUS
new ParamSet(
new Param[] { PARAM_COUNT, MISC1, MISC1, POINTER },
NO_PARAMS
)
},
{ 0x83, // SOS_D_CONTROL
new ParamSet(
new Param[] { PARAM_COUNT, MISC1, MISC1, POINTER },
NO_PARAMS
)
},
{ 0x84, // SOS_GET_DEV_NUM
new ParamSet(
new Param[] { PARAM_COUNT, PATHNAME, MISC1 },
NO_PARAMS
)
},
{ 0x85, // SOS_D_INFO
new ParamSet(
new Param[] { PARAM_COUNT, MISC1, PATHNAME, OPTION_LIST, OPTION_LENGTH },
new Param[] { MISC1, MISC1, MISC1, MISC1, MISC1, MISC2, MISC2, MISC2 }
)
},
{ 0xc0, // SOS_CREATE
new ParamSet(
new Param[] { PARAM_COUNT, PATHNAME, OPTION_LIST, OPTION_LENGTH },
new Param[] { MISC1, MISC2, MISC1, FILE_POS }
)
},
{ 0xc1, // SOS_DESTROY
new ParamSet(
new Param[] { PARAM_COUNT, PATHNAME },
NO_PARAMS
)
},
{ 0xc2, // SOS_RENAME
new ParamSet(
new Param[] { PARAM_COUNT, PATHNAME, PATHNAME },
NO_PARAMS
)
},
{ 0xc3, // SOS_SET_FILE_INFO
new ParamSet(
new Param[] { PARAM_COUNT, PATHNAME, OPTION_LIST, OPTION_LENGTH },
new Param[] { ACCESS, MISC1, MISC2, UNUSED7, DATE_TIME }
)
},
{ 0xc4, // SOS_GET_FILE_INFO
new ParamSet(
new Param[] { PARAM_COUNT, PATHNAME, OPTION_LIST, OPTION_LENGTH },
new Param[] { ACCESS, MISC1, MISC2, MISC1, FILE_POS, MISC2, DATE_TIME }
)
},
{ 0xc5, // SOS_VOLUME
new ParamSet(
new Param[] { PARAM_COUNT, PATHNAME, PATHNAME, MISC2, MISC2 },
NO_PARAMS
)
},
{ 0xc6, // SOS_SET_PREFIX
new ParamSet(
new Param[] { PARAM_COUNT, PATHNAME },
NO_PARAMS
)
},
{ 0xc7, // SOS_GET_PREFIX
new ParamSet(
new Param[] { PARAM_COUNT, PATHNAME, MISC1 },
NO_PARAMS
)
},
{ 0xc8, // OPEN
new ParamSet(
new Param[] { PARAM_COUNT, PATHNAME, REF_NUM, OPTION_LIST, OPTION_LENGTH },
new Param[] { ACCESS, MISC1, POINTER }
)
},
{ 0xc9, // SOS_NEWLINE
new ParamSet(
new Param[] { PARAM_COUNT, REF_NUM, MISC1, MISC1 },
NO_PARAMS
)
},
{ 0xca, // SOS_READ
new ParamSet(
new Param[] { PARAM_COUNT, REF_NUM, POINTER, MISC2, MISC2 },
NO_PARAMS
)
},
{ 0xcb, // SOS_WRITE
new ParamSet(
new Param[] { PARAM_COUNT, REF_NUM, POINTER, MISC2 },
NO_PARAMS
)
},
{ 0xcc, // SOS_CLOSE
new ParamSet(
new Param[] { PARAM_COUNT, REF_NUM },
NO_PARAMS
)
},
{ 0xcd, // SOS_FLUSH
new ParamSet(
new Param[] { PARAM_COUNT, REF_NUM },
NO_PARAMS
)
},
{ 0xce, // SOS_SET_MARK
new ParamSet(
new Param[] { PARAM_COUNT, REF_NUM, MISC1, FILE_POS },
NO_PARAMS
)
},
{ 0xcf, // SOS_GET_MARK
new ParamSet(
new Param[] { PARAM_COUNT, REF_NUM, FILE_POS },
NO_PARAMS
)
},
{ 0xd0, // SOS_SET_EOF
new ParamSet(
new Param[] { PARAM_COUNT, REF_NUM, MISC1, FILE_POS },
NO_PARAMS
)
},
{ 0xd1, // SOS_GET_EOF
new ParamSet(
new Param[] { PARAM_COUNT, REF_NUM, FILE_POS },
NO_PARAMS
)
},
{ 0xd2, // SOS_SET_LEVEL
new ParamSet(
new Param[] { PARAM_COUNT, MISC1 },
NO_PARAMS
)
},
{ 0xd3, // SOS_GET_LEVEL
new ParamSet(
new Param[] { PARAM_COUNT, MISC1 },
NO_PARAMS
)
},
};
#endregion Parameter block defs
private IApplication mAppRef;
private byte[] mFileData;
private Dictionary<int, PlSymbol> mFunctionList;
private AddressTranslate mAddrTrans;
public string Identifier {
get {
@ -46,6 +323,7 @@ namespace RuntimeData.Apple {
public void Prepare(IApplication appRef, byte[] fileData, AddressTranslate addrTrans) {
mAppRef = appRef;
mFileData = fileData;
mAddrTrans = addrTrans;
mAppRef.DebugLog("SOS(id=" + AppDomain.CurrentDomain.Id + "): prepare()");
//System.Diagnostics.Debugger.Break();
@ -54,6 +332,7 @@ namespace RuntimeData.Apple {
public void Unprepare() {
mAppRef = null;
mFileData = null;
mAddrTrans = null;
}
public void UpdateSymbolList(List<PlSymbol> plSyms) {
@ -89,10 +368,91 @@ namespace RuntimeData.Apple {
mAppRef.SetInlineDataFormat(offset + 2, 2, DataType.NumericLE,
DataSubType.Address, null);
// Clear the "no continue" flag unless this is a QUIT call.
if (req != 0x65) { // QUIT call
ParamSet pset;
if (mParamDescrs.TryGetValue(req, out pset)) {
FormatParameterBlock(offset, pset);
}
// Clear the "no continue" flag unless this is a TERMINATE (QUIT) call.
if (req != 0x65) { // SOS_TERMINATE
noContinue = false;
}
}
private void FormatParameterBlock(int offset, ParamSet pset) {
if (VERBOSE) {
mAppRef.DebugLog("SOSPARM: trying to format SOS at +" + offset.ToString("x6"));
}
int blockAddr = Util.GetWord(mFileData, offset + 2, 2, false);
// Try to format the parameter block. Start by figuring out how long the
// required portion is.
int blockLen = 0;
foreach (Param parm in pset.Required) {
blockLen += parm.Length;
}
int optionListAddr = -1;
int optionListLen = -1;
// Locate it and verify that the entire thing fits in the file.
int blockOff = mAddrTrans.AddressToOffset(offset, blockAddr);
if (VERBOSE) {
mAppRef.DebugLog("SOSPARM: checking addr=$" + blockAddr.ToString("x4") +
" off=+" + blockOff.ToString("x6") + " len=" + blockLen);
}
if (Util.IsInBounds(mFileData, blockOff, blockLen)) {
if (VERBOSE) {
mAppRef.DebugLog("SOSPARM: formatting block at +" + blockOff.ToString("x6"));
}
foreach (Param parm in pset.Required) {
// Watch for option list parameters.
if (parm == OPTION_LIST) {
optionListAddr = Util.GetWord(mFileData, blockOff, 2, false);
} else if (parm == OPTION_LENGTH) {
optionListLen = mFileData[blockOff];
}
// 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;
}
} else {
if (VERBOSE) {
mAppRef.DebugLog("SOSPARM: NOT in bounds");
}
}
if (optionListAddr >= 0 && optionListLen > 0) {
if (VERBOSE) {
mAppRef.DebugLog("SOSPARM: format optionList addr=$" +
optionListAddr.ToString("x4") + " len=" + optionListLen);
}
blockOff = mAddrTrans.AddressToOffset(offset, optionListAddr);
if (Util.IsInBounds(mFileData, blockOff, optionListLen)) {
// Format the parts of the option list that are present.
int usedLen = 0;
foreach (Param parm in pset.Optional) {
if (usedLen + parm.Length > optionListLen) {
// This parameter was not provided.
break;
}
mAppRef.SetInlineDataFormat(blockOff, parm.Length, parm.Type,
parm.SubType, null);
blockOff += parm.Length;
usedLen += parm.Length;
}
}
}
}
}
}

View File

@ -2,9 +2,10 @@
; See the LICENSE.txt file for distribution terms (Apache 2.0).
;
; Source: SOS programmer's guide
; SOS Reference Manual, Volume 2 (Apple 1982)
; SOS Reference Manual, Volume 1 & 2 (Apple 1982)
; Undocumented Apple /// SOS Features
*SYNOPSIS Apple /// Sophisticated Operating System constants.
*SYNOPSIS Apple III Sophisticated Operating System constants.
; SOS MLI function codes.
*TAG SOS-MLI-Functions
@ -21,12 +22,12 @@ SOS_GET_FENCE = $61
SOS_SET_TIME = $62
SOS_GET_TIME = $63
SOS_GET_ANALOG = $64
; SOS ref: "TERMINATE"
SOS_TERMINATE = $65
; SOS ref: "No errors are possible. This is an excellent call for beginners."
SOS_QUIT = $65
SOS_READBLOCK = $80
SOS_WRITEBLOCK = $81
; SOS ref does not describe D_READ and D_WRITE; see Undocumented Features doc.
SOS_D_READ = $80
SOS_D_WRITE = $81
SOS_D_STATUS = $82
SOS_D_CONTROL = $83
SOS_GET_DEV_NUM = $84
@ -42,10 +43,8 @@ SOS_SET_PREFIX = $C6
SOS_GET_PREFIX = $C7
SOS_OPEN = $C8
SOS_NEWLINE = $C9
; SOS ref: "READ"
SOS_READFILE = $CA
; SOS ref: "WRITE"
SOS_WRITEFILE = $CB
SOS_READ = $CA
SOS_WRITE = $CB
SOS_CLOSE = $CC
SOS_FLUSH = $CD
SOS_SET_MARK = $CE
@ -54,3 +53,75 @@ SOS_SET_EOF = $D0
SOS_GET_EOF = $D1
SOS_SET_LEVEL = $D2
SOS_GET_LEVEL = $D3
*TAG
;
; SOS call error codes.
;
; $01-05: problem with form of call, parameters, or pointers
; $10-2f: device call errors
; $30-3f: problem with particular device
; $40-5a: file call errors
; $70-7f: utility call errors
; $e0-ef: memory call errors
;
SOS_BADSCNUM = $01
SOS_BADCZPAGE = $02
SOS_BADXBYTE = $03
SOS_BADSCPCNT = $04
SOS_BADSCBNDS = $05
SOS_DNFERR = $10
SOS_BADDNUM = $11
SOS_BADREQCODE = $20
SOS_BADCTL = $21
SOS_BADCTLPARM = $22
SOS_NOTOPEN = $23
SOS_NORESC = $25
SOS_BADOP = $26
SOS_IOERR = $27
SOS_CRCERR = $2a
SOS_NOWRITE = $2b
SOS_BYTECNT = $2c
SOS_BLKNUM = $2d
SOS_DISKSW = $2e
SOS_BADPATH = $40
SOS_CFCBFULL = $41
SOS_FCBFULL = $42
SOS_BADREFNUM = $43
SOS_PNFERR = $44
SOS_VNFERR = $45
SOS_FNFERR = $46
SOS_DUPERR = $47
SOS_OVRERR = $48
SOS_DIRFULL = $49
SOS_CPTERR = $4a
SOS_TYPERR = $4b
SOS_EOFERR = $4c
SOS_POSNERR = $4d
SOS_ACCSERR = $4e
SOS_BTSERR = $4f
SOS_FILBUSY = $50
SOS_DIRERR = $51
SOS_NOTSOS = $52
SOS_BADLSTCNT = $53
SOS_OUTOFMEM = $54
SOS_BUFTBLFULL = $55
SOS_BADSYSBUF = $56
SOS_DUPVOL = $57
SOS_NOTBLKDEV = $58
SOS_LVLERR = $59
SOS_BITMAPADR = $5a
SOS_BADJMODE = $70
SOS_BADBKPG = $e0
SOS_SEGRQDN = $e1
SOS_SEGTBLFULL = $e2
SOS_BADSEGNUM = $e3
SOS_SEGNOTFND = $e4
SOS_BADSRCHMODE = $e5
SOS_BADCHGMODE = $e6
SOS_BADPGCNT = $e7