-- SegmentDefs.Mesa  Edited by Sandman on August 12, 1980  9:54 AM
-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  AltoDefs USING [
    BytesPerPage, MaxFilePage, MaxVMPage, PageCount, PageNumber, PageSize,
    PagesPerMDS],
  AltoFileDefs USING [CFA, FA, FH, FI, FP, vDA],
  Mopcodes USING [zAND, zLDIV, zMUL, zPUSH];

SegmentDefs: DEFINITIONS =
  BEGIN OPEN AltoDefs, AltoFileDefs;

  FileHint: TYPE = AltoFileDefs.FH;
  FileIndex: TYPE = AltoFileDefs.FI;
  PageCount: TYPE = AltoDefs.PageCount;
  PageNumber: TYPE = AltoDefs.PageNumber;

  -- Basic Memory Addressing: 


  PagePointer: PROCEDURE [a: POINTER] RETURNS [POINTER] = INLINE
    BEGIN
    BITAND: PROCEDURE [UNSPECIFIED, UNSPECIFIED] RETURNS [UNSPECIFIED] = MACHINE
      CODE BEGIN Mopcodes.zAND END;

    RETURN[BITAND[a, 177400B]]
    END;

  PageFromAddress: PROCEDURE [a: POINTER] RETURNS [PageNumber];

  AddressFromPage: PROCEDURE [p: PageNumber] RETURNS [POINTER] = INLINE
    BEGIN RETURN[LOOPHOLE[p*PageSize]] END;

  PageFromLongAddress: PROCEDURE [a: LONG POINTER] RETURNS [PageNumber] = INLINE
    BEGIN
    LongDiv: PROCEDURE [p: LONG POINTER, den: CARDINAL] RETURNS [CARDINAL] =
      MACHINE CODE BEGIN Mopcodes.zLDIV END;

    RETURN[LongDiv[p: a, den: PageSize]]
    END;

  LongAddressFromPage: PROCEDURE [p: PageNumber] RETURNS [LONG POINTER] = INLINE
    BEGIN
    LongMult: PROCEDURE [CARDINAL, CARDINAL] RETURNS [LONG POINTER] = MACHINE CODE
      BEGIN Mopcodes.zMUL; Mopcodes.zPUSH END;

    RETURN[LongMult[p, PageSize]]
    END;

  PageAvailable: PROCEDURE [page: PageNumber, info: AllocInfo] RETURNS [BOOLEAN];
  LargestMDSHole: PROCEDURE RETURNS [base: PageNumber, pages: PageCount];
  LargestHole: PROCEDURE RETURNS [base: PageNumber, pages: PageCount];
  PagesAvailable: PROCEDURE [base: PageNumber, pages: PageCount, info: AllocInfo]
    RETURNS [BOOLEAN];

  -- Configuration Information

  MachineType: TYPE = {
    unknown0, AltoI, AltoII, AltoIIXM, D0, Dorado, unknown6, unknown7};

  ControlStoreType: TYPE = {Ram0, RamandRom, Ram3k, unknown};

  BankIndex: TYPE = [0..17B];
  Banks: TYPE = PACKED ARRAY BankIndex OF BOOLEAN;

  MemoryConfig: TYPE = MACHINE DEPENDENT RECORD [
    reserved: [0..37B],
    AltoType: MachineType,
    xmMicroCode, useXM: BOOLEAN,
    mdsBank: BankIndex,
    controlStore: ControlStoreType,
    banks: [0..177777B],
    mesaMicrocodeVersion: [0..177777B]];

  memConfig: PUBLIC READONLY MemoryConfig;

  GetMemoryConfig: PROCEDURE RETURNS [MemoryConfig] = INLINE
    BEGIN RETURN[memConfig] END;

  -- Primative System Objects: 

  ObjectType: PRIVATE TYPE = {free, segment, file, length};

  ObjectHandle: PRIVATE TYPE = POINTER TO Object;

  Object: TYPE = RECORD [
    busy: PRIVATE BOOLEAN ← FALSE,
    body:
      SELECT tag: ObjectType FROM
	free => [
	  seal: PRIVATE [0..37B],
	  size: PRIVATE FrobSize,
	  fwdp, backp: PRIVATE FrobLink],
	segment => [
	  VMpage: [0..MaxVMPage],
	  info:
	    SELECT type: SegmentType FROM
	      data => [
		type: DataSegmentType ← UnknownDS, pages: [1..PagesPerMDS]],
	      file => [
		swappedin: BOOLEAN,
		write: BOOLEAN,
		class: FileSegmentClass,
		inuse: BOOLEAN,
		lock: SegLockCount,
		pages: [1..PagesPerMDS],
		file: FileHandle,
		base: PageNumber,
		location:
		  SELECT loc: SegmentLocation FROM
		    disk => [hint: FileHint],
		    remote => [proc: RemoteSegProc, info: UNSPECIFIED],
		    ENDCASE],
	      ENDCASE],
	file => [
	  open: BOOLEAN,
	  length: BOOLEAN,
	  lengthvalid: BOOLEAN,
	  read, write, append: BOOLEAN,
	  lengthchanged: BOOLEAN,
	  unused: [0..77B] ← 0,
	  lock: FileLockCount,
	  swapcount: RefCount,
	  segcount: SegCount,
	  fp: FP],
	length => [
	  unused: [0..7B] ← 0,
	  byte: [0..BytesPerPage],
	  page: PageNumber,
	  file: FileHandle,
	  da: vDA],
	ENDCASE];

  MaxRefs: CARDINAL = 377B;
  RefCount: TYPE = [0..MaxRefs];

  MaxSegLocks: CARDINAL = 17B;
  SegLockCount: TYPE = [0..MaxSegLocks];

  MaxFileLocks: CARDINAL = 377B;
  FileLockCount: TYPE = [0..MaxFileLocks];

  MaxSegs: CARDINAL = 177777B;
  SegCount: TYPE = [0..MaxSegs];

  -- Free Objects

  Frob: TYPE = free Object;
  FrobHandle: TYPE = POINTER TO Frob;
  FrobLink: TYPE = ORDERED POINTER [0..AltoDefs.PageSize) TO Frob;
  FrobSize: TYPE = [0..AltoDefs.PageSize);
  FrobNull: FrobLink = LAST[FrobLink];

  -- S E G M E N T S: 

  DefaultPages: PageCount = 0;
  DefaultBase: PageNumber = MaxFilePage;
  DefaultMDSBase: PageNumber = DefaultBase - 1;
  DefaultXMBase: PageNumber = DefaultMDSBase - 1;
  DefaultANYBase: PageNumber = DefaultXMBase - 1;
  DefaultBase0: PageNumber = DefaultANYBase - 1;
  DefaultBase1: PageNumber = DefaultBase0 - 1;
  DefaultBase2: PageNumber = DefaultBase1 - 1;
  DefaultBase3: PageNumber = DefaultBase2 - 1;

  SegmentObject: TYPE = segment Object;
  SegmentHandle: TYPE = POINTER TO SegmentObject;

  SegmentType: TYPE = {data, file};
  SegmentLocation: TYPE = {disk, remote};
  SegmentClass: TYPE = {frame, table, code, other};
  RemoteSegProc: TYPE = PROCEDURE [
    seg: FileSegmentHandle, command: RemoteSegCommand];
  RemoteSegCommand: TYPE = UNSPECIFIED;

  VMtoSegment: PROCEDURE [a: POINTER] RETURNS [SegmentHandle];
  SegmentAddress: PROCEDURE [seg: SegmentHandle] RETURNS [POINTER];

  AllocInfo: TYPE = RECORD [
    effort: {hard, easy}, direction: {topdown, bottomup}, class: SegmentClass];

  EasyUp: AllocInfo = AllocInfo[easy, bottomup, other];
  EasyDown: AllocInfo = AllocInfo[easy, topdown, other];
  HardUp: AllocInfo = AllocInfo[hard, bottomup, other];
  HardDown: AllocInfo = AllocInfo[hard, topdown, other];

  -- Data Segments: 

  DataSegmentObject: TYPE = data SegmentObject;
  DataSegmentHandle: TYPE = POINTER TO DataSegmentObject;

  DataSegmentType: TYPE = CARDINAL [0..377B];
  UnknownDS: DataSegmentType = 0;
  FrameDS: DataSegmentType = 1;
  TableDS: DataSegmentType = 2;
  HeapDS: DataSegmentType = 3;
  SystemDS: DataSegmentType = 4;
  BitmapDS: DataSegmentType = 5;
  StreamBufferDS: DataSegmentType = 6;
  PupBufferDS: DataSegmentType = 7;

  NewDataSegment: PROCEDURE [base: PageNumber ← DefaultBase, pages: PageCount]
    RETURNS [DataSegmentHandle] = INLINE
    BEGIN RETURN[MakeDataSegment[base, pages, EasyDown]] END;

  MakeDataSegment: PROCEDURE [
    base: PageNumber ← DefaultBase, pages: PageCount, info: AllocInfo ← EasyDown]
    RETURNS [seg: DataSegmentHandle];

  DeleteDataSegment: PROCEDURE [seg: DataSegmentHandle];

  VMtoDataSegment: PROCEDURE [a: POINTER] RETURNS [DataSegmentHandle];
  DataSegmentAddress: PROCEDURE [seg: DataSegmentHandle] RETURNS [POINTER];

  EnumerateDataSegments: PROCEDURE [
    proc: PROCEDURE [DataSegmentHandle] RETURNS [BOOLEAN]]
    RETURNS [DataSegmentHandle];

  -- File Segments: 

  FileSegmentObject: TYPE = file SegmentObject;
  FileSegmentHandle: TYPE = POINTER TO FileSegmentObject;

  FileSegmentClass: TYPE = {code, other};

  InvalidSegmentSize: SIGNAL [pages: PageCount];

  NewFileSegment: PROCEDURE [
    file: FileHandle, base: PageNumber, pages: PageCount, access: AccessOptions]
    RETURNS [FileSegmentHandle];
  MoveFileSegment: PROCEDURE [
    seg: FileSegmentHandle, base: PageNumber, pages: PageCount];
  MapFileSegment: PROCEDURE [
    seg: FileSegmentHandle, file: FileHandle, base: PageNumber];
  DeleteFileSegment: PROCEDURE [seg: FileSegmentHandle];

  VMtoFileSegment: PROCEDURE [a: POINTER] RETURNS [FileSegmentHandle];
  FileSegmentAddress: PROCEDURE [seg: FileSegmentHandle] RETURNS [POINTER];

  GetFileSegmentDA: PROCEDURE [seg: FileSegmentHandle] RETURNS [vDA];
  SetFileSegmentDA: PROCEDURE [seg: FileSegmentHandle, da: vDA];

  EnumerateFileSegments: PROCEDURE [
    proc: PROCEDURE [FileSegmentHandle] RETURNS [BOOLEAN]]
    RETURNS [FileSegmentHandle];

  -- File Segment Swapping: 

  SwapError: SIGNAL [seg: FileSegmentHandle];
  SegmentFault: SIGNAL [seg: FileSegmentHandle, pages: PageCount];
  SwapUp, SwapOut, Unlock: PROCEDURE [seg: FileSegmentHandle];
  SwapIn: PROCEDURE [seg: FileSegmentHandle] = INLINE
    BEGIN MakeSwappedIn[seg, DefaultMDSBase, EasyUp] END;

  MakeSwappedIn: PROCEDURE [
    seg: FileSegmentHandle, base: PageNumber ← DefaultBase,
    info: AllocInfo ← EasyUp];

  -- Initializing File and Data Segments


  CopyDataToFileSegment: PROCEDURE [
    dataseg: DataSegmentHandle, fileseg: FileSegmentHandle];
  CopyFileToDataSegment: PROCEDURE [
    fileseg: FileSegmentHandle, dataseg: DataSegmentHandle];
  ChangeDataToFileSegment: PROCEDURE [
    dataseg: DataSegmentHandle, fileseg: FileSegmentHandle];

  InsufficientVM: SIGNAL [needed: PageCount];
  VMnotFree: SIGNAL [base: PageNumber, pages: PageCount];

  -- F I L E S: 

  FileObject: TYPE = file Object;
  FileHandle: TYPE = POINTER TO FileObject;
  LengthObject: TYPE = length Object;
  LengthHandle: TYPE = POINTER TO LengthObject;

  AccessOptions: TYPE = [0..7];
  Read: AccessOptions = 1;
  Write: AccessOptions = 2;
  Append: AccessOptions = 4;
  ReadWrite: AccessOptions = 3;
  WriteAppend: AccessOptions = 6;
  ReadWriteAppend: AccessOptions = 7;

  VersionOptions: TYPE = [0..3];
  NewFileOnly: VersionOptions = 1;
  OldFileOnly: VersionOptions = 2;

  DefaultAccess: AccessOptions = 0;
  DefaultVersion: VersionOptions = 0;

  FileNameError: SIGNAL [name: STRING];
  InvalidFP: SIGNAL [fp: POINTER TO FP];
  FileError, FileAccessError: SIGNAL [file: FileHandle];

  NewFile: PROCEDURE [
    name: STRING, access: AccessOptions ← DefaultAccess,
    version: VersionOptions ← DefaultVersion] RETURNS [FileHandle];
  InsertFile: PROCEDURE [fp: POINTER TO FP, access: AccessOptions ← DefaultAccess]
    RETURNS [FileHandle];
  OpenFile, CloseFile: PROCEDURE [file: FileHandle];
  LockFile, UnlockFile: PROCEDURE [file: FileHandle];
  ReleaseFile, DestroyFile: PROCEDURE [file: FileHandle];

  GetFileTimes: PROCEDURE [file: FileHandle]
    RETURNS [read, write, create: LONG CARDINAL];
  SetFileTimes: PROCEDURE [
    file: FileHandle, read, write, create: LONG CARDINAL ← 0];

  GetFileAccess: PROCEDURE [file: FileHandle] RETURNS [access: AccessOptions];
  SetFileAccess: PROCEDURE [file: FileHandle, access: AccessOptions];

  InsertFileLength: PROCEDURE [file: FileHandle, fa: POINTER TO FA];
  GetEndOfFile: PROCEDURE [file: FileHandle]
    RETURNS [page: PageNumber, byte: CARDINAL];
  SetEndOfFile: PROCEDURE [file: FileHandle, page: PageNumber, byte: CARDINAL];
  SetFileLength: PROCEDURE [file: FileHandle, fa: POINTER TO FA];
  UpdateFileLength: PROCEDURE [file: FileHandle, fa: POINTER TO FA];
  GetFileLength: PROCEDURE [file: FileHandle, fa: POINTER TO FA];

  JumpToPage: PROCEDURE [cfa: POINTER TO CFA, page: PageNumber, buf: POINTER]
    RETURNS [prev, next: vDA];

  GetFileFP: PROCEDURE [file: FileHandle, fp: POINTER TO FP];
  FindFile: PROCEDURE [fp: POINTER TO FP] RETURNS [FileHandle];

  EnumerateFiles: PROCEDURE [proc: PROCEDURE [FileHandle] RETURNS [BOOLEAN]]
    RETURNS [file: FileHandle];

  -- Extended Memory


  ValidateVMPage: PROCEDURE [page: UNSPECIFIED];
  InvalidVMPage: ERROR [page: UNSPECIFIED];

  ValidateLongPointer: PROCEDURE [a: LONG UNSPECIFIED];
  InvalidLongPointer: ERROR [lp: LONG UNSPECIFIED];

  LongVMtoSegment: PROCEDURE [a: LONG POINTER] RETURNS [SegmentHandle];
  LongSegmentAddress: PROCEDURE [seg: SegmentHandle] RETURNS [LONG POINTER];

  LongVMtoDataSegment: PROCEDURE [a: LONG POINTER] RETURNS [DataSegmentHandle];
  LongDataSegmentAddress: PROCEDURE [seg: DataSegmentHandle]
    RETURNS [LONG POINTER];

  LongVMtoFileSegment: PROCEDURE [a: LONG POINTER] RETURNS [FileSegmentHandle];
  LongFileSegmentAddress: PROCEDURE [seg: FileSegmentHandle]
    RETURNS [LONG POINTER];

  ImmovableSegmentInXM: SIGNAL [seg: SegmentHandle];

  END.