/* class comment */!!

inherit(ProvidedLibs, #AsmLib, #(workAddr  /* work address */), 2, nil)!!

now(class(AsmLib))!!

/* semiPRIVATE -- should only be called via require(AsmLib)
   Define entry points and load library.  Define any structs required.
*/
Def provide(self, path)
{
  ^initialize( new(self:ancestor), path )
}
!!

now(AsmLib)!!


/* PUBLIC */
Def setOffset(self, asmID, offset)
{
  /* set offset in address structure */
  lastError := setOffset(AddressLibClass$Inst, workAddr, offset);
  if not(lastError)
    ^nil
  endif;
  
  /* send address structure to asm */
  if pcallLock(self)
    lastError := pcall(procs[#DADSETASMADDR], asmID, workAddr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if lastError <> GOOD
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, FORCE_POPUP, nil, nil, nil);
    ^nil;
  endif;
  ^lastError
}
!!

/* 2/4/1992 17:06 */
Def addImportProcs(self)
{
  add(self, #DADASMOPEN,    1, #(1, 1)      );
  add(self, #DADASM,        1, #(1, 1, 1, 1));
  add(self, #DADSETASMADDR, 1, #(1, 1, 1)   );
  add(self, #DADASMCLOSE,   1, #(1)         );
}
!!

/* assemble the source code at the specified address. */
/* Note that the returned buffer and length are ignored; just let the
   memory write invalidate the cache. */
Def assembleSource(self, asmID, startAddr, source |
      bufIn bufRef lengthRef length aStruct)
{
  /* set address */
  lastError := setAddress(self, asmID, startAddr);
  if not(lastError)
    ^nil;
  endif;
  
  bufIn := asciiz(source);
  bufRef := new(Struct, 4);
  lengthRef := new(Struct, 2);
  
  if pcallLock(self) then
    lastError := pcall(procs[#DADASM], asmID, bufIn, bufRef, lengthRef);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if (lastError <> GOOD) then
    displayFormattedError(ErrorTextLibClass$Inst,
       lastError, FORCE_POPUP, nil, nil, nil);
    ^nil;
  endif;

  /* ignore length; free returned instruction */
  cFree(MallocLibClass$Inst, longAt(bufRef, 0));
  
  ^lastError;
}!!

/* PUBLIC */
Def closeAsm(self, asmID)
{
  if pcallLock(self)
    lastError := pcall(procs[#DADASMCLOSE], asmID);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, FORCE_POPUP, nil, nil, nil);

  if workAddr
    destroyAddress(AddressLibClass$Inst, workAddr);
    workAddr := nil;
  endif;
  
  if (lastError = 0)
    ^lastError
  else
    ^nil
  endif;
}
!!

/* PUBLIC
   create work address. */
Def createWorkAddr(self)
{
  /* create temporary work address if not already done */
  if not(workAddr) then
    workAddr := createAddress(AddressLibClass$Inst);
    if not(workAddr) then
      lastError := lastError(AddressLibClass$Inst);
      clearError(AddressLibClass$Inst);
      ^nil
    endif;
  endif;
  
  ^0
}!!

/* init */
Def initialize(self, path)
{
  createWorkAddr(self);
  ^initialize(self:ancestor, path)
}!!

/* PUBLIC */
Def openAsm(self, startAddr | descRef temp)
{
  if not(createWorkAddr(self))
    ^nil
  endif;
  
  descRef := new(Struct, 4);
  if pcallLock(self)
    lastError := pcall(procs[#DADASMOPEN], descRef, startAddr);
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if lastError <> GOOD
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, FORCE_POPUP, nil, nil, nil);
    ^nil;
  endif;
  ^longAt(descRef, 0)
}
!!

/* PUBLIC */
Def setAddress(self, asmID, address | temp)
{
  temp := self;
  /* send address structure to asm */
  if pcallLock(self) then
    if (temp <> self)
      errorBox("set address point 1", "self lost");
    endif;
    lastError := pcall(procs[#DADSETASMADDR], asmID, address);
    if (temp <> self)
      errorBox("set address point 2", "self lost");
    endif;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION;
  endif;
  
  if lastError <> GOOD then
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, FORCE_POPUP, nil, nil, nil);
    ^nil;
  endif;
  ^lastError
}
!!

/* PUBLIC
   Simplified open; don't require user to mess with address structure;
   initialize asm at address 0 with memSize/processor defaults. */
Def simpleOpenAsm(self | tempAddr status)
{
  if not(tempAddr := createAddress(AddressLibClass$Inst)) then
    lastError := lastError(AddressLibClass$Inst);
    clearError(AddressLibClass$Inst);
    ^nil
  endif;

  status := openAsm(self, tempAddr);
  
  destroyAddress(AddressLibClass$Inst, tempAddr);
  
  ^status;
}
!!
