PRJ:第2代hacker编写的汇编器

本文介绍了Chipper V2.11 Assembler的基本概念、核心功能及其在不同操作系统上的兼容性优化。从版本历史、源语言解析到指令集和表达式解析,详细解释了其工作原理和用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/* (S)Chip-48 Assembler V2.11 by Christian Egeberg 2/11-'90 .. 20/8-'91 */

#define CopyRight "(S)Chip-48 Assembler V2.11 by Christian Egeberg 20/8-\'91"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

/* Modify macro below to force Ansi or Kernighan-Ritchie prototypes */
#define ANSI ( defined( c_plusplus ) || defined( __cplusplus ) || __STDC__ )
/* Modify macro below to change procedure storage class */
#define PROC

#define False     ( char )0
#define True      ( char )~0
#define UnDefined 0L
#define Defined   ~0L

#define StartAddress 0x200L
#define StopAddress  0xfffL
#define CheckMagic   0x1081L
#define WordMask     0xffffL
#define AddrMask     0xfffL
#define ByteMask     0xffL
#define NibbleMask   0xfL

#define SpaceLength     32768 
#define LineLength      255
#define ParamLength     127
#define SymbolLength    32
#define ListLength      32
#define StackLength     32  
#define MaxBaseLength   16
#define BinHpHeadLength 13
#define FailExitCode    1
#define SuccessExitCode 0

#define NullChar      '\0'
#define BellChar      '\7'
#define SpaceChar     ' '
#define SeparatorChar ','
#define RemarkChar    ';'
#define SymbolChar    '_'
#define LabelChar     ':'
#define EqualChar     '='
#define TextChar      '\''
#define AddressChar   '\77'
#define HexChar       '#'
#define BinChar       '$'
#define OctChar       '@'
#define AscChar       '\"'
#define StartChar     '('
#define StopChar      ')'
#define PlusChar      '+'
#define MinusChar     '-'
#define NotChar       '~'
#define PowerChar     '!'
#define ShlChar       '<'
#define ShrChar       '>'
#define MulChar       '*'
#define FracChar      '/'
#define AndChar       '&'
#define OrChar        '|'
#define XorChar       '^'
#define DivChar       '\\'
#define ModChar       '%'

#define WrongToken    0
#define EqualToken    1
#define AddToken      2
#define AlignToken    3
#define AndToken      4
#define CallToken     5
#define ClsToken      6
#define DaToken       7
#define DbToken       8
#define DefineToken   9
#define DrwToken     10
#define DsToken      11
#define DwToken      12
#define ElseToken    13
#define EndToken     14
#define EndifToken   15
#define EquToken     16
#define ExitToken    17
#define HighToken    18
#define IfdefToken   19
#define IfundToken   20
#define IncludeToken 21
#define JpToken      22
#define LdToken      23
#define LowToken     24
#define OptionToken  25
#define OrToken      26
#define OrgToken     27
#define RetToken     28
#define RndToken     29
#define ScdToken     30
#define SclToken     31
#define ScrToken     32
#define SeToken      33
#define ShlToken     34
#define ShrToken     35
#define SknpToken    36
#define SkpToken     37
#define SneToken     38
#define SubToken     39
#define SubnToken    40
#define SysToken     41
#define UndefToken   42
#define UsedToken    43
#define XorToken     44
#define XrefToken    45
#define LastToken    46

#define BadReg   0
#define BReg     1
#define DtReg    2
#define FReg     3
#define HfReg    4
#define IReg     5
#define KReg     6
#define LfReg    7
#define RReg     8
#define StReg    9
#define V0Reg   10
#define V1Reg   11
#define V2Reg   12
#define V3Reg   13
#define V4Reg   14
#define V5Reg   15
#define V6Reg   16
#define V7Reg   17
#define V8Reg   18
#define V9Reg   19
#define VaReg   20
#define VbReg   21
#define VcReg   22
#define VdReg   23
#define VeReg   24
#define VfReg   25
#define IiReg   26
#define LastReg 27

#define AlignOnDefault  Defined
#define Chip8Default    UnDefined
#define Chip48Default   Defined
#define Super10Default  UnDefined
#define Super11Default  UnDefined
#define UsedYesDefault  UnDefined
#define UsedOnDefault   UnDefined
#define XrefYesDefault  Defined
#define XrefOnDefault   Defined
#define HpHeadDefault   Defined
#define HpAscDefault    UnDefined

typedef char CharSet[ 0x100 ];
typedef char LineString[ LineLength + 1 ];
typedef char ParamString[ ParamLength + 1 ];
typedef char SymbolString[ SymbolLength + 1 ];
typedef struct SpaceRecord {
  unsigned int Size;
  char *Start;
  char *Point;
  char *Index;
  unsigned int Request;
} SpaceRecord;
typedef struct LocRecord *LocPointer;
typedef struct LocRecord {
  unsigned int Line; 
  char *Name;
  char *Text;
  char Xref;
  long int Addr;
} LocRecord;
typedef struct ReferRecord *ReferPointer;
typedef struct ReferRecord {
  LocRecord Loc;
  ReferPointer Next;
} ReferRecord;
typedef struct ParamRecord *ParamPointer;
typedef struct ParamRecord {
  char *Param;
  ParamPointer Next;
} ParamRecord;
typedef struct SymbolRecord *SymbolPointer;
typedef struct SymbolRecord {
  LocRecord Loc;
  long int Value;
  char *Symbol;
  char *Expr;
  ReferPointer Refer;
  SymbolPointer Left;
  SymbolPointer Right;
} SymbolRecord;
typedef struct InstRecord *InstPointer;
typedef struct InstRecord { 
  LocRecord Loc;
  unsigned int Token;
  unsigned int Count;
  ParamPointer Params;
  InstPointer Next;
} InstRecord;

static char InExtDefault[] = ".chp";
static char ListExtDefault[] = ".lst";
static char DefFileName[] = ".";
static char StdFileName[] = "-";
static char StdInFileName[] = "stdin";
static char StdOutFileName[] = "stdout";
static char BinHpHeadText[] = "HPHP48-C";
static char AscHpHeadText[] = "%%HP: T(3)A(R)F(.);\n";

static char RunErrorMessage[] = "Fatal error: ";
static char RunWarningMessage[] = "Warning: ";
static char WarningNumMessage[] = "Total number of warnings: ";
static char EndOfFileMessage[] = "; End of file";
static char NoTargetError[] = "Usage is.. chipper Target [Source] [List]";
static char NoSourceError[] = "No source file found";
static char FileAccessError[] = "Unable to open file";
static char FileWriteError[] = "File or pipe output failed";
static char AllocationError[] = "Unable to allocate more memory";
static char SpaceAssertError[] = "Internal memory allocation mismatch";
static char NestedIfdefError[] = "Too many nested conditions";
static char BoundsError[] = "Outside legal address range";
static char ParamCountWarning[] = "Incorrect number of parameters";
static char DualSymbolWarning[] = "No directive recognized";
static char NoOptionWarning[] = "Option not recognized";
static char MissingSymbolWarning[] = "No symbol name specified";
static char NoSymbolWarning[] = "Not a defined symbol";
static char UnusedSymbolWarning[] = "Unused symbol detected";
static char CopySymbolWarning[] = "Existing symbol redefined";
static char UndefinedWarning[] = "Unable to evaluate parameter";
static char RangeWarning[] = "Parameter out of range";
static char NoRegisterWarning[] = "No register recognized";
static char BadRegisterWarning[] = "Illegal register specified";
static char NeedsChip8Warning[] = "Chip-8 spesific directive";
static char NeedsChip48Warning[] = "Chip-48 spesific directive";
static char NeedsSuper10Warning[] = "Super Chip-48 V1.0.. spesific directive";
static char NeedsSuper11Warning[] = "Super Chip-48 V1.1.. spesific directive";
static char MissingIfdefWarning[] = "No previous condition found";
static char CountDefineWarning[] = "Unbalanced condition matching in file";
static char InternalWarning[] = "Internal data structure mismatch";

static char AlignOnName[] = "ALIGNON";
static char Chip8Name[] = "CHIP8";
static char Chip48Name[] = "CHIP48";
static char Super10Name[] = "SCHIP10";
static char Super11Name[] = "SCHIP11";
static char UsedYesName[] = "USEDYES";
static char UsedOnName[] = "USEDON";
static char XrefYesName[] = "XREFYES";
static char XrefOnName[] = "XREFON";
static char HpHeadName[] = "HPHEAD";
static char HpAscName[] = "HPASC";
static char HpBinName[] = "HPBIN";
static char BinaryName[] = "BINARY";
static char StringName[] = "STRING";

static char OptionYesName[] = "YES";
static char OptionNoName[] = "NO";
static char OptionOnName[] = "ON";
static char OptionOffName[] = "OFF";

static SymbolString TokenText[ LastToken ] = 
  { ",,,,,",   "=",       "ADD",     "ALIGN",   "AND",
    "CALL",    "CLS",     "DA",      "DB",      "DEFINE",
    "DRW",     "DS",      "DW",      "ELSE",    "END",     
    "ENDIF",   "EQU",     "EXIT",    "HIGH",    "IFDEF",   
    "IFUND",   "INCLUDE", "JP",      "LD",      "LOW",     
    "OPTION",  "OR",      "ORG",     "RET",     "RND",     
    "SCD",     "SCL",     "SCR",     "SE",      "SHL",     
    "SHR",     "SKNP",    "SKP",     "SNE",     "SUB",     
    "SUBN",    "SYS",     "UNDEF",   "USED",    "XOR",     
    "XREF"                                                };

static SymbolString RegisterText[ LastReg ] =
  { ",,,", "B",   "DT",  "F",   "HF",  "I",   "K",   "LF",
    "R",   "ST",  "V0",  "V1",  "V2",  "V3",  "V4",  "V5",
    "V6",  "V7",  "V8",  "V9",  "VA",  "VB",  "VC",  "VD",
    "VE",  "VF",  "[I]"                                    };

static SpaceRecord Space = { SpaceLength, NULL, NULL, NULL, 0 };

static char StackStart[ StackLength + 1 ];
static char *StackPoint = StackStart;

static CharSet Operators;
static char StartOperator[] = { StartChar, NullChar };
static char StopOperator[] = { StopChar, NullChar };
static char UnaryOperator[] = { PlusChar, MinusChar, NotChar, NullChar };
static char PowerOperator[] = { PowerChar, ShlChar, ShrChar, NullChar };
static char MulDivOperator[] = { MulChar, FracChar, NullChar };
static char PlusMinusOperator[] = { PlusChar, MinusChar, NullChar };
static char BitWiseOperator[] = { AndChar, OrChar, XorChar, NullChar };
static char DivModOperator[] = { DivChar, ModChar, NullChar };
static ParamString DigitText = "0123456789ABCDEF.";
static char NullString[] = "\0";
static LineString Separator = "";

static long int DefinedValue = Defined;
static long int DummyValue = UnDefined;
static long int *AlignOnCond = &DummyValue;
static long int *Chip8Cond = &DummyValue;
static long int *Chip48Cond = &DummyValue;
static long int *Super10Cond = &DummyValue;
static long int *Super11Cond = &DummyValue;
static long int *UsedYesCond = &DummyValue;
static long int *UsedOnCond = &DummyValue;
static long int *XrefYesCond = &DummyValue;
static long int *XrefOnCond = &DummyValue;
static long int *HpHeadCond = &DummyValue;
static long int *HpAscCond = &DummyValue;

static InstPointer Instructions = NULL;
static SymbolPointer Directives = NULL;
static SymbolPointer Registers = NULL;
static SymbolPointer Symbols= NULL;
static SymbolPointer Conditions= NULL;
static InstPointer InstPoint = NULL;
static SymbolPointer SymbPoint = NULL;
static SymbolPointer CurrentSymbol = NULL;

static long int FinalAddress = StartAddress;
static LocRecord NullLocation = { 0, NullString, NullString, False, 0L };
static LocRecord UsedLocation = { 0, NullString, NullString, True, 0L };
static LocRecord Location = { 0, NullString, NullString, False, StartAddress };
static unsigned int WarningCount = 0;

static FILE *InFile = NULL;
static FILE *OutFile = NULL;
static FILE *ListFile = NULL;
static LineString InFileName = "";
static LineString OutFileName = "";
static LineString ListFileName = "";

static unsigned char Memory[ StopAddress - StartAddress + 1 ];

#if ANSI
  static PROC char ResolveDivMod( char *Symbol, char **Param,
    long int *Value, SymbolPointer Head, LocPointer Loc );
  static PROC void DecodeFile( char *FileName, InstPointer *Head,
    SymbolPointer Dir, SymbolPointer *Symb, SymbolPointer *Cond );
#else
  static PROC char ResolveDivMod();
  static PROC void DecodeFile();
#endif

#if ANSI
  static PROC void RunError( char AbortFlag, char *Message )
#else
  static PROC void RunError( AbortFlag, Message )
  char AbortFlag;
  char *Message;
#endif
{
  if( AbortFlag ) {
    fprintf( stderr, "%c%s\n%s%s\n", BellChar, Separator, RunErrorMessage,
      Message );
    if( ListFile )
      fprintf( ListFile, "%s\n%s%s\n", Separator, RunErrorMessage, Message );
  } else {
    fprintf( stderr, "%s\n%s%s\n", Separator, RunWarningMessage, Message );
    if( ListFile )
      fprintf( ListFile, "%s\n%s%s\n", Separator, RunWarningMessage, Message );
  }
  if( Location.Line ) {
    fprintf( stderr, "Current file %s line %u\n%s\n", Location.Name,
      Location.Line, Location.Text );
    if( ListFile ) 
      fprintf( ListFile, "Current file %s line %u\n%s\n", Location.Name,
        Location.Line, Location.Text );
  }
  if( InstPoint ) {
    fprintf( stderr, "Associated file %s line %u\n%s\n",
      InstPoint->Loc.Name, InstPoint->Loc.Line, InstPoint->Loc.Text );
    if( ListFile ) 
      fprintf( ListFile, "Associated file %s line %u\n%s\n",
        InstPoint->Loc.Name, InstPoint->Loc.Line, InstPoint->Loc.Text );
  }
  if( SymbPoint ) {
    fprintf( stderr, "Symbol %s file %s line %u\n%s\n", SymbPoint->Symbol,
      SymbPoint->Loc.Name, SymbPoint->Loc.Line, SymbPoint->Loc.Text );
    if( ListFile ) 
      fprintf( ListFile, "Symbol %s file %s line %u\n%s\n", SymbPoint->Symbol,
        SymbPoint->Loc.Name, SymbPoint->Loc.Line, SymbPoint->Loc.Text );
  }
  fprintf( stderr, "%s\n", Separator );
  if( ListFile )
    fprintf( ListFile, "%s\n", Separator );
  if( AbortFlag ) 
    exit( FailExitCode );
    /* exit function should close all files */
  else
    WarningCount++;
}

#if ANSI
  static PROC char *NumberString( char *Result, long int Value,
    unsigned int Base, unsigned int Count )
#else
  static PROC char *NumberString( Result, Value, Base, Count )
  char *Result;
  long int Value;
  unsigned int Base;
  unsigned int Count;
#endif
{
  char *Digit;

  Digit = Result + Count;
  *( Digit-- ) = NullChar;
  while(( Digit >= Result ) && ( Value > 0L )) {
    *( Digit-- ) = DigitText[ Value % Base ];
    Value /= Base;
  }
  while( Digit >= Result ) 
    *( Digit-- ) = '0';
  return( Result );
}

#if ANSI
  static PROC void ListInstruction( long int Address, unsigned int Count,
    InstPointer Inst )
#else
  static PROC void ListInstruction( Address, Count, Inst )
  long int Address;
  unsigned int Count;
  InstPointer Inst;
#endif
{
  unsigned int This;
  SymbolString HexText;

  if( fprintf( ListFile, "%s\n%s(%u).. %s: ", Inst->Loc.Text, Inst->Loc.Name,
    Inst->Loc.Line, NumberString( HexText, Address, 16, 3 )) <= 0 )
      RunError( True, FileWriteError );
  for( This = 0; This < Count; This++ )
    if( fprintf( ListFile, NumberString( HexText, ( long int )
      Memory[ Address + This - StartAddress ], 16, 2 )) <= 0 )
        RunError( True, FileWriteError );
  fprintf( ListFile, "\n" );
}

#if ANSI
  static PROC void ListReference( ReferPointer Head )
#else
  static PROC void ListReference( Head )
  ReferPointer Head;
#endif
{
  for( ; Head; Head = Head->Next )
    if( Head->Loc.Line && Head->Loc.Xref )
      if( fprintf( ListFile, "  %s(%u)\n", Head->Loc.Name,
        Head->Loc.Line ) <= 0 )
          RunError( True, FileWriteError );
}

#if ANSI
  static PROC void ListSymbols( SymbolPointer Head )
#else
  static PROC void ListSymbols( Head )
  SymbolPointer Head;
#endif
{
  SymbolString HexText;

  if( Head ) {
    if( Head->Left )
      ListSymbols( Head->Left );
    SymbPoint = Head;
    if( !( *UsedYesCond ) && Head->Loc.Line && !( Head->Refer ))
      RunError( False, UnusedSymbolWarning );
    if( Head->Expr )
      strcpy( HexText, "UND" );
    else
      NumberString( HexText, Head->Value, 16, 3 );
    if( fprintf( ListFile, "%s %s %s(%u)\n", HexText, Head->Symbol,
      Head->Loc.Name, Head->Loc.Line ) <= 0 )
        RunError( True, FileWriteError );
    if( *XrefYesCond )
      ListReference( Head->Refer );
    SymbPoint = NULL;
    if( Head->Right )
      ListSymbols( Head->Right );
  }
}

#if ANSI
  static PROC void ListDefines( SymbolPointer Head )
#else
  static PROC void ListDefines( Head )
  SymbolPointer Head;
#endif
{
  if( Head ) {
    if( Head->Left )
      ListDefines( Head->Left );
    if( Head->Value ) {
      if( fprintf( ListFile, "DEF %s\n", Head->Symbol ) <= 0 )
        RunError( True, FileWriteError );
    } else 
      if( fprintf( ListFile, "UND %s\n", Head->Symbol ) <= 0 )
        RunError( True, FileWriteError );
    if( Head->Right )
      ListDefines( Head->Right );
  }
}

#if ANSI
  static PROC void ListWarnings( void )
#else
  static PROC void ListWarnings()
#endif
{
  if( fprintf( stderr, "%s%u\n", WarningNumMessage, WarningCount ) <= 0 )
    RunError( True, FileWriteError );
  if( fprintf( ListFile, "%s%u\n", WarningNumMessage, WarningCount ) <= 0 )
    RunError( True, FileWriteError );
}

#if ANSI
  static PROC char *AssertSpace( SpaceRecord *Chain, unsigned int Size )
#else
  static PROC char *AssertSpace( Chain, Size )
  SpaceRecord *Chain;
  unsigned int Size;
#endif
{
  if( Chain ) {
    if( Chain->Request )
      RunError( True, SpaceAssertError );
    if( Size + sizeof( char * ) > Chain->Size )
      RunError( True, SpaceAssertError );
    if( !( Chain->Start )) {
      Chain->Start = ( char * )malloc( Chain->Size );
      if( !( Chain->Start ))
        RunError( True, AllocationError );
      Chain->Point = NULL;
    }
    if( !( Chain->Point )) {
      Chain->Point = Chain->Start;
      Chain->Index = NULL;
    }
    if( !( Chain->Index )) {
      *( char ** )Chain->Point = NULL;
      Chain->Index = Chain->Point + sizeof( char * );
    }
    if( Chain->Index + Size > Chain->Point + Chain->Size ) {
      char *This;

      This = ( char * )malloc( Chain->Size );
      if( !This )
        RunError( True, AllocationError );
      *( char ** )Chain->Point = This;
      Chain->Point = This;
      *( char ** )This = NULL;
      Chain->Index = This + sizeof( char * );
    }
  } else
    RunError( True, SpaceAssertError );
  Chain->Request = Size;
  return( Chain->Index );
}

#if ANSI
  static PROC void ClaimSpace( SpaceRecord *Chain, unsigned int Size )
#else
  static PROC void ClaimSpace( Chain, Size )
  SpaceRecord *Chain;
  unsigned int Size;
#endif
{
  if( Chain ) {
    if( !( Chain->Request ))
      RunError( True, SpaceAssertError );
    if( Size > Chain->Request )
      RunError( True, SpaceAssertError );
    Chain->Index += Size;
    Chain->Request = 0;
  } else
    RunError( True, SpaceAssertError );
}

#if ANSI
  static PROC void ReleaseSpace( SpaceRecord *Chain )
#else
  static PROC void ReleaseSpace( Chain )
  SpaceRecord *Chain;
#endif
{
  char *This;
  char *Next;

  if( Chain ) {
    if( Chain->Request )
      RunError( True, SpaceAssertError );
    for( This = Chain->Start; This; ) {
      Next = *( char ** )This;
      free( This );
      This = Next;
    }
    Chain->Start = NULL;
    Chain->Point = NULL;
    Chain->Index = NULL;
    Chain->Request = 0;
  } else
    RunError( True, SpaceAssertError );
}

#if ANSI
  static PROC char OpenFiles( int argc, char *argv[] )
#else
  static PROC char OpenFiles( argc, argv )
  int argc;
  char *argv[]; 
#endif
{
  if( argc >= 2 ) {
    strcpy( OutFileName, argv[ 1 ]);
    if( argc >= 3 )
      strcpy( InFileName, argv[ 2 ]);
    else {
      strcpy( InFileName, OutFileName );
      strcat( InFileName, InExtDefault );
    }
    if( !strcmp( InFileName, DefFileName )) {
      strcpy( InFileName, OutFileName );
      strcat( InFileName, InExtDefault );
    }
    if( !strcmp( InFileName, StdFileName )) 
      strcpy( InFileName, StdInFileName );
    if( argc >= 4 ) 
      strcpy( ListFileName, argv[ 3 ]);
    else {
      strcpy( ListFileName, OutFileName );
      strcat( ListFileName, ListExtDefault );
    }
    if( !strcmp( ListFileName, DefFileName )) {
      strcpy( ListFileName, OutFileName );
      strcat( ListFileName, ListExtDefault );
    }
    if( !strcmp( ListFileName, StdFileName )) 
      strcpy( ListFileName, StdOutFileName );
  } else
    RunError( True, NoTargetError );
  if( fprintf( stderr, "TargetFile: %s\n", OutFileName ) <= 0 )
    RunError( True, FileWriteError );
  OutFile = fopen( OutFileName, "w+b" );
  if( !OutFile )
    RunError( True, FileAccessError );
  if( fprintf( stderr, "SourceFile: %s\n", InFileName ) <= 0 )
    RunError( True, FileWriteError );
  if( strcmp( InFileName, StdInFileName ))
    InFile = fopen( InFileName, "r" );
  else 
    InFile = stdin;
  if( !InFile )
    RunError( True, NoSourceError );
  if( fprintf( stderr, "ListFile: %s\n", ListFileName ) <= 0 )
    RunError( True, FileWriteError );
  if( strcmp( ListFileName, StdOutFileName )) 
    ListFile = fopen( ListFileName, "w" );
  else
    ListFile = stdout;
  if( !ListFile )
    RunError( True, FileAccessError );
  fprintf( stderr, "\n" );
  if( fprintf( ListFile,
    "%s\n\nTargetFile: %s\nSourceFile: %s\nListFile: %s\n\n", CopyRight,
    OutFileName, InFileName, ListFileName ) <= 0 )
      RunError( True, FileWriteError );
  return( True );
}

#if ANSI
  static PROC void DefineReference( LocPointer Loc, ReferPointer *Head )
#else
  static PROC void DefineReference( Loc, Head )
  LocPointer Loc;
  ReferPointer *Head;
#endif
{
  ReferPointer This;
  ReferPointer Ref;
  ReferPointer Last;
  int Compare;

  if( Loc ) {
    This = ( ReferPointer )AssertSpace( &Space, sizeof( ReferRecord ));
    ClaimSpace( &Space, sizeof( ReferRecord ));
    This->Loc = *Loc;
    This->Next = NULL;
    for( Last = NULL, Ref = *Head; Ref; ) {
      Compare = strcmp( Loc->Name, Ref->Loc.Name );
      if( !Compare ) {
        if( Loc->Line < Ref->Loc.Line ) {
          This->Next = Ref;
          Ref = NULL;
        } else {
          Last = Ref;
          Ref = Ref->Next;
        }
      } else 
        if( Compare < 0 ) {
          This->Next = Ref;
          Ref = NULL;
        } else {
          Last = Ref;
          Ref = Ref->Next;
        }
    }
    if( !Last ) 
      *Head = This;
    else  
      if(( Loc->Line != Last->Loc.Line ) || ( Loc->Name != Last->Loc.Name )) 
        Last->Next = This;
  }
}

#if ANSI
  static PROC char *StripSymbol( char *Result, char *Symbol )
#else
  static PROC char *StripSymbol( Result, Symbol )
  char *Result;
  char *Symbol;
#endif
{
  if( *Symbol == SymbolChar ) 
    Symbol++;
  strncpy( Result, Symbol, SymbolLength );
  Result[ SymbolLength ] = NullChar;
  Symbol = Result + strlen( Result ) - 1;
  if( *Symbol == LabelChar )
    *Symbol = NullChar;
  return( Result );
}

#if ANSI
  static PROC char DefineSymbol( char *RawSymbol, long int Value,
    SymbolPointer *Head, LocPointer Loc )
#else
  static PROC char DefineSymbol( RawSymbol, Value, Head, Loc )
  char *RawSymbol;
  long int Value;
  SymbolPointer *Head;
  LocPointer Loc;
#endif
{
  SymbolString Symbol;
  SymbolPointer Symb;
  SymbolPointer Last;
  int Compare;

  StripSymbol( Symbol, RawSymbol );
  Compare = 0;
  Last = NULL;
  Symb = *Head;
  while( Symb ) {
    Compare = strcmp( Symbol, Symb->Symbol );
    if( !Compare ) {
      Symb->Value = Value;
      Symb->Expr = NULL;
      if( Loc ) 
        Symb->Loc = *Loc;
      else
        Symb->Loc = NullLocation; 
      if( Symb->Loc.Xref )
        DefineReference( &( Symb->Loc ), &( Symb->Refer ));
      CurrentSymbol = Symb;
      return( False );
    }
    Last = Symb;
    if( Compare <= 0 )
      Symb = Symb->Left;
    else
      Symb = Symb->Right;
  }
  Symb = ( SymbolPointer )AssertSpace( &Space, sizeof( SymbolRecord ));
  ClaimSpace( &Space, sizeof( SymbolRecord ));
  Symb->Symbol = ( char * )AssertSpace( &Space, sizeof( SymbolString ));
  strcpy( Symb->Symbol, Symbol );
  ClaimSpace( &Space, ( unsigned int )( strlen( Symb->Symbol ) + 1 ));
  Symb->Value = Value;
  Symb->Expr = NULL;
  if( Loc )
    Symb->Loc = *Loc;
  else
    Symb->Loc = NullLocation; 
  Symb->Refer = NULL;
  if( *UsedOnCond )
    DefineReference( &NullLocation, &( Symb->Refer ));
  Symb->Left = NULL;
  Symb->Right = NULL;
  if( !Last )
    *Head = Symb;
  else 
    if( Compare <= 0 )
      Last->Left = Symb;
    else
      Last->Right = Symb;
  CurrentSymbol = Symb;
  return( True );
}

#if ANSI
  static PROC char ResolveOption( char *Option, long int *YesNoPoint,
    long int *OnOffPoint )
#else
  static PROC char ResolveOption( Option, YesNoPoint, OnOffPoint )
  char *Option;
  long int *YesNoPoint;
  long int *OnOffPoint;
#endif
{
  char Result;

  Result = True;
  if( !strcmp( Option, OptionYesName )) {
    *YesNoPoint = Defined;
    Result = False;
  }
  if( !strcmp( Option, OptionNoName )) {
    *YesNoPoint = UnDefined;
    Result = False;
  }
  if( !strcmp( Option, OptionOnName )) {
    *OnOffPoint = Defined;
    Result = False;
  }
  if( !strcmp( Option, OptionOffName )) {
    *OnOffPoint = UnDefined;
    Result = False;
  }
  return( Result );
}

#if ANSI
  static PROC char ResolveSymbol( char *RawSymbol, long int *Value,
    SymbolPointer Head, LocPointer Loc )
#else
  static PROC char ResolveSymbol( RawSymbol, Value, Head, Loc )
  char *RawSymbol;
  long int *Value;
  SymbolPointer Head;
  LocPointer Loc;
#endif
{
  SymbolString Symbol;
  int Compare;
  char Result;

  Result = False;
  *Value = 0L;
  StripSymbol( Symbol, RawSymbol );
  while( Head ) {
    Compare = strcmp( Symbol, Head->Symbol );
    if( !Compare ) {
      *Value = Head->Value;
      if( Loc )
        if( Loc->Xref )
          DefineReference( Loc, &( Head->Refer ));
      if( !( Head->Expr ))
        Result = True;
      Head = NULL;
    } else {
      if( Compare <= 0 )
        Head = Head->Left;
      else
        Head = Head->Right;
    }
  }
  return( Result );
}

#if ANSI
  static PROC char ResolveNumber( char *Symbol, int Base, long int *Value )
#else
  static PROC char ResolveNumber( Symbol, Base, Value )
  char *Symbol;
  int Base;
  long int *Value;
#endif
{
  char *Digit;
  char Result;
  unsigned int Count;
  unsigned int Length;

  Result = True;
  if( !( *Symbol ))
    Result = False;
  *Value = 0L;
  Length = strlen( Symbol );
  for( Count = 1; Count <= Length; Count++ ) {
    Digit = strchr( DigitText, Symbol[ Count - 1 ]);
    if( !Digit ) {
      Result = False;
      Count = Length;
    } else {
      if(( Digit - DigitText ) >= MaxBaseLength ) 
        Digit = DigitText;
      if(( Digit - DigitText ) > Base ) {
        Result = False;
        Count = Length;
      } else
        *Value = Base * ( *Value ) + ( Digit - DigitText );
    }
  }
  return( Result );
}

#if ANSI
  static PROC char ResolveValue( char *Symbol, long int *Value,
    SymbolPointer Head, LocPointer Loc )
#else
  static PROC char ResolveValue( Symbol, Value, Head, Loc )
  char *Symbol;
  long int *Value;
  SymbolPointer Head;
  LocPointer Loc;
#endif
{
  char Result;

  Result = False;
  *Value = 0L;
  if(( Symbol[ 0 ] == AddressChar ) && !( Symbol[ 1 ]) && Loc ) {
    *Value = Loc->Addr;
    return( True );
  }
  switch( Symbol[ 0 ]) {
    case HexChar:
      Result = ResolveNumber( Symbol + 1, 16, Value );
      break;
    case BinChar:
      Result = ResolveNumber( Symbol + 1, 2, Value );
      break;
    case OctChar:
      Result = ResolveNumber( Symbol + 1, 8, Value );
      break;
    case AscChar:
      if( Symbol[ 1 ]) {
        *Value = Symbol[ 1 ];
        if( !( Symbol[ 2 ]))
        Result = True;
      }
      break;
    default:
      if( isdigit( Symbol[ 0 ]))
        Result = ResolveNumber( Symbol, 10, Value );
      else
        Result = ResolveSymbol( Symbol, Value, Head, Loc );
      break;
  }
  return( Result );
}

#if ANSI
  static PROC char *SplitParam( char *Result, char **Param )
#else
  static PROC char *SplitParam( Result, Param )
  char *Result;
  char **Param;
#endif
{
  char *Start;
  char *Count;
  char *Store;
  char Reading;

  Store = Result;
  *Store = NullChar;
  Reading = True;
  for( Start = NULL, Count = *Param; *Count; Count++ ) 
    if( isgraph( *Count )) {
      Start = Count;
      Count = NullString;
    }
  if( Start ) {
    Count = Start;
    if( Operators[ *Count ]) {
      *( Store++ ) = *Count;
      *( Store++ ) = NullChar; 
      *Param = Count + 1;
      Reading = False;
    } else 
      for( ; *Count; Count++ ) 
        if(( !isgraph( *Count )) || Operators[ *Count ]) {
          *Param = Count;
          Count = NullString;
          Reading = False;
        } else 
          *( Store++ ) = *Count;
  }
  if( Reading )
    *Param = NullString;
  *( Store++ ) = NullChar;
  return( Result );
}

#if ANSI
  static PROC char ResolveOperator( char *Symbol, char *Token, char *Legal )
#else
  static PROC char ResolveOperator( Symbol, Token, Legal )
  char *Symbol;
  char *Token;
  char *Legal;
#endif
{
  *Token = *Symbol;
  if(( *Token ) && strchr( Legal, *Token ))
    return( True ); 
  else
    return( False ); 
}

#if ANSI
  static PROC char ResolveSingle( char Token, long int *Value )
#else
  static PROC char ResolveSingle( Token, Value )
  char Token;
  long int *Value;
#endif
{
  char Result;

  Result = True;
  switch( Token ) {
    case PlusChar:
      /* Nothing to be done */
      break;
    case MinusChar:
      *Value = -( *Value );
      break;
    case NotChar:
      *Value = ~( *Value );
      break;
    default:
      Result = False;
      break;
  }
  return( Result );
}

#if ANSI
  static PROC char ResolveDouble( char Token, long int *Value,
    long int Operand )
#else
  static PROC char ResolveDouble( Token, Value, Operand )
  char Token;
  long int *Value;
  long int Operand;
#endif
{
  long int Count;
  long int This;
  char Result;

  Result = True;
  switch( Token ) {
    case PowerChar:
      This = 1;
      for( Count = 1; Count <= Operand; Count++ )
        This *= *Value;
      *Value = This;
      break;
    case ShlChar:
      *Value <<= Operand;
      break;
    case ShrChar:
      *Value >>= Operand;
      break;
    case MulChar:
      *Value *= Operand;
      break;
    case FracChar:
    case DivChar:
      *Value /= Operand;
      break;
    case PlusChar:
      *Value += Operand;
      break;
    case MinusChar:
      *Value -= Operand;
      break;
    case AndChar:
      *Value &= Operand;
      break;
    case OrChar:
      *Value |= Operand;
      break;
    case XorChar:
      *Value ^= Operand;
      break;
    case ModChar:
      *Value %= Operand;
      break;
    default:
      Result = False;
      break;
  }
  return( Result );
}

#if ANSI
  static PROC char ResolveParent( char *Symbol, char **Param, long int *Value,
    SymbolPointer Head, LocPointer Loc )
#else
  static PROC char ResolveParent( Symbol, Param, Value, Head, Loc )
  char *Symbol;
  char **Param;
  long int *Value;
  SymbolPointer Head;
  LocPointer Loc;
#endif
{
  char Token;
  char Status;

  if( ResolveOperator( Symbol, &Token, StartOperator )) {
    SplitParam( Symbol, Param );
    Status = ResolveDivMod( Symbol, Param, Value, Head, Loc );
    if( !ResolveOperator( Symbol, &Token, StopOperator ))
      Status = False;
    SplitParam( Symbol, Param );
  } else {
    Status = ResolveValue( Symbol, Value, Head, Loc );
    SplitParam( Symbol, Param );
  }
  return( Status );
}

#if ANSI
  static PROC char ResolveUnary( char *Symbol, char **Param, long int *Value,
    SymbolPointer Head, LocPointer Loc )
#else
  static PROC char ResolveUnary( Symbol, Param, Value, Head, Loc )
  char *Symbol;
  char **Param;
  long int *Value;
  SymbolPointer Head;
  LocPointer Loc;
#endif
{
  char Token;
  char Status;

  if( ResolveOperator( Symbol, &Token, UnaryOperator )) {
    SplitParam( Symbol, Param );
    Status = ResolveParent( Symbol, Param, Value, Head, Loc );
    Status = Status & ResolveSingle( Token, Value );
  } else
    Status = ResolveParent( Symbol, Param, Value, Head, Loc );
  return( Status );
}

#if ANSI
  static PROC char ResolvePower( char *Symbol, char **Param, long int *Value,
    SymbolPointer Head, LocPointer Loc )
#else
  static PROC char ResolvePower( Symbol, Param, Value, Head, Loc )
  char *Symbol;
  char **Param;
  long int *Value;
  SymbolPointer Head;
  LocPointer Loc;
#endif
{
  long int Operand;
  char Token;
  char Status;

  Operand = 0L;
  Status = ResolveUnary( Symbol, Param, Value, Head, Loc );
  while( ResolveOperator( Symbol, &Token, PowerOperator )) {
    SplitParam( Symbol, Param );
    Status = Status & ResolveUnary( Symbol, Param, &Operand, Head, Loc );
    Status = Status & ResolveDouble( Token, Value, Operand );
  }
  return( Status );
}

#if ANSI
  static PROC char ResolveMulDiv( char *Symbol, char **Param, long int *Value,
    SymbolPointer Head, LocPointer Loc )
#else
  static PROC char ResolveMulDiv( Symbol, Param, Value, Head, Loc )
  char *Symbol;
  char **Param;
  long int *Value;
  SymbolPointer Head;
  LocPointer Loc;
#endif
{
  long int Operand;
  char Token;
  char Status;

  Operand = 0L;
  Status = ResolvePower( Symbol, Param, Value, Head, Loc );
  while( ResolveOperator( Symbol, &Token, MulDivOperator )) {
    SplitParam( Symbol, Param );
    Status = Status & ResolvePower( Symbol, Param, &Operand, Head, Loc );
    Status = Status & ResolveDouble( Token, Value, Operand );
  }
  return( Status );
}

#if ANSI
  static PROC char ResolvePlusMinus( char *Symbol, char **Param,
    long int *Value, SymbolPointer Head, LocPointer Loc )
#else
  static PROC char ResolvePlusMinus( Symbol, Param, Value, Head, Loc )
  char *Symbol;
  char **Param;
  long int *Value;
  SymbolPointer Head;
  LocPointer Loc;
#endif
{
  long int Operand;
  char Token;
  char Status;

  Operand = 0L;
  Status = ResolveMulDiv( Symbol, Param, Value, Head, Loc );
  while( ResolveOperator( Symbol, &Token, PlusMinusOperator )) {
    SplitParam( Symbol, Param );
    Status = Status & ResolveMulDiv( Symbol, Param, &Operand, Head, Loc );
    Status = Status & ResolveDouble( Token, Value, Operand );
  }
  return( Status );
}

#if ANSI
  static PROC char ResolveBitWise( char *Symbol, char **Param, long int *Value,
    SymbolPointer Head, LocPointer Loc )
#else
  static PROC char ResolveBitWise( Symbol, Param, Value, Head, Loc )
  char *Symbol;
  char **Param;
  long int *Value;
  SymbolPointer Head;
  LocPointer Loc;
#endif
{
  long int Operand;
  char Token;
  char Status;

  Operand = 0L;
  Status = ResolvePlusMinus( Symbol, Param, Value, Head, Loc );
  while( ResolveOperator( Symbol, &Token, BitWiseOperator )) {
    SplitParam( Symbol, Param );
    Status = Status & ResolvePlusMinus( Symbol, Param, &Operand, Head, Loc );
    Status = Status & ResolveDouble( Token, Value, Operand );
  }
  return( Status );
}

#if ANSI
  static PROC char ResolveDivMod( char *Symbol, char **Param, long int *Value,
    SymbolPointer Head, LocPointer Loc )
#else
  static PROC char ResolveDivMod( Symbol, Param, Value, Head, Loc )
  char *Symbol;
  char **Param;
  long int *Value;
  SymbolPointer Head;
  LocPointer Loc;
#endif
{
  long int Operand;
  char Token;
  char Status;

  Operand = 0L;
  Status = ResolveBitWise( Symbol, Param, Value, Head, Loc );
  while( ResolveOperator( Symbol, &Token, DivModOperator )) {
    SplitParam( Symbol, Param );
    Status = Status & ResolveBitWise( Symbol, Param, &Operand, Head, Loc );
    Status = Status & ResolveDouble( Token, Value, Operand );
  }
  return( Status );
}

#if ANSI
  static PROC char ResolveExpression( char **Param, long int *Value,
    SymbolPointer Head, LocPointer Loc )
#else
  static PROC char ResolveExpression( Param, Value, Head, Loc )
  char **Param;
  long int *Value;
  SymbolPointer Head;
  LocPointer Loc;
#endif
{
  SymbolString Symbol;
  char Result;

  Result = False;
  *Value = 0L;
  SplitParam( Symbol, Param );
  if( *Symbol )
    Result = ResolveDivMod( Symbol, Param, Value, Head, Loc );
  if( *Symbol )
    return( False );
  else
    return( Result );
}

#if ANSI
  static PROC void MissingEquations( SymbolPointer Head )
#else
  static PROC void MissingEquations( Head )
  SymbolPointer Head;
#endif
{
  if( Head ) {
    MissingEquations( Head->Left );
    if( Head->Expr ) {
      SymbPoint = Head;
      RunError( False, UndefinedWarning );
      SymbPoint = NULL;
    }
    MissingEquations( Head->Right ); 
  }
}

#if ANSI
  static PROC unsigned int ResolveTraversal( SymbolPointer Symb,
    SymbolPointer Head )
#else
  static PROC unsigned int ResolveTraversal( Symb, Head )
  SymbolPointer Symb;
  SymbolPointer Head;
#endif
{
  char *Expression;
  long int Value;
  unsigned int Count;

  Count = 0;
  if( Symb ) {
    if( Symb->Expr ) {
      Expression = Symb->Expr;
      if( ResolveExpression( &Expression, &Value, Head, &( Symb->Loc ))) {
        Symb->Value = Value;
        Symb->Expr = NULL; 
      } else
        Count++;
    }
    Count += ResolveTraversal( Symb->Left, Head );
    Count += ResolveTraversal( Symb->Right, Head ); 
  }
  return( Count );
}

#if ANSI
  static PROC void ResolveEquations( SymbolPointer Head )
#else
  static PROC void ResolveEquations( Head )
  SymbolPointer Head;
#endif
{
  unsigned int Count;
  unsigned int Remains;

  Count = 0;
  do {
    Remains = Count;
    Count = ResolveTraversal( Head, Head );
  } while( Count && ( Count != Remains ));
  if( Count ) 
    MissingEquations( Head );
}

#if ANSI
  static PROC void StoreSymbolList( SymbolString SymbolText[],
    unsigned int Min, unsigned int Max, SymbolPointer *DirHead )
#else
  static PROC void StoreSymbolList( SymbolText, Min, Max, DirHead )
  SymbolString SymbolText[];
  unsigned int Min;
  unsigned int Max;
  SymbolPointer *DirHead;
#endif
{
  unsigned int This;

  This = Min + (( Max - Min ) >> 1 );
  if( !DefineSymbol( SymbolText[ This ], ( long int )This, DirHead,
    &NullLocation ))
      RunError( False, CopySymbolWarning );
  if( This != Min )
    StoreSymbolList( SymbolText, Min, This - 1, DirHead );
  if( This != Max )
    StoreSymbolList( SymbolText, This + 1, Max, DirHead );
}

#if ANSI
  static PROC char *SplitLine( char *Result, char **Line, char AbortFlag )
#else
  static PROC char *SplitLine( Result, Line, AbortFlag )
  char *Result;
  char **Line;
  char AbortFlag;
#endif
{
  char *Start;
  char *Count;
  char *Store;
  int Level;
  char TextFlag;
  char Reading;

  Store = Result;
  *Store = NullChar;
  Level = 0;
  TextFlag = False;
  Reading = True;
  for( Start = NULL, Count = *Line; *Count; Count++ ) 
    if( *Count == RemarkChar )
      Count = NullString;
    else 
      if( isgraph( *Count ) && ( *Count != SeparatorChar )) {
        Start = Count;
        Count = NullString;
      }
  if( Start ) 
    for( Count = Start; *Count && ( Count < Start + ParamLength ); Count++ ) 
      if( *Count == TextChar ) {
        if( Count != Start )
          if( *( Count - 1 ) == TextChar ) 
            *( Store++ ) = TextChar;
        TextFlag = ( char )~TextFlag;
      } else
        if( TextFlag ) 
          *( Store++ ) = *Count;
        else
          switch( *Count ) {
            case SeparatorChar:
              if( !Level ) {
                *Line = Count;
                Reading = False;
                Count = NullString;
              } else 
                *( Store++ ) = *Count;
              break;
            case RemarkChar:
              *Line = NullString;
              Reading = False;
              Count = NullString;
              break;
            case StartChar:
              Level++;
              *( Store++ ) = *Count;
              break;
            case StopChar:
              Level--;
              *( Store++ ) = *Count;
              break;
            default:
              if( isgraph( *Count )) 
                *( Store++ ) = ( char )toupper(( int )( *Count ));
              else
                if( AbortFlag && ( !Level )) {
                  *Line = Count;
                  Reading = False;
                  Count = NullString;
                } else
                  if( Store != Result )
                   if( *( Store - 1 ) != SpaceChar )
                     *( Store++ ) = SpaceChar; 
              break;
          }
  if( Reading )
    *Line = NullString;
  if( Store != Result )
    *( Store-- ) = NullChar;
  while( *Store == SpaceChar ) 
    if( Store > Result )
      *( Store-- ) = NullChar;
    else
      *Store = NullChar;
  return( Result );
}

#if ANSI
  static PROC void AlignWordBounds( void )
#else
  static PROC void AlignWordBounds()
#endif
{
  if( *AlignOnCond )
    Location.Addr = (( Location.Addr + 1 ) >> 1 ) << 1;
  if( Location.Addr > FinalAddress )
    FinalAddress = Location.Addr;
  if(( Location.Addr < StartAddress ) || ( Location.Addr > StopAddress ))
    RunError( True, BoundsError );
}

#if ANSI
  static PROC char ParamCheck( unsigned int Count, unsigned int Min,
    unsigned int Max )
#else
  static PROC char ParamCheck( Count, Min, Max )
  unsigned int Count;
  unsigned int Min;
  unsigned int Max;
#endif
{
  if(( Count < Min ) || ( Count > Max ))
    RunError( False, ParamCountWarning );
  if( Count >= Min )
    return( True );
  else
    return( False );
}

#if ANSI
  static PROC char RangeCheck( long int Value, long int Min, long int Max,
    char *Message )
#else
  static PROC char RangeCheck( Value, Min, Max, Message )
  long int Value;
  long int Min;
  long int Max;
  char *Message;
#endif
{
  if(( Value < Min ) || ( Value > Max )) {
    RunError( False, Message );
    return( True );
  } else
    return( False );
}

#if ANSI
  static PROC char DecodeOption( char *Option )
#else
  static PROC char DecodeOption( Option )
  char *Option;
#endif
{
  char Result;

  Result = True;
  if( !strcmp( Option, Chip8Name )) {
    *Chip8Cond = Defined;
    *Chip48Cond = Defined;
    *Super10Cond = UnDefined;
    *Super11Cond = UnDefined;
    *HpHeadCond = UnDefined;
    *HpAscCond = UnDefined;
    Result = False;
  }
  if( !strcmp( Option, Chip48Name )) {
    *Chip8Cond = UnDefined;
    *Chip48Cond = Defined;
    *Super10Cond = UnDefined;
    *Super11Cond = UnDefined;
    *HpHeadCond = Defined;
    Result = False;
  }
  if( !strcmp( Option, Super10Name )) {
    *Chip8Cond = UnDefined;
    *Chip48Cond = UnDefined;
    *Super10Cond = Defined;
    *Super11Cond = UnDefined;
    *HpHeadCond = Defined;
    Result = False;
  }
  if( !strcmp( Option, Super11Name )) {
    *Chip8Cond = UnDefined;
    *Chip48Cond = UnDefined;
    *Super10Cond = Defined;
    *Super11Cond = Defined;
    *HpHeadCond = Defined;
    Result = False;
  }
  if( !strcmp( Option, HpBinName )) {
    *HpHeadCond = Defined;
    *HpAscCond = UnDefined;
    Result = False;
  }
  if( !strcmp( Option, HpAscName )) {
    *HpHeadCond = Defined;
    *HpAscCond = Defined;
    Result = False;
  }
  if( !strcmp( Option, BinaryName )) {
    *HpHeadCond = UnDefined;
    *HpAscCond = UnDefined;
    Result = False;
  }
  if( !strcmp( Option, StringName )) {
    *HpHeadCond = UnDefined;
    *HpAscCond = Defined;
    Result = False;
  }
  return( Result );
}

#if ANSI
  static PROC unsigned int DecodeParameters( char **Line, ParamPointer *Head )
#else
  static PROC unsigned int DecodeParameters( Line, Head )
  char **Line;
  ParamPointer *Head;
#endif
{
  ParamString FoundWord;
  ParamPointer Param;
  ParamPointer Last;
  unsigned int Count;

  *Head = NULL;
  Count = 0;
  for( Last = NULL; **Line; )
    if( *SplitLine( FoundWord, Line, False )) {
      Param = ( ParamPointer )AssertSpace( &Space, sizeof( ParamRecord ));
      ClaimSpace( &Space, sizeof( ParamRecord ));
      Param->Param = ( char * )AssertSpace( &Space, sizeof( ParamString ));
      strcpy( Param->Param, FoundWord );
      ClaimSpace( &Space, ( unsigned int )( strlen( Param->Param ) + 1 ));
      Param->Next = NULL;
      if( Last )
        Last->Next = Param;
      else
        *Head = Param;
      Last = Param;
      Count++;
    }
  return( Count );
}

#if ANSI
  static PROC void DecodeDirective( unsigned int Token, char **Line,
    InstPointer *Head, SymbolPointer Dir, SymbolPointer *Symb,
    SymbolPointer *Cond )
#else
  static PROC void DecodeDirective( Token, Line, Head, Dir, Symb, Cond )
  unsigned int Token;
  char **Line;
  InstPointer *Head;
  SymbolPointer Dir;
  SymbolPointer *Symb;
  SymbolPointer *Cond;
#endif
{
  ParamPointer Params;
  InstPointer Inst;
  unsigned int Count;

  Count = DecodeParameters( Line, &Params );
  switch( Token ) {
    case ElseToken:
      ParamCheck( Count, 0, 0 );
      if( StackPoint == StackStart ) 
        RunError( False, MissingIfdefWarning );
      else 
        *StackPoint = ( char )~( *StackPoint );
      break;
    case EndifToken:
      ParamCheck( Count, 0, 0 );
      if( StackPoint <= StackStart ) 
        RunError( False, MissingIfdefWarning );
      else 
        StackPoint--;
      break;
    case IfdefToken:
    case IfundToken:
      if( ParamCheck( Count, 1, 1 )) {
        long int Value;

        if( !ResolveSymbol( Params->Param, &Value, *Cond, &NullLocation ))
          Value = 0L;
        if( Token == IfundToken )
          Value = ~Value;
        if( StackPoint >= StackStart + StackLength ) 
          RunError( True, NestedIfdefError );
        else 
          if( Value ) 
            *( ++StackPoint ) = True;
          else
            *( ++StackPoint ) = False;
      }
      break;
    default:
      if( *StackPoint ) {
        switch( Token ) {
          case WrongToken:
            RunError( False, InternalWarning );
            break;
          case AlignToken:
            if( ParamCheck( Count, 1, 1 )) 
              if( ResolveOption( Params->Param, AlignOnCond, AlignOnCond ))
                RunError( False, NoOptionWarning );
            break;
          case DefineToken:
          case UndefToken:
            if( ParamCheck( Count, 1, 1 )) 
              if( Token == DefineToken )
                DefineSymbol( Params->Param, Defined, Cond, &NullLocation );
              else
                DefineSymbol( Params->Param, UnDefined, Cond,
                  &NullLocation );
            break;
          case EqualToken:
          case EquToken:
            if( !CurrentSymbol )
              RunError( False, MissingSymbolWarning );
            else 
              if( ParamCheck( Count, 1, 1 )) {
                char *Expression;

                Expression = ( char * )AssertSpace( &Space,
                  sizeof( ParamString ));
                CurrentSymbol->Expr = strcpy( Expression, Params->Param );
                ClaimSpace( &Space, ( unsigned int )
                  ( strlen( Expression ) + 1 ));
              }
            break;
          case DsToken:
            if( ParamCheck( Count, 1, 1 )) {
              char *FirstParam;
              long int Value;

              FirstParam = Params->Param;
              if( !ResolveExpression( &FirstParam, &Value, *Symb, &Location ))
                RunError( False, UndefinedWarning );
              Location.Addr += Value;
            }
            break;
          case OptionToken:
            if( ParamCheck( Count, 1, 1 )) 
              if( DecodeOption( Params->Param ))
                RunError( False, NoOptionWarning );
            break;
          case OrgToken:
            if( ParamCheck( Count, 1, 1 )) {
              char *FirstParam;
              long int Value;

              FirstParam = Params->Param;
              if( ResolveExpression( &FirstParam, &Value, *Symb, &Location ))
                Location.Addr = Value;
              else
                RunError( False, UndefinedWarning );
            }
            break;
          case IncludeToken:
            if( ParamCheck( Count, 1, 1 )) {
              FILE *StoreFile;
              LocRecord StoreLoc;
              char *IncludeName;

              StoreFile = InFile; 
              StoreLoc = Location;
              for( IncludeName = Params->Param; *IncludeName; IncludeName++ )
                *IncludeName = ( char )tolower(( int )( *IncludeName ));
              IncludeName = ( char * )AssertSpace( &Space,
                sizeof( LineString ));
              strcpy( IncludeName, Params->Param );
              ClaimSpace( &Space, ( unsigned int )
                ( strlen( IncludeName ) + 1 ));
              InFile = fopen( IncludeName, "r" );
              if( !InFile )
                RunError( True, NoSourceError );
              DecodeFile( IncludeName, Head, Dir, Symb, Cond );
              InFile = StoreFile;
              Location = StoreLoc;
              if( fprintf( stderr, "Reading: %s\n\n", Location.Name ) <= 0 )
                RunError( True, FileWriteError );
              if( fprintf( ListFile, "Reading: %s\n\n", Location.Name ) <= 0 )
                RunError( True, FileWriteError );
            }
            break;
          case EndToken:
            ParamCheck( Count, 0, 0 );
            /* The END directive is ignored */
            break;
          case UsedToken:
            if( ParamCheck( Count, 1, ListLength )) 
              if( ResolveOption( Params->Param, UsedYesCond, UsedOnCond )) {
                ParamPointer Point;
                long int Value;
      
                for( Point = Params; Point; Point = Point->Next ) 
                  if( *XrefOnCond ) {
                    if( !ResolveSymbol( Point->Param, &Value, *Symb,
                      &Location ))
                        if( !Value )
                          RunError( False, NoSymbolWarning );
                  } else
                    if( !ResolveSymbol( Point->Param, &Value, *Symb,
                      &UsedLocation ))
                        if( !Value )
                          RunError( False, NoSymbolWarning );
              } else
                if( Count > 1 )
                  RunError( False, ParamCountWarning );
            break;
          case XrefToken:
            if( ParamCheck( Count, 1, 1 )) 
              if( ResolveOption( Params->Param, XrefYesCond, XrefOnCond ))
                RunError( False, NoOptionWarning );
            break;
          default:
            Inst = ( InstPointer )AssertSpace( &Space, sizeof( InstRecord ));
            ClaimSpace( &Space, sizeof( InstRecord ));
            Inst->Loc = Location;
            Inst->Token = Token;
            Inst->Count = Count;
            Inst->Params = Params;
            Inst->Next = NULL;
            if( *Head ) 
              ( *Head )->Next = Inst;
            else
              Instructions = Inst;
            *Head = Inst;
            switch( Token ) {
              case DbToken:
                if( ParamCheck( Count, 1, ListLength ))
                  Location.Addr += Count;
                break;
              case DwToken:
                if( ParamCheck( Count, 1, ListLength ))
                  Location.Addr += Count * 2;
                break;
              case DaToken:
                if( ParamCheck( Count, 1, 1 ))
                  Location.Addr += strlen( Params->Param );
                break;
              default:
                Location.Addr += 2;
                break;
            }
          break;
        }
      }
      break;
  }
}

#if ANSI
  static PROC void DecodeLine( char **Line, InstPointer *Head,
    SymbolPointer Dir, SymbolPointer *Symb, SymbolPointer *Cond )
#else
  static PROC void DecodeLine( Line, Head, Dir, Symb, Cond )
  char **Line;
  InstPointer *Head;
  SymbolPointer Dir;
  SymbolPointer *Symb;
  SymbolPointer *Cond;
#endif
{
  ParamString Split;
  long int Value;

  CurrentSymbol = NULL;
  while( **Line ) 
    if( *SplitLine( Split, Line, True )) 
      if( !ResolveSymbol( Split, &Value, Dir, &NullLocation )) {
        if( *StackPoint )
          if( CurrentSymbol ) {
            RunError( False, DualSymbolWarning );
            *Line = NullString;
          } else 
            if( !DefineSymbol( Split, Location.Addr, Symb, &Location ))
              RunError( False, CopySymbolWarning );
      } else {
        DecodeDirective(( unsigned int )Value, Line, Head, Dir, Symb, Cond );
        AlignWordBounds();
        *Line = NullString;
      }
  CurrentSymbol = NULL;
}

#if ANSI
  static PROC void DecodeFile( char *FileName, InstPointer *Head,
    SymbolPointer Dir, SymbolPointer *Symb, SymbolPointer *Cond )
#else
  static PROC void DecodeFile( FileName, Head, Dir, Symb, Cond )
  char *FileName;
  InstPointer *Head;
  SymbolPointer Dir;
  SymbolPointer *Symb;
  SymbolPointer *Cond;
#endif
{
  char *StoreStack;
  char *Line;

  StoreStack = StackPoint;
  if( fprintf( stderr, "Reading: %s\n\n", FileName ) <= 0 )
    RunError( True, FileWriteError );
  if( fprintf( ListFile, "Reading: %s\n\n", FileName ) <= 0 )
    RunError( True, FileWriteError );
  Location.Text = ( char * )AssertSpace( &Space, sizeof( LineString ));
  *( Location.Text ) = NullChar;
  Location.Name = FileName;
  Location.Line = 1;
  while( fgets( Location.Text, LineLength + 1, InFile )) {
    ClaimSpace( &Space, ( unsigned int )( strlen( Location.Text ) + 1 ));
    if( *XrefOnCond )
      Location.Xref = True;
    else
      Location.Xref = False;
    for( Line = Location.Text; *Line; Line++ )
      if( iscntrl( *Line ))
        *Line = SpaceChar;
    Line = Location.Text;
    DecodeLine( &Line, Head, Dir, Symb, Cond );
    Location.Text = ( char * )AssertSpace( &Space, sizeof( LineString ));
    *( Location.Text ) = NullChar;
    Location.Line++;
  }
  strcpy( Location.Text, EndOfFileMessage );
  ClaimSpace( &Space, ( unsigned int )( strlen( Location.Text ) + 1 ));
  if( StoreStack != StackPoint )
    RunError( False, CountDefineWarning );
  if( InFile )
    if( InFile != stdin )
      fclose( InFile );
  InFile = NULL;
  Location = NullLocation;
}

#if ANSI
  static PROC void EncodeNoneToken( InstPointer Inst, long int OpCode,
    long int *Ver10, long int *Ver11 )
#else
  static PROC void EncodeNoneToken( Inst, OpCode, Ver10, Ver11 )
  InstPointer Inst;
  long int OpCode;
  long int *Ver10;
  long int *Ver11;
#endif
{
  ParamCheck( Inst->Count, 0, 0 );
  /* Generate instruction anyway */
  if( !( *Ver11 ))
    RunError( False, NeedsSuper11Warning );
  if( !( *Ver10 ))
    RunError( False, NeedsSuper10Warning );
  Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
    (( OpCode & 0xff00L ) >> 8 );
  Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
    ( OpCode & 0xffL );
  ListInstruction( Inst->Loc.Addr, 2, Inst );
}

#if ANSI
  static PROC void EncodeValToken( InstPointer Inst, long int OpCode,
    long int Limit, SymbolPointer Symb, long int *Ver8, long int *Ver11 )
#else
  static PROC void EncodeValToken( Inst, OpCode, Limit, Symb, Ver8, Ver11 )
  InstPointer Inst;
  long int OpCode;
  long int Limit;
  SymbolPointer Symb;
  long int *Ver8; 
  long int *Ver11;
#endif
{
  long int Value;

  Value = 0L;
  if( ParamCheck( Inst->Count, 1, 1 )) {
    char *FirstParam;

    FirstParam = Inst->Params->Param;
    if( !ResolveExpression( &FirstParam, &Value, Symb, &( Inst->Loc )))
      RunError( False, UndefinedWarning );
  }
  if( RangeCheck( Value, 0L, Limit, RangeWarning ))
    Value &= Limit;
  if( !( *Ver11 ))
    RunError( False, NeedsSuper11Warning );
  if( !( *Ver8 ))
    RunError( False, NeedsChip8Warning );
  Value |= OpCode;
  Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
    (( Value & 0xff00L ) >> 8 );
  Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
    ( Value & 0xffL );
  ListInstruction( Inst->Loc.Addr, 2, Inst );
}

#if ANSI
  static PROC void EncodeRegToken( InstPointer Inst, long int OpCode,
    SymbolPointer Reg )
#else
  static PROC void EncodeRegToken( Inst, OpCode, Reg )
  InstPointer Inst;
  long int OpCode;
  SymbolPointer Reg;
#endif
{
  long int RegX;

  RegX = ( long int )V0Reg;
  if( ParamCheck( Inst->Count, 1, 1 )) {
    if( ResolveSymbol( Inst->Params->Param, &RegX, Reg, &NullLocation ))
      RegX -= V0Reg;
    else
      RunError( False, NoRegisterWarning );
  }
  if( RangeCheck( RegX, 0L, NibbleMask, BadRegisterWarning ))
    RegX = 0L;
  RegX = OpCode | ( RegX << 8 );
  Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
    (( RegX & 0xff00L ) >> 8 );
  Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
    ( RegX & 0xffL );
  ListInstruction( Inst->Loc.Addr, 2, Inst );
}

#if ANSI
  static PROC void EncodeRegValToken( InstPointer Inst, long int OpCode,
    SymbolPointer Reg, SymbolPointer Symb )
#else
  static PROC void EncodeRegValToken( Inst, OpCode, Reg, Symb )
  InstPointer Inst;
  long int OpCode;
  SymbolPointer Reg;
  SymbolPointer Symb;
#endif
{
  long int RegX;
  long int Value;

  RegX = ( long int )V0Reg;
  Value = 0L;
  if( Inst->Count >= 1 ) 
    if( ResolveSymbol( Inst->Params->Param, &RegX, Reg, &NullLocation ))
      RegX -= V0Reg;
    else
      RunError( False, NoRegisterWarning );
  if( RangeCheck( RegX, 0L, NibbleMask, BadRegisterWarning ))
    RegX = 0L;
  if( ParamCheck( Inst->Count, 2, 2 )) {
    char *SecondParam;

    SecondParam = Inst->Params->Next->Param;
    if( !ResolveExpression( &SecondParam, &Value, Symb, &( Inst->Loc )))
      RunError( False, UndefinedWarning );
  }
  if( RangeCheck( Value, 0L, ByteMask, RangeWarning ))
    Value &= ByteMask;
  Value |= OpCode | ( RegX << 8 );
  Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
    (( Value & 0xff00L ) >> 8 );
  Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
    ( Value & 0xffL );
  ListInstruction( Inst->Loc.Addr, 2, Inst );
}

#if ANSI
  static PROC void EncodeRegRegToken( InstPointer Inst, long int OpCode,
    unsigned int Min, SymbolPointer Reg )
#else
  static PROC void EncodeRegRegToken( Inst, OpCode, Min, Reg )
  InstPointer Inst;
  long int OpCode;
  unsigned int Min;
  SymbolPointer Reg;
#endif
{
  long int RegX;
  long int RegY;

  RegX = ( long int )V0Reg;
  RegY = 0L;
  if( ParamCheck( Inst->Count, Min, 2 )) 
    if( ResolveSymbol( Inst->Params->Param, &RegX, Reg, &NullLocation ))
      RegX -= V0Reg;
    else
      RunError( False, NoRegisterWarning );
  if( RangeCheck( RegX, 0L, NibbleMask, BadRegisterWarning ))
    RegX = 0L;
  if( Inst->Count >= 2 ) 
    if( ResolveSymbol( Inst->Params->Next->Param, &RegY, Reg, &NullLocation ))
      RegY -= V0Reg;
    else
      RunError( False, NoRegisterWarning );
  if( RangeCheck( RegY, 0L, NibbleMask, BadRegisterWarning ))
    RegY = 0L;
  RegX = OpCode | ( RegX << 8 ) | ( RegY << 4 );
  Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
    (( RegX & 0xff00L ) >> 8 );
  Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
    ( RegX & 0xffL );
  ListInstruction( Inst->Loc.Addr, 2, Inst );
}

#if ANSI
  static PROC void EncodeRegRegOrValToken( InstPointer Inst, long int OpCode1,
    long int OpCode2, SymbolPointer Reg, SymbolPointer Symb )
#else
  static PROC void EncodeRegRegOrValToken( Inst, OpCode1, OpCode2, Reg, Symb )
  InstPointer Inst;
  long int OpCode1;
  long int OpCode2;
  SymbolPointer Reg;
  SymbolPointer Symb;
#endif
{
  long int RegX;
  long int RegY;
  long int Value;

  RegX = ( long int )V0Reg;
  RegY = ( long int )V0Reg;
  Value = 0L;
  if( Inst->Count >= 1 ) 
    if( ResolveSymbol( Inst->Params->Param, &RegX, Reg, &NullLocation ))
      RegX -= V0Reg;
    else
      RunError( False, NoRegisterWarning );
  if( RangeCheck( RegX, 0L, NibbleMask, BadRegisterWarning ))
    RegX = 0L;
  if( ParamCheck( Inst->Count, 2, 2 ))
    if( ResolveSymbol( Inst->Params->Next->Param, &RegY, Reg,
      &NullLocation )) {
        RegY -= V0Reg;
        if( RangeCheck( RegY, 0L, NibbleMask, BadRegisterWarning ))
          RegY = 0L;
        Value = OpCode1 | ( RegX << 8 ) | ( RegY << 4 );
        Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
          (( Value & 0xff00L ) >> 8 );
        Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
          ( Value & 0xffL );
        ListInstruction( Inst->Loc.Addr, 2, Inst );
      } else {
        char *SecondParam;

        SecondParam = Inst->Params->Next->Param; 
        if( !ResolveExpression( &SecondParam, &Value, Symb, &( Inst->Loc )))
          RunError( False, UndefinedWarning );
        if( RangeCheck( Value, 0L, ByteMask, RangeWarning ))
          Value &= ByteMask;
        Value |= OpCode2 | ( RegX << 8 );
        Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
          (( Value & 0xff00L ) >> 8 );
        Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
          ( Value & 0xffL );
        ListInstruction( Inst->Loc.Addr, 2, Inst );
      }
}

#if ANSI
  static PROC void EncodeDrwToken( InstPointer Inst, long int OpCode,
    SymbolPointer Reg, SymbolPointer Symb )
#else
  static PROC void EncodeDrwToken( Inst, OpCode, Reg, Symb )
  InstPointer Inst;
  long int OpCode;
  SymbolPointer Reg;
  SymbolPointer Symb;
#endif
{
  long int RegX;
  long int RegY;
  long int Value;

  RegX = ( long int )V0Reg;
  RegY = ( long int )V0Reg;
  Value = 0L;
  if( Inst->Count >= 1 ) 
    if( ResolveSymbol( Inst->Params->Param, &RegX, Reg, &NullLocation ))
      RegX -= V0Reg;
    else
      RunError( False, NoRegisterWarning );
  if( RangeCheck( RegX, 0L, NibbleMask, BadRegisterWarning ))
    RegX = 0L;
  if( Inst->Count >= 2 ) 
    if( ResolveSymbol( Inst->Params->Next->Param, &RegY, Reg, &NullLocation ))
      RegY -= V0Reg;
    else
      RunError( False, NoRegisterWarning );
  if( RangeCheck( RegY, 0L, NibbleMask, BadRegisterWarning ))
    RegY = 0L;
  if( ParamCheck( Inst->Count, 3, 3 )) {
    char *ThirdParam;

    ThirdParam = Inst->Params->Next->Next->Param;
    if( !ResolveExpression( &ThirdParam, &Value, Symb, &( Inst->Loc )))
      RunError( False, UndefinedWarning );
  }
  if( RangeCheck( Value, 0L, NibbleMask, RangeWarning ))
    Value &= NibbleMask;
  if(( Value == 0L ) && !( *Super10Cond ))
    RunError( False, NeedsSuper10Warning );
  Value |= OpCode | ( RegX << 8 ) | ( RegY << 4 );
  Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
    (( Value & 0xff00L ) >> 8 );
  Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
    ( Value & 0xffL );
  ListInstruction( Inst->Loc.Addr, 2, Inst );
}

#if ANSI
  static PROC void EncodeAddToken( InstPointer Inst, SymbolPointer Reg,
    SymbolPointer Symb )
#else
  static PROC void EncodeAddToken( Inst, Reg, Symb )
  InstPointer Inst;
  SymbolPointer Reg;
  SymbolPointer Symb;
#endif
{
  long int RegX;
  long int RegY;
  long int Value;

  RegX = ( long int )V0Reg;
  RegY = ( long int )V0Reg;
  Value = 0L;
  if( Inst->Count >= 1 ) 
    if( !ResolveSymbol( Inst->Params->Param, &RegX, Reg, &NullLocation )) {
      RegX = ( long int )V0Reg;
      RunError( False, NoRegisterWarning );
    }
  if( RegX == ( long int )IReg ) {
    if( ParamCheck( Inst->Count, 2, 2 )) 
      if( ResolveSymbol( Inst->Params->Next->Param, &RegX, Reg,
        &NullLocation ))
          RegX -= V0Reg;
      else
        RunError( False, NoRegisterWarning );
    if( RangeCheck( RegX, 0L, NibbleMask, BadRegisterWarning ))
      RegX = 0L;
    Value = 0xf01eL | ( RegX << 8 );
    Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
      (( Value & 0xff00L ) >> 8 );
    Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
      ( Value & 0xffL );
    ListInstruction( Inst->Loc.Addr, 2, Inst );
  } else {
    RegX -= V0Reg;
    if( RangeCheck( RegX, 0L, NibbleMask, BadRegisterWarning ))
      RegX = 0L;
    if( ParamCheck( Inst->Count, 2, 2 ))
      if( ResolveSymbol( Inst->Params->Next->Param, &RegY, Reg,
        &NullLocation )) {
          RegY -= V0Reg;
          if( RangeCheck( RegY, 0L, NibbleMask, BadRegisterWarning ))
            RegY = 0L;
          Value = 0x8004L | ( RegX << 8 ) | ( RegY << 4 );
          Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
            (( Value & 0xff00L ) >> 8 );
          Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
            ( Value & 0xffL );
          ListInstruction( Inst->Loc.Addr, 2, Inst );
        } else {
          char *SecondParam;

          SecondParam = Inst->Params->Next->Param;
          if( !ResolveExpression( &SecondParam, &Value, Symb, &( Inst->Loc )))
            RunError( False, UndefinedWarning );
          if( RangeCheck( Value, 0L, ByteMask, RangeWarning ))
            Value &= ByteMask;
          Value |= 0x7000L | ( RegX << 8 );
          Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
            (( Value & 0xff00L ) >> 8 );
          Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
            ( Value & 0xffL );
          ListInstruction( Inst->Loc.Addr, 2, Inst );
        }
  }
}

#if ANSI
  static PROC void EncodeJpToken( InstPointer Inst, SymbolPointer Reg,
    SymbolPointer Symb )
#else
  static PROC void EncodeJpToken( Inst, Reg, Symb )
  InstPointer Inst;
  SymbolPointer Reg;
  SymbolPointer Symb;
#endif
{
  long int RegX;
  long int Addr;

  RegX = ( long int )V0Reg;
  Addr = ( long int )V0Reg;
  if( ParamCheck( Inst->Count, 1, 2 ))
    if( ResolveSymbol( Inst->Params->Param, &RegX, Reg, &NullLocation )) {
      if( RegX != V0Reg )
        RunError( False, BadRegisterWarning );
      if( Inst->Count == 1 )
        RunError( False, ParamCountWarning );
      else {
        char *SecondParam;

        SecondParam = Inst->Params->Next->Param;
        if( ResolveExpression( &SecondParam , &Addr, Symb, &( Inst->Loc )))
          RunError( False, UndefinedWarning );
      }
      if( RangeCheck( Addr, 0L, AddrMask, RangeWarning ))
        Addr &= AddrMask;
      Addr |= 0xb000L;
      Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
        (( Addr & 0xff00L ) >> 8 );
      Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
        ( Addr & 0xffL );
      ListInstruction( Inst->Loc.Addr, 2, Inst );
    } else {
      char *FirstParam;

      FirstParam = Inst->Params->Param;
      if( !ResolveExpression( &FirstParam, &Addr, Symb, &( Inst->Loc )))
        RunError( False, UndefinedWarning );
      if( Inst->Count == 2 )
        RunError( False, ParamCountWarning );
      if( RangeCheck( Addr, 0L, AddrMask, RangeWarning ))
        Addr &= AddrMask;
      Addr |= 0x1000L;
      Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
        (( Addr & 0xff00L ) >> 8 );
      Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
        ( Addr & 0xffL );
      ListInstruction( Inst->Loc.Addr, 2, Inst );
    }
}

#if ANSI
  static PROC void EncodeLdToken( InstPointer Inst, SymbolPointer Reg,
    SymbolPointer Symb )
#else
  static PROC void EncodeLdToken( Inst, Reg, Symb )
  InstPointer Inst;
  SymbolPointer Reg;
  SymbolPointer Symb;
#endif
{
  long int RegX;
  long int RegY;
  long int Value;
  char RegFlag;

  RegX = ( long int )V0Reg;
  RegY = ( long int )V0Reg;
  Value = 0L;
  RegFlag = True;
  if( Inst->Count >= 1 ) 
    if( !ResolveSymbol( Inst->Params->Param, &RegX, Reg, &NullLocation )) {
      RegX = ( long int )V0Reg;
      RunError( False, NoRegisterWarning );
    }
  switch( RegX ) {
    case BReg:
    case DtReg:
    case FReg:
    case HfReg:
    case LfReg:
    case RReg:
    case StReg:
    case IiReg:
      RegY = RegX;
      RegX = ( long int )V0Reg;
      if( ParamCheck( Inst->Count, 2, 2 )) 
        if( ResolveSymbol( Inst->Params->Next->Param, &RegX, Reg,
          &NullLocation ))
            RegX -= V0Reg;
        else
          RunError( False, NoRegisterWarning );
      if( RangeCheck( RegX, 0L, NibbleMask, BadRegisterWarning ))
        RegX = 0L;
      switch( RegY ) {
        case BReg:
          Value = 0xf033L | ( RegX << 8 );
          break;
        case DtReg:
          Value = 0xf015L | ( RegX << 8 );
          break;
        case FReg:
          if( !( *Chip48Cond ))
            RunError( False, NeedsChip48Warning );
          Value = 0xf029L | ( RegX << 8 );
          break;
        case HfReg:
          if( !( *Super10Cond ))
            RunError( False, NeedsSuper10Warning );
          Value = 0xf030L | ( RegX << 8 );
          break;
        case LfReg:
          if( !( *Super10Cond ))
            RunError( False, NeedsSuper10Warning );
          Value = 0xf029L | ( RegX << 8 );
          break;
        case RReg:
          if( RangeCheck( RegX, 0L, 7L, BadRegisterWarning ))
            RegX = 0L;
          if( !( *Super10Cond ))
            RunError( False, NeedsSuper10Warning );
          Value = 0xf075L | ( RegX << 8 );
          break;
        case StReg:
          Value = 0xf018L | ( RegX << 8 );
          break;
        case IiReg:
          Value = 0xf055L | ( RegX << 8 );
          break;
        default:
          RunError( False, InternalWarning );
          break;
      }
      Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
        (( Value & 0xff00L ) >> 8 );
      Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
        ( Value & 0xffL );
      ListInstruction( Inst->Loc.Addr, 2, Inst );
      break;
    case IReg:
      if( ParamCheck( Inst->Count, 2, 2 )) {
        char *SecondParam;

        SecondParam = Inst->Params->Next->Param;
        if( !ResolveExpression( &SecondParam, &Value, Symb, &( Inst->Loc )))
          RunError( False, UndefinedWarning );
      }
      if( RangeCheck( Value, 0L, AddrMask, RangeWarning ))
        Value &= AddrMask;
      Value |= 0xa000L;
      Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
        (( Value & 0xff00L ) >> 8 );
      Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
        ( Value & 0xffL );
      ListInstruction( Inst->Loc.Addr, 2, Inst );
      break;
    default:
      RegX -= V0Reg;
      if( RangeCheck( RegX, 0L, NibbleMask, BadRegisterWarning ))
        RegX = 0L;
      if( ParamCheck( Inst->Count, 2, 2 ))
        RegFlag = ResolveSymbol( Inst->Params->Next->Param, &RegY, Reg,
          &NullLocation );
      if( RegFlag ) 
        switch( RegY ) {
          case DtReg:
            Value = 0xf007L | ( RegX << 8 );
            Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
              (( Value & 0xff00L ) >> 8 );
            Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
              ( Value & 0xffL );
            ListInstruction( Inst->Loc.Addr, 2, Inst );
            break;
          case KReg:
            Value = 0xf00aL | ( RegX << 8 );
            Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
              (( Value & 0xff00L ) >> 8 );
            Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
              ( Value & 0xffL );
            ListInstruction( Inst->Loc.Addr, 2, Inst );
            break;
          case RReg:
            if( RangeCheck( RegX, 0L, 7L, BadRegisterWarning ))
              RegX = 0L;
            if( !( *Super10Cond ))
              RunError( False, NeedsSuper10Warning );
            Value = 0xf085L | ( RegX << 8 );
            Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
              (( Value & 0xff00L ) >> 8 );
            Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
              ( Value & 0xffL );
            ListInstruction( Inst->Loc.Addr, 2, Inst );
            break;
          case IiReg:
            Value = 0xf065L | ( RegX << 8 );
            Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
              (( Value & 0xff00L ) >> 8 );
            Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
              ( Value & 0xffL );
            ListInstruction( Inst->Loc.Addr, 2, Inst );
            break;
          default:
            RegY -= V0Reg;
            if( RangeCheck( RegY, 0L, NibbleMask, BadRegisterWarning ))
              RegY = 0L;
            Value = 0x8000L | ( RegX << 8 ) | ( RegY << 4 );
            Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
              (( Value & 0xff00L ) >> 8 );
            Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
              ( Value & 0xffL );
            ListInstruction( Inst->Loc.Addr, 2, Inst );
            break;
        }
      else {
        if( Inst->Count >= 2 ) {
          char *SecondParam;

          SecondParam = Inst->Params->Next->Param;
          if( !ResolveExpression( &SecondParam, &Value, Symb, &( Inst->Loc )))
            RunError( False, UndefinedWarning );
        }
        if( RangeCheck( Value, 0L, ByteMask, RangeWarning ))
          Value &= ByteMask;
        Value |= 0x6000L | ( RegX << 8 );
        Memory[ Inst->Loc.Addr - StartAddress ] = ( unsigned char )
          (( Value & 0xff00L ) >> 8 );
        Memory[ Inst->Loc.Addr - StartAddress + 1 ] = ( unsigned char )
          ( Value & 0xffL );
        ListInstruction( Inst->Loc.Addr, 2, Inst );
      }
      break;
  }
}

#if ANSI
  static PROC void EncodeDaToken( InstPointer Inst )
#else
  static PROC void EncodeDaToken( Inst )
  InstPointer Inst;
#endif
{
  char *Param;
  char *This;
  long int Store;

  Param = NullString;
  if( Inst->Count >= 1 )
    Param = Inst->Params->Param;
  Store = Inst->Loc.Addr - StartAddress;
  for( This = Param ; *This; This++ )
    Memory[ Store++ ] = *This;
  ListInstruction( Inst->Loc.Addr, ( unsigned int )strlen( Param ), Inst );
}

#if ANSI
  static PROC void EncodeDbToken( InstPointer Inst, SymbolPointer Symb )
#else
  static PROC void EncodeDbToken( Inst, Symb )
  InstPointer Inst;
  SymbolPointer Symb;
#endif
{
  ParamPointer Param;
  char *LoopParam;
  long int Value;
  unsigned int This;

  This = 0;
  Value = 0L;
  for( Param = Inst->Params; Param; Param = Param->Next ) {
    LoopParam = Param->Param; 
    if( !ResolveExpression( &LoopParam, &Value, Symb, &( Inst->Loc )))
      RunError( False, UndefinedWarning );
    if( RangeCheck( Value, 0L, ByteMask, RangeWarning ))
      Value &= ByteMask;
    Memory[ Inst->Loc.Addr + ( This++ ) - StartAddress ] = ( unsigned char )
      Value;
  }
  ListInstruction( Inst->Loc.Addr, Inst->Count, Inst );
}

#if ANSI
  static PROC void EncodeDwToken( InstPointer Inst, SymbolPointer Symb )
#else
  static PROC void EncodeDwToken( Inst, Symb )
  InstPointer Inst;
  SymbolPointer Symb;
#endif
{
  ParamPointer Param;
  char *LoopParam;
  long int Value;
  unsigned int This;

  This = 0;
  Value = 0L;
  for( Param = Inst->Params; Param; Param = Param->Next ) {
    LoopParam = Param->Param;
    if( !ResolveExpression( &LoopParam, &Value, Symb, &( Inst->Loc )))
      RunError( False, UndefinedWarning );
    if( RangeCheck( Value, 0L, WordMask, RangeWarning ))
      Value &= WordMask;
    Memory[ Inst->Loc.Addr + ( This++ ) - StartAddress ] = ( unsigned char )
      (( Value & 0xff00L ) >> 8 );
    Memory[ Inst->Loc.Addr + ( This++ ) - StartAddress ] = ( unsigned char )
      ( Value & 0xffL );
  }
  ListInstruction( Inst->Loc.Addr, Inst->Count * 2, Inst );
}

#if ANSI
  static PROC void EncodeInstruction( InstPointer Inst, SymbolPointer Reg,
    SymbolPointer Symb )
#else
  static PROC void EncodeInstruction( Inst, Reg, Symb )
  InstPointer Inst;
  SymbolPointer Reg;
  SymbolPointer Symb;
#endif
{
  switch( Inst->Token ) {
    case AddToken:
      EncodeAddToken( Inst, Reg, Symb );
      break;
    case AndToken:
      EncodeRegRegToken( Inst, 0x8002L, 2, Reg );
      break;
    case CallToken:
      EncodeValToken( Inst, 0x2000L, AddrMask, Symb, &DefinedValue,
        &DefinedValue );
      break;
    case ClsToken:
      EncodeNoneToken( Inst, 0x00e0L, &DefinedValue, &DefinedValue );
      break;
    case DaToken:
      EncodeDaToken( Inst );
      break;
    case DbToken:
      EncodeDbToken( Inst, Symb );
      break;
    case DrwToken:
      EncodeDrwToken( Inst, 0xd000L, Reg, Symb );
      break;
    case DwToken:
      EncodeDwToken( Inst, Symb );
      break;
    case ExitToken:
      EncodeNoneToken( Inst, 0x00fdL, Super10Cond, &DefinedValue );
      break;
    case HighToken:
      EncodeNoneToken( Inst, 0x00ffL, Super10Cond, &DefinedValue );
      break;
    case JpToken:
      EncodeJpToken( Inst, Reg, Symb );
      break;
    case LdToken:
      EncodeLdToken( Inst, Reg, Symb );
      break;
    case LowToken:
      EncodeNoneToken( Inst, 0x00feL, Super10Cond, &DefinedValue );
      break;
    case OrToken:
      EncodeRegRegToken( Inst, 0x8001L, 2, Reg );
      break;
    case RetToken:
      EncodeNoneToken( Inst, 0x00eeL, &DefinedValue, &DefinedValue );
      break;
    case RndToken:
      EncodeRegValToken( Inst, 0xc000L, Reg, Symb );
      break;
    case ScdToken:
      EncodeValToken( Inst, 0x00c0L, NibbleMask, Symb, &DefinedValue,
        Super11Cond );
      break;
    case SclToken:
      EncodeNoneToken( Inst, 0x00fcL, &DefinedValue, Super11Cond );
      break;
    case ScrToken:
      EncodeNoneToken( Inst, 0x00fbL, &DefinedValue, Super11Cond );
      break;
    case SeToken:
      EncodeRegRegOrValToken( Inst, 0x5000L, 0x3000L, Reg, Symb );
      break;
    case ShlToken:
      EncodeRegRegToken( Inst, 0x800eL, 1, Reg );
      break;
    case ShrToken:
      EncodeRegRegToken( Inst, 0x8006L, 1, Reg );
      break;
    case SknpToken:
      EncodeRegToken( Inst, 0xe0a1L, Reg );
      break;
    case SkpToken:
      EncodeRegToken( Inst, 0xe09eL, Reg );
      break;
    case SneToken:
      EncodeRegRegOrValToken( Inst, 0x9000L, 0x4000L, Reg, Symb );
      break;
    case SubToken:
      EncodeRegRegToken( Inst, 0x8005L, 2, Reg );
      break;
    case SubnToken:
      EncodeRegRegToken( Inst, 0x8007L, 2, Reg );
      break;
    case SysToken:
      EncodeValToken( Inst, 0x2000L, AddrMask, Symb, Chip8Cond,
        &DefinedValue );
      break;
    case XorToken:
      EncodeRegRegToken( Inst, 0x8003L, 2, Reg );
      break;
    default:
      RunError( False, InternalWarning );
      break;
  }
}

#if ANSI
  static PROC void EncodeMemory( InstPointer Inst, SymbolPointer Reg,
    SymbolPointer Symb, SymbolPointer Cond )
#else
  static PROC void EncodeMemory( Inst, Reg, Symb, Cond )
  InstPointer Inst;
  SymbolPointer Reg;
  SymbolPointer Symb;
  SymbolPointer Cond;
#endif
{
  long int Count;

  if( fprintf( ListFile, "-----   *INSTRUCTIONS*   -----\n\n" ) <= 0 )
    RunError( True, FileWriteError );
  for( Count = StartAddress; Count <= StopAddress; Count++ )
    Memory[ Count - StartAddress ] = 0;
  while( Inst ) {
    InstPoint = Inst;
    EncodeInstruction( Inst, Reg, Symb );
    Inst = Inst->Next;
  }
  InstPoint = NULL;
  if( fprintf( ListFile, "\n-----   *SYMBOLS*   -----\n\n" ) <= 0 )
    RunError( True, FileWriteError );
  ListSymbols( Symb );
  if( fprintf( ListFile, "\n-----   *CONDITIONS*   -----\n\n" ) <= 0 )
    RunError( True, FileWriteError );
  ListDefines( Cond );
  fprintf( ListFile, "\n" );
  ListWarnings();
}

#if ANSI
  static PROC void WriteCheckByte( long int *Check, unsigned char Value )
#else
  static PROC void WriteCheckByte( Check, Value )
  long int *Check;
  unsigned char Value;
#endif
{
  SymbolString MsbText;
  SymbolString LsbText;

  if( *HpHeadCond ) {
    if( fprintf( OutFile, "%s%s", NumberString( LsbText,
      ( long int )( Value & NibbleMask ), 16, 1 ), NumberString( MsbText,
      ( long int )(( Value >> 4 ) & NibbleMask ), 16, 1 )) <= 0 )
        RunError( True, FileWriteError );
  } else
    if( fprintf( OutFile, "%s", NumberString( MsbText, ( long int )Value,
      16, 2 )) <= 0 )
        RunError( True, FileWriteError );
  *Check = ((( *Check ) >> 4 ) ^ ((( Value ^ ( *Check )) & NibbleMask ) *
    CheckMagic ) & WordMask );
  *Check = ((( *Check ) >> 4 ) ^ (((( Value >> 4 ) ^ ( *Check )) &
    NibbleMask ) * CheckMagic ) & WordMask );
}

#if ANSI
  static PROC void WriteMemory( long int Start, long int Stop )
#else
  static PROC void WriteMemory( Start, Stop )
  long int Start;
  long int Stop;
#endif
{
  if( *HpAscCond ) {
    OutFile = freopen( OutFileName, "w+", OutFile );
    if( !OutFile )
      RunError( True, FileAccessError );
  }
  if( *HpHeadCond )
    if( *HpAscCond ) {
      if( fprintf( OutFile, "%s", AscHpHeadText ) <= 0 )
        RunError( True, FileWriteError );
    } else {
      unsigned char HpHeading[ BinHpHeadLength ];
      long int Size;

      Size = (( Stop - Start ) << 1 ) + 5;
      strcpy(( char * )HpHeading, BinHpHeadText );
      HpHeading[ BinHpHeadLength - 5 ] = 0x2c;
      HpHeading[ BinHpHeadLength - 4 ] = 0x2a;
      HpHeading[ BinHpHeadLength - 3 ] = ( unsigned char )( 0 | (( Size &
        0xfL ) << 4 ));
      HpHeading[ BinHpHeadLength - 2 ] = ( unsigned char )(( Size &
        0xff0L ) >> 4 );
      HpHeading[ BinHpHeadLength - 1 ] = ( unsigned char )(( Size &
        0xff000L ) >> 12 );
      if( fwrite(( char * )HpHeading, 1, BinHpHeadLength, OutFile ) !=
        BinHpHeadLength ) 
          RunError( True, FileWriteError );
    }
  if( *HpAscCond ) {
    SymbolString HexText;
    long int Count;
    long int Check;

    Check = 0L;
    if( *HpHeadCond ) {
      long int Size;

      Size = (( Stop - Start ) << 1 ) + 5;
      if( fprintf( OutFile, "\"" ) <= 0 )
        RunError( True, FileWriteError );
      WriteCheckByte( &Check, 0x2c );
      WriteCheckByte( &Check, 0x2a );
      WriteCheckByte( &Check, ( unsigned char )( 0 | (( Size & 0xfL ) << 4 )));
      WriteCheckByte( &Check, ( unsigned char )(( Size & 0xff0L ) >> 4 ));
      WriteCheckByte( &Check, ( unsigned char )(( Size & 0xff000L ) >> 12 ));
    }
    for( Count = Start; Count < Stop; Count++ ) {
      WriteCheckByte( &Check, Memory[ Count - StartAddress ]);
      if( !(( Count - Start + 6 ) % 32 ) && ( *HpHeadCond ))
        if( fprintf( OutFile, "\n" ) <= 0 )
          RunError( True, FileWriteError );
    }
    if( *HpHeadCond ) {
      for( Count = 0; Count < 4; Count++ ) 
        if( fprintf( OutFile, "%s", NumberString( HexText,
          ( Check >> ( 4 * Count )) & NibbleMask, 16, 1 )) <= 0 )
            RunError( True, FileWriteError );
      if( fprintf( OutFile, "\"" ) <= 0 )
        RunError( True, FileWriteError );
    }
  } else {
    unsigned int Size;

    if(( Stop - Start ) > 0L ) {
      Size = ( unsigned int )( Stop - Start );
      if( fwrite(( char * )&Memory[ Start - StartAddress ], 1, Size,
        OutFile ) != Size )
          RunError( True, FileWriteError );
    }
  }
}

#if ANSI
  PROC int main( int argc, char *argv[] )
#else
  PROC int main( argc, argv )
  int argc;
  char *argv[];
#endif
{
  InstPointer Inst; 
  unsigned int Count;
  
  if( fprintf( stderr, "%s\n\n", CopyRight ) <= 0 )
    RunError( True, FileWriteError );
  strcpy( Separator, "---------------------------------------" );
  strcat( Separator, "---------------------------------------" );
  for( Count = 0x0; Count < 0x100; Count++ )
    Operators[ Count ] = False;
  Operators[ StartChar ] = True;
  Operators[ StopChar ] = True;
  Operators[ PlusChar ] = True;
  Operators[ MinusChar ] = True;
  Operators[ NotChar ] = True;
  Operators[ PowerChar ] = True;
  Operators[ ShlChar ] = True;
  Operators[ ShrChar ] = True;
  Operators[ MulChar ] = True;
  Operators[ FracChar ] = True;
  Operators[ AndChar ] = True;
  Operators[ OrChar ] = True;
  Operators[ XorChar ] = True;
  Operators[ DivChar ] = True;
  Operators[ ModChar ] = True;
  if( OpenFiles( argc, argv )) {
    *StackPoint = True;
    StoreSymbolList( TokenText, 0, LastToken - 1, &Directives );
    StoreSymbolList( RegisterText, 0, LastReg - 1, &Registers );
    DefineSymbol( Super10Name, Super10Default, &Conditions, &NullLocation );
    Super10Cond = &( CurrentSymbol->Value );
    DefineSymbol( Chip48Name, Chip48Default, &Conditions, &NullLocation );
    Chip48Cond = &( CurrentSymbol->Value );
    DefineSymbol( UsedYesName, UsedYesDefault, &Conditions, &NullLocation );
    UsedYesCond = &( CurrentSymbol->Value );
    DefineSymbol( AlignOnName, AlignOnDefault, &Conditions, &NullLocation );
    AlignOnCond = &( CurrentSymbol->Value );
    DefineSymbol( HpAscName, HpAscDefault, &Conditions, &NullLocation );
    HpAscCond = &( CurrentSymbol->Value );
    DefineSymbol( Super11Name, Super11Default, &Conditions, &NullLocation );
    Super11Cond = &( CurrentSymbol->Value );
    DefineSymbol( XrefOnName, XrefOnDefault, &Conditions, &NullLocation );
    XrefOnCond = &( CurrentSymbol->Value );
    DefineSymbol( Chip8Name, Chip8Default, &Conditions, &NullLocation );
    Chip8Cond = &( CurrentSymbol->Value );
    DefineSymbol( HpHeadName, HpHeadDefault, &Conditions, &NullLocation );
    HpHeadCond = &( CurrentSymbol->Value );
    DefineSymbol( UsedOnName, UsedOnDefault, &Conditions, &NullLocation );
    UsedOnCond = &( CurrentSymbol->Value );
    DefineSymbol( XrefYesName, XrefYesDefault, &Conditions, &NullLocation );
    XrefYesCond = &( CurrentSymbol->Value );
    CurrentSymbol = NULL;
    Inst = NULL;
    DecodeFile( InFileName, &Inst, Directives, &Symbols, &Conditions );
    if( fprintf( stderr, "Done reading\n\n" ) <= 0 )
      RunError( True, FileWriteError );
    if( fprintf( ListFile, "Done reading\n\n" ) <= 0 )
      RunError( True, FileWriteError );
    ResolveEquations( Symbols );
    EncodeMemory( Instructions, Registers, Symbols, Conditions );
    WriteMemory( StartAddress, FinalAddress );
    if( OutFile )
      fclose( OutFile );
    OutFile = NULL;
    if( ListFile )
      if( ListFile != stdout )
        fclose( ListFile );
    ListFile = NULL;
    ReleaseSpace( &Space );
  }
  return( SuccessExitCode );
}


 

Chipper V2.11 is a toy assembler for a toy language called Chip-8,

and three emulators called Chip-48, Super Chip-48 V1.0 and V1.1.

 

 

Chipper V2.11 is written by Christian Egeberg 2/11-'90 .. 20/8-'91.

In order to utilize this assembler, you will need the following:

 

    *  A computer, preferably with 512k bytes or more memory.

    *  A Kernighan-Ritchie C, ANSI C, or C++ compiler for the computer.

    *  A Hewlett Packard 48 series calculator.

    *  A serial cable for connecting the computer and the calculator.

    *  A Kermit compatible communication program for the computer.

    *  A Chip-8 emulator program for the calculator.

 

    *  You may also need the HP48 decode program called ASC->.

 

 

Chip-8 is a video game interpreter commonly found on RCA CDP1802 based

home computers in the late 1970's. Chip-48 emulates the original Chip-8

instruction set precisely, except for the calling of CDP1802 routines.

Super Chip-48 V1.0 and V1.1 extend the instruction set of Chip-48, in

order to utilize the higher screen resolution of the Hewlett Packard

calculator, and also provide a few additional features.

 

 

Chip-8 programs have access to 4k bytes of memory, addressed from #000

to #FFF. All programs start at address #200, because of the memory

requirements of the original Chip-8 interpreter. Instructions are 16

bits long and start at even memory locations.

 

 

Chip-8 has 16 general registers, named V0, V1, V2, .. , VE, VF. These

are 8 bits wide. The VF register works as carry flag and collision

indicator, and is modified by certain instructions. A 16 bit register

named I also exists. The lower 12 bits of this register are typically

used as a memory pointer. A delay timer and a sound timer is provided

as well. These are 8 bits wide and decrement at around 60 hertz, until

a value of 0 is reached. The calculator beeper will buzz while the

sound timer is nonzero.

 

 

Chip-8 screen resolution is 64 pixels horisontal, 32 pixels vertical.

Screen origin is the upper left corner. A graphics object called a

sprite is 8 pixels wide and from 1 to 15 pixels high, meaning they are

between 1 and 15 bytes large. The upper row of the sprite is in the

first byte. The leftmost pixel is in the most significant bit. Sprites

are XORed onto the background. If this causes any pixel to be erased,

VF is set to #01, else VF will be #00. Super Chip-48 V1.0 and V1.1

support an additional screen mode with a resolution of 128 pixels

horisontal and 64 pixels vertical. A new 16 by 16 pixel sprite size is

also provided, 32 bytes large. 2 bytes, or a word, per row.

 

 

Chip-8 programs may access 16 keys numbered from #0 to #F. The HP48

keyboard mapping is shown below:

 

    ( 7 )  ->  #1    ( 8 )  ->  #2    ( 9 )  ->  #3    ( / )  ->  #C

    ( 4 )  ->  #4    ( 5 )  ->  #5    ( 6 )  ->  #6    ( * )  ->  #D

    ( 1 )  ->  #7    ( 2 )  ->  #8    ( 3 )  ->  #9    ( - )  ->  #E

    ( 0 )  ->  #A    ( . )  ->  #0    ( _ )  ->  #B    ( + )  ->  #F

 

 

A following table contains Chip instruction opcodes, the list of

interpreters that support each opcode, and the syntax of Chipper V2.11.

A brief explanation of terms used in the table preceeds it:

 

    CHIP8       means the instruction is supported by Chip-8.

    CHIP48      instructions are valid on Chip-48.

    SCHIP10     instructions need Super Chip-48 V1.0.

    SCHIP11     instructions need Super Chip-48 V1.1.

 

    NNN         indicates a 12 bit address.

    KK          means an 8 bit constant.

    X           denotes a 4 bit register number.

    Y           denotes a 4 bit register number.

    1..9, A..F  are hexadecimal digits.

 

    Word        represents an expression defining a 16 bit constant.

    Addr        is an expression resulting in a 12 bit address.

    Byte        results in an 8 bit constant.

    Nibble      would be a 4 bit constant.

    Expr        may be any of the above expressions.

    Char        is an ASCII character.

    String      is a sequence of ASCII characters.

 

Text in curly brackets is optional. Instruction codes are written most

significant byte first, least significant last. The instructions are:

 

    #FX1E  ADD   I, VX           ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set I = I + VX

    #7XKK  ADD   VX, Byte        ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = VX + Byte

    #8XY4  ADD   VX, VY          ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = VX + VY, VF = carry

    #8XY2  AND   VX, VY          ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = VX & VY, VF updates

    #2NNN  CALL  Addr            ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Call subroutine at Addr (16 levels)

    #00E0  CLS                   ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Clear display

    #DXYN  DRW   VX, VY, Nibble  ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Draw Nibble byte sprite stored at

                                 ; [I] at VX, VY. Set VF = collision

    #DXY0  DRW   VX, VY, 0       ; SCHIP10, SCHIP11

                                 ; Draw extended sprite stored at [I]

                                 ; at VX, VY. Set VF = collision

    #00FD  EXIT                  ; SCHIP10, SCHIP11

                                 ; Terminate the interpreter

    #00FF  HIGH                  ; SCHIP10, SCHIP11

                                 ; Enable extended screen mode

    #1NNN  JP    Addr            ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Jump to Addr

    #BNNN  JP    V0, Addr        ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Jump to Addr + V0

    #FX33  LD    B, VX           ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Store BCD of VX in [I], [I+1], [I+2]

    #FX15  LD    DT, VX          ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set delaytimer = VX

    #FX29  LD    F, VX           ; CHIP8, CHIP48

                                 ; Point I to 5 byte numeric sprite

                                 ; for value in VX

    #FX30  LD    HF, VX          ; SCHIP10, SCHIP11

                                 ; Point I to 10 byte numeric sprite

                                 ; for value in VX

    #ANNN  LD    I, Addr         ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set I = Addr

    #FX29  LD    LF, VX          ; SCHIP10, SCHIP11

                                 ; Point I to 5 byte numeric sprite

                                 ; for value in VX

    #FX75  LD    R, VX           ; SCHIP10, SCHIP11

                                 ; Store V0 .. VX in RPL user flags.

                                 ; Only V0 .. V7 valid

    #FX18  LD    ST, VX          ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set soundtimer = VX

    #6XKK  LD    VX, Byte        ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = Byte

    #FX07  LD    VX, DT          ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = delaytimer

    #FX0A  LD    VX, K           ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = key, wait for keypress

    #FX85  LD    VX, R           ; SCHIP10, SCHIP11

                                 ; Read V0 .. VX from RPL user flags.

                                 ; Only V0 .. V7 valid

    #8XY0  LD    VX, VY          ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = VY, VF updates

    #FX65  LD    VX, [I]         ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Read V0 .. VX from [I] .. [I+X]

    #FX55  LD    [I], VX         ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Store V0 .. VX in [I] .. [I+X]

    #00FE  LOW                   ; SCHIP10, SCHIP11

                                 ; Disable extended screen mode

    #8XY1  OR    VX, VY          ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = VX | VY, VF updates

    #00EE  RET                   ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Return from subroutine (16 levels)

    #CXKK  RND   VX , Byte       ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = random & Byte

    #00CN  SCD   Nibble          ; SCHIP11

                                 ; Scroll screen Nibble lines down

    #00FC  SCL                   ; SCHIP11

                                 ; Scroll screen 4 pixels left        

    #00FB  SCR                   ; SCHIP11

                                 ; Scroll screen 4 pixels right   

    #3XKK  SE    VX, Byte        ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Skip next instruction if VX == Byte

    #5XY0  SE    VX, VY          ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Skip next instruction if VX == VY

    #8XYE  SHL   VX {, VY}       ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = VX << 1, VF = carry

    #8XY6  SHR   VX {, VY}       ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = VX >> 1, VF = carry

    #EX9E  SKP   VX              ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Skip next instruction if key VX down

    #EXA1  SKNP  VX              ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Skip next instruction if key VX up

    #4XKK  SNE   VX, Byte        ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Skip next instruction if VX != Byte

    #9XY0  SNE   VX, VY          ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Skip next instruction if VX != VY

    #8XY5  SUB   VX, VY          ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = VX - VY, VF = !borrow

    #8XY7  SUBN  VX, VY          ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = VY - VX, VF = !borrow

    #0NNN  SYS   Addr            ; CHIP8

                                 ; Call CDP1802 code at Addr. This 

                                 ; is not implemented on emulators

    #8XY3  XOR   VX, VY          ; CHIP8, CHIP48, SCHIP10, SCHIP11

                                 ; Set VX = VX ^ VY, VF updates

 

 

Additional Chipper V2.11 directives are:

 

    Symbol  =        Expr           ; Assign constant value to Symbol

            ALIGN    OFF            ; Stop word aligning each line

            ALIGN    ON             ; Start word aligning each line

            DA       String         ; Define String at current address

            DB       Byte {, ..}    ; Define Byte(s) at current address

            DEFINE   Condition      ; Define Condition as logical true

            DS       Byte           ; Allocate Byte uninitialized bytes

                                    ; at current address

            DW       Word {, ..}    ; Define Word(s) at current address

            ELSE                    ; Toggle assembly on/off according

                                    ; to current Condition

            END                     ; This directive is ignored

            ENDIF                   ; Forget current, and return to

                                    ; previous assembly Condition

    Symbol  EQU      Expr           ; Assign constant value to Symbol

            IFDEF    Condition      ; Disable further assembly if

                                    ; Condition is logical false

            IFUND    Condition      ; Disable further assembly if

                                    ; Condition is logical true

            INCLUDE  FileName       ; Include one more sourcefile.

                                    ; FileName must be lower case

            OPTION   BINARY         ; Select pure binary output mode

            OPTION   CHIP8          ; Specify Chip-8 as target mode

            OPTION   CHIP48         ; Specify Chip-48 as target mode

            OPTION   HPASC          ; Select HP48 ASC-> output mode

            OPTION   HPBIN          ; Select HP48 binary output mode

            OPTION   SCHIP10        ; Specify Super Chip-48 V1.0 mode

            OPTION   SCHIP11        ; Specify Super Chip-48 V1.1 mode

            OPTION   STRING         ; Select hex string output mode

            ORG      Addr           ; Set current address to Addr

            UNDEF    Condition      ; Define Condition as logical false

            USED     NO             ; Enable UnusedSymbols warnings

            USED     OFF            ; Turn off automatic Symbol used

                                    ; when being defined feature

            USED     ON             ; Turn on automatic Symbol used

                                    ; when being defined feature

            USED     Symbol {, ..}  ; Register Symbol(s) as used

            USED     YES            ; Disable UnusedSymbols warnings

            XREF     NO             ; Disable cross reference listing

            XREF     OFF            ; Stop cross referencing

            XREF     ON             ; Start cross referencing

            XREF     YES            ; Enable cross reference listing

 

 

Chipper V2.11 accepts one label, or symbol, per line of source. This

should start with an alphabetic character, and consist of only

alphanumeric characters, otherwise the expression parser will get

confused. All symbols will be converted to upper case, and may be

prefixed by an underscore character and/or suffixed by a colon. These

will be stripped off before the symbol is used. Each symbol contains a

32 bit signed integer value, set to current address, unless defined by

the = or EQU directives. A condition is basically a symbol restricted

to logical true or false values, used for conditional assembly.

 

 

A string containing lower case letters or non alphanumeric characters,

should be contained within apostrophes. Two apostrophes following

eachother will produce one resultant apostrophe. Some string examples:

 

    '11/6-'68'           ; Is an unterminated string, that engulfs what

                         ; comes behind it, and starts with 11/6-68

    11/6-''68            ; Evaluates to 11/6-'68

    Christian Egeberg    ; Evaluates to CHRISTIAN EGEBERG

    'Christian Egeberg'  ; Evaluates to Christian Egeberg

    This, is a test      ; Evaluates to THIS

                         ; and          IS A TEST

    This',' is a test    ; Evaluates to THIS, IS A TEST

    'This, is a test'    ; Evaluates to This, is a test

    ''''                 ; Evaluates to '''

    ''                   ; Evaluates to '

 

 

In a numeric value, any 0 digit may be replaced with a . sign. This is

particularly useful when defining graphics. A numeric value may be one

of the following:

 

    Symbol        ; For instance LOOP

    Decimal       ; For instance 1106

    #Hexadecimal  ; For instance #452

    $Binary       ; For instance $10001010010, or $.....1...1.1..1.

    @Octal        ; For instance @2122

    "Character    ; For instance "'c'

    ?             ; Current assembly address

 

 

An expression may consist of numeric values and the following

operators. Horisontal lines denote different priorities. Operators

sharing the same priority level are evaluated left to right:

 

    (  ; Start parentheses expression

    )  ; End of parentheses expression

    ----------------------------------

    +  ; Unary plus sign

    -  ; Unary minus sign

    ~  ; Bitwise NOT operator

    ----------------------------------

    !  ; Power of operator

    <  ; Shift left number of bits

    >  ; Shift right number of bits

    ----------------------------------

    *  ; Multiply

    /  ; Divide

    ----------------------------------

    +  ; Add

    -  ; Subtract

    ----------------------------------

    &  ; Bitwise AND operator

    |  ; Bitwise OR operator

    ^  ; Bitwise XOR operator

    ----------------------------------

    \  ; Low priority divide

    %  ; Modulus operator

 

Some expression examples:

 

    ( ? + 15 \ 16 ) * 16       ; Is a paragraph (16 bytes) alignment

    "'c' + @2 % #20            ; Resolves to 5

    -3 * -( -7 + ~3 )          ; Resolves to -33

    -3 * -( -7 + ~3 ) & #FF    ; Resolves to 223

    ( 2 + 1 )! 2 ^ $1101 > 2   ; Resolves to 10

    (2+1)!2^$1101>2            ; Resolves to 10

    TABLESTART + 4 * ITEMSIZE  ; Resolves

 

 

Remarks are prefixed by semicolons, as in the above examples. Note that

Chipper V2.11 by default performs a word alignment after every line of

source code. This means that for instance two single parameter DB

directives in rapid succession will have an uninitialized separator

byte between them. Avoid this by defining any multiple of two bytes per

DB directive, or by temporarily disabling word alignment.

 

 

A note concerning at least the Chip-48 instruction set. The LD VX, [I]

and LD [I], VX instructions will change the value of the I register if

VX is different from V0. Actually, I think it is set to the address of

the last byte/register read or written. When detecting collisions, it

might be wise to check whether the VF register is zero or nonzero,

rather than depending on it being equal to 1.

 

 

Chipper V2.11 fatal error messages:

 

    File or pipe output failed

        ; Disk problem, perhaps no free disk space

    Internal memory allocation mismatch

        ; Christian Egeberg is a lousy programmer, bug(s) in program

    No source file found

        ; Incorrect source file name or path, must be lower case

    Outside legal address range

        ; Current assembly address outside #200 .. #FFF

    Too many nested conditions

        ; Too many IFDEFs and IFUNDs within eachother, stack blown

    Unable to allocate more memory

        ; Memory size or model problem, out of data storage space

    Unable to open file

        ; Disk problem, perhaps no write access

    Usage is.. chipper Target [Source] [List]

        ; Specify at least one parameter at startup

 

 

Chipper V2.11 warning messages:

 

    Chip-48 spesific directive

        ; The assembler should be in CHIP48 mode for this directive

    Chip-8 spesific directive

        ; The assembler should be in CHIP8 mode for this directive

    Existing symbol redefined

        ; Symbol already defined, old value lost, watch out

    Illegal register specified

        ; Parameter is not a valid register for this directive

    Incorrect number of parameters

        ; Too few or too many parameters for this directive

    Internal data structure mismatch

        ; Christian Egeberg is a lousy programmer, bug(s) in program

    No directive recognized

        ; Two symbols defined on same line, perhaps typing mistake

    No previous condition found

        ; ENDIF or ELSE encountered, but no matching IFDEF or IFUND

    No register recognized

        ; Parameter is not a register name

    No symbol name specified

        ; Assignment with = or EQU, but no destination symbol

    Not a defined symbol

        ; Attempt to reference an undefined symbol with USED

    Option not recognized

        ; Not a valid parameter string for this directive

    Parameter out of range

        ; Parameter value too large or too small for this directive

    Super Chip-48 V1.0.. spesific directive

        ; The assembler should be in SCHIP10 mode for this directive

    Super Chip-48 V1.1.. spesific directive

        ; The assembler should be in SCHIP11 mode for this directive

    Unable to evaluate parameter

        ; Undefined symbol or bad syntax in expression, value lost

    Unbalanced condition matching in file

        ; Count of IFDEF and IFUND not equal to count of ENDIF in file

    Unused symbol detected

        ; Symbol defined, but not referenced, perhaps typing mistake

 

 

Chipper V2.11 should be invoked with:

 

    chipper Target [Source] [List]

 

where Target is destination filename. Source is an optional filename.

If no source name is specified, the default will be Target.chp. List is

an optional filename. If no list name is specified, the default will be

Target.lst. Again, Target is the destination filename. No intelligent

filename expansion is provided. All filenames should be lower case, and

include filenames will be forced lower case. Special cases of source

and list filenames are . for default name, and - for stdin/stdout. The

list file will contain all error/warning messages, hexdump of all

generated instructions, a symboltable, an optional symbol cross

reference, along with defined conditions.

 

 

HPASC and STRING mode target files should be transfered as ASCII. HPBIN

and BINARY output mode target files must be transfered as binary. Use

kermit for downloading HPASC or HPBIN mode target files to a Hewlett

Packard 48 series calculator, where the target files will become

strings. Run the ASC-> program on the HPASC output mode strings, in

order to make them equal the HPBIN ones. Put a HPBIN mode string on the

stack, and run the appropriate Chip-48, Super Chip-48 V1.0 or V1.1.

 

 

Chipper V2.11 reserves a few conditions for its own mode setting

purposes. These are manipulated by directives according to the

following table:

 

                      A                   S   S       U       X

                      L       C       H   C   C   U   S   X   R

                      I   C   H   H   P   H   H   S   E   R   E

                      G   H   I   P   H   I   I   E   D   E   F

                      N   I   P   A   E   P   P   D   Y   F   Y

                      O   P   4   S   A   1   1   O   E   O   E

                      N   8   8   C   D   0   1   N   S   N   S

 

    Default           1   0   1   0   1   0   0   0   0   1   1

 

    ALIGN   OFF       0   .   .   .   .   .   .   .   .   .   .

    ALIGN   ON        1   .   .   .   .   .   .   .   .   .   .

    OPTION  BINARY    .   .   .   0   0   .   .   .   .   .   .

    OPTION  CHIP8     .   1   1   0   0   0   0   .   .   .   .

    OPTION  CHIP48    .   0   1   .   1   0   0   .   .   .   .

    OPTION  HPASC     .   .   .   1   1   .   .   .   .   .   .

    OPTION  HPBIN     .   .   .   0   1   .   .   .   .   .   .

    OPTION  SCHIP10   .   0   0   .   1   1   0   .   .   .   .

    OPTION  SCHIP11   .   0   0   .   1   1   1   .   .   .   .

    OPTION  STRING    .   .   .   1   0   .   .   .   .   .   .

    USED    NO        .   .   .   .   .   .   .   .   0   .   .

    USED    OFF       .   .   .   .   .   .   .   0   .   .   .

    USED    ON        .   .   .   .   .   .   .   1   .   .   .

    USED    YES       .   .   .   .   .   .   .   .   1   .   .

    XREF    NO        .   .   .   .   .   .   .   .   .   .   0

    XREF    OFF       .   .   .   .   .   .   .   .   .   0   .

    XREF    ON        .   .   .   .   .   .   .   .   .   1   .

    XREF    YES       .   .   .   .   .   .   .   .   .   .   1

 

 

Differences from Chipper V1.12:

 

    *  Written in C, in order to run on a broader range of computers.

       This, unfortunately, makes the program potentially more

       unstable, because of extensive use of pointers.

 

    *  The order of the command line parameters has changed to target,

       source and list files. If no source and/or list file names are

       given, these are derived from the target name by unintelligently

       adding MS-DOS like file extensions.

 

    *  Entirely noninteractive. All communication into Chipper V2.11

       takes place on the command line or in the sourcefiles. There is

       no special mode to ask for filenames.

 

    *  Support for Chip-8, Chip-48, Super Chip-48 V1.0 and V1.1 with

       illegal opcode warnings and different assembler modes.

 

    *  New directives for mode control and conditional assembly.

 

    *  Several target file output modes, including ASC-> format.

 

    *  Multiple pass forward referencing of symbols before use.

 

    *  Improved warning system, with more accurate information,

       additional messages, and new list file format, including symbol

       cross reference listing.

 

 

Chipper V2.11 has been tested on a small number of Kernighan-Ritchie C,

ANSI C and C++ compilers, running on a limited range of the most

widespread personal computer and workstation operating systems

available today. The program has to my knowledge behaved reasonably,

and produced the desired code. A lot of effort has gone into making

the assembler stable and portable, but I am by no means an experienced

C programmer, so do not make any assumption that this program should

run flawlessly, or even run at all, on your computer system. If your C

compiler has an ANSI mode, enable it when compiling Chipper V2.11. If

your C compiler/linker imposes memory constraints on the resulting

program, make sure that the data storage area is allowed to grow past

64k bytes. This makes the compact memory model ideal for compilation on

IBM PC compatibles. The following command line should enable compact

model, ansi compatibility and optimization for time on the likes of

Microsoft C V6.00 for MS-DOS:

 

    cl /AC /Za /Ot chipper.c

 

 

The evolution of Chipper V2.11:

 

    V1.00:  2/11-'90 .. 4/11-'90

 

        Written in Turbo Pascal V5.5, for MS-DOS

        Full Chipper V1.12 instruction set and directives

        No expression parser, only numeric assignment

        Assembled the symbolic part of Roy Trevino's Zyzygy listfile

 

    V1.10:  5/11-'90 .. 5/11-'90

 

        Expression parser added

        Current assembly address valid in expressions

        Nondeterministic bugs during expression evaluation

 

    V1.11:  6/11-'90 .. 7/11-'90

 

        Expression parser completely rewritten

        Fixed bug in current assembly address evaluation

        Assembled parts of Blinky V1.00: 7/11-'90 .. 11/11-'90

 

    V1.12:  7/11-'90 .. 7/11-'90

 

        Cosmetic changes only

        First official version, released on various ftp sites

        Assembled the completed Blinky V1.00

        Used for assembling Blinky V1.01: 7/6-'91 .. 7/6-'91

        Source language of several good Chip-48 games

 

    V1.13:  10/7-'91 .. 29/7-'91

 

        First Kernighan-Ritchie C version, tested on SCO Xenix

        Very close to V1.12 in syntax and functionality

        May dump core because of string copy overflows

        New list file format, allows use of stdin/stdout

 

    V2.00:  29/7-'91 .. 19/8-'91

 

        Tested on various cc, gcc, g++, msc, tc and bc compilers

        Tested under MS-DOS, UNIX, Xenix and OS/2 operating systems

        New instructions, directives and error messages

        Several output file formats, conditions, cross referencing

        Multiple pass forward referencing of symbols in expressions

        Assembled the completed Blinky V2.00: 17/8-'91 .. 18/8-'91

 

    V2.10:  19/8-'91 .. 19/8-'91

 

        Identical to V2.00 in syntax and functionality

        Reduces memory fragmentation by using block allocations

        Requires 30% less available memory than V2.00

 

    V2.11:  20/8-'91 .. 20/8-'91

 

        Identical to V2.10 in syntax and functionality

        Second official version, released on comp.sources.hp48

        Handles carriage return in ASC-> output format on MS-DOS

 

 

Thank you, to all who have used Chipper V1.12, played Blinky, and/or

taken interest in porting Chipper to new platforms. It feels good to

know that people actually use my programs once in a while. May all

HP48 users enjoy their Chip-48 games for a long time to come..

 

 

This document contains some information more or less copied directly

off the Chip-48 documentation by Andreas Gustafsson, and off the

Super Chip-48 documentation by Erik Bryntse. These two have done a

great job, hacking for the HP48SX. The Chipper V2.11 syntax is a slight

extension of the V1.12 original. This was in turn inspired by the

Syzygy game listing posted to comp.sys.handhelds by Roy Trevino. Syzygy

is still a great Chip-48 game.

 

 

Chip-48 is (C) Copyright 1990 Andreas Gustafsson.

Super Chip-48 V1.0 and V1.1 are modifications made by Erik Bryntse.

Chipper V2.11 is (C) Copyright 1991 Christian Egeberg.

 

Noncommercial distribution allowed, provided that copyright messages

are preserved, and any modified versions are clearly marked as such.

 

Chip-48, it's successors, and because of that, programs written in

Chipper make use of undocumented low-level features of the Hewlett

Packard 48 series calculator. They may or may not cause loss of data,

excessive battery drainage, and/or damage to the calculator hardware.

The authors take no responsibility whatsoever for any damage caused

by the use of these programs.

 

The authors takes no responsibility for loss of data, damage to any

personal computer or workstation hardware and/or software, nor strange

incidents caused by the use of these programs.

 

This software is provided "as is" and without any express or implied

warranties, including, but not limited to, the implied warranties of

merchantability and fitness for a particular purpose.

END_DOC

http://www.pong-story.com/chip8/

 

Enjoy~~

mars

September 29, 2012

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值