!!!ACTION! BUG SHEET #3 - part 1
This document supercedes the previous two bug sheets published for ACTION!
November 6, 1984
--------------------------------------------------------------------------

!!GENERAL INFORMATION

Before getting to the bad stuff (the bugs), here are some goodies about ACTION! which we would like to pass on to you:

!TIPS ON TEMPS

A magazine article titled "Lights, Camera, Action!" (by Dave Plotkin) which appeared in the July 1984 issue of ANTIC featured a set of routines to facilitate writing ACTION!-based interrupt handlers.

The article gave the listings for two routines (more properly, two DEFINEs) named "SaveTemps" and "GetTemps". These routines are adequate only if no math beyond addition and subtraction is performed in the interrupt service routine. The following versions of these two routines will work properly in the more general case:

Make the following DEFINEs in your program before you declare your interrupt routine (comments may be omitted-they exist only for clarification):

{{{
DEFINE SaveTemps=[
     $A2 $07     ;       LDX #7
     $B5 $C0     ; LOOP  LDA $C0,X
     $48         ;       PHA
     $B5 $A0     ;       LDA $A0,X
     $48         ;       PHA
     $B5 $80     ;       LDA $80,X
     $48         ;       PHA
     $B5 $A8     ;       LDA $A8,X
     $48         ;       PHA
     $CA         ;       DEX
     $10 $F1     ;       BPL LOOP
     $A5 $D3     ;       LDA $D3
     $48         ;       PHA
  ]

DEFINE GetTemps=[
     $68         ;       PLA
     $85 $D3     ;       STA $D3
     $A2 $00     ;       LDX #0
     $68         ; LOOP  PLA
     $95 $A8     ;       STA $A8,X
     $68         ;       PLA
     $95 $80     ;       STA $80,X
     $68         ;       PLA
     $95 $A0     ;       STA $A0,X
     $68         ;       PLA
     $95 $C0     ;       STA $C0,X
     $E8         ;       INX
     $E0 $08     ;       CPX #8
     $D0 $EF     ;       BNE LOOP
  ]"}}}

Use these routines inside your interrupt routine as follows:

; Your interrupt routine.
{{{PROC InterruptRoutine()
  ; Local declarations, if any.
    BYTE a, b, c, etc.
  ; First line of code within
  ; procedure SaveTemps

    ... ; Your interrupt
        ; code goes here.

    GetTemps      ; Last line of code
                  ; within procedure.
[$6C OldVBI]      ; A special way to
                  ; end for VBIs- see
                  ; below.}}}

For example, the following program will set up the routine ChangeColor as a vertical blank interrupt routine (hit the START key to exit the program):

{{{
DEFINE SaveTemps=
   [ $A2 $07 $B5 $C0 $48
     $B5 $A0 $48 $B5 $80
     $48 $B5 $A8 $48 $CA
     $10 $F1 $A5 $D3 $48 ]

DEFINE GetTemps=
   [ $68 $85 $D3 $A2 $00 $68
     $95 $A8 $68 $95 $80 $68
     $95 $A0 $68 $95 $C0 $E8
     $E0 $08 $D0 $EF ]

CARD OldVBI    ; Will hold previous
               ; contents of vertical
               ; blank interrupt
               ; vector.

; This procedure will change the background color to random values.
; The main routine will set up this code to operate during the
; deferred vertical blank interrupt.
PROC ChangeColor()
    BYTE hue, lum

    SaveTemps
    hue = Rand( 16 )
    lum = Rand( 16 )
    SetColor(2,hue,lum)
    GetTemps
[ $6C OldVBI ]  ; Vertical blank
                ; interrupts must end
                ; like this ($6C is a
                ; 6502 indirect jump
                ; instruction).

PROC Test()     ; Main routine
 BYTE critic=$42, ; Critical I/O flag
      console=$D01F ; Console key
         ; hardware location
 CARD VBIvec=$224 ; Deferred vertical
         ; blank interrupt vector

    ; You must install a VBI routine like this:
    critic = 1    OldVBI = VBIvec
    VBIvec = ChangeColor
    critic = 0

    ; ChangeColor is now running as the vertical blank interrupt
    ; routine-- since our mainline code has nothing more to do,
    ; we just go into a loop waiting for the START key to be
    ; pressed.
    WHILE console&1
      DO
      OD

    ; Now turn off the VBI routine.
    critic = 1
    VBIvec = OldVBI
    critic = 0
RETURN
}}}
This method of saving and restoring ACTION zero page variables may also be used to write BASIC machine language subroutines in ACTION! Your main ACTION routine should then have SaveTemps as the first executable line, and GetTemps as the last executable line before the RETURN statement.


!!BUGS IN THE ACTION! CARTRIDGES

The following is a list of all bugs we currently know exist in the ACTION! cartridge. We list these bugs separately from those in the RunTime library and/or the PAD disk or ToolKit, which occur in following pages. Each bug is described in detail and, when possible, bug fixes are given. Many of these bugs deal only with specific versions of ACTION!. To find out which version of ACTION! you own, type the following from the ACTION! monitor:
  ?$B000 [[RETURN]
Below is an actual copy of what printed following that command for one of our cartridges.
  45055,$B000 = 0 $0730 48 1840
              ^
To find out the version number, look at the character to the right of the equals sign (here printed with a caret under it).  The "0" in this case implies that the cartridge is version 3.0.  If yours has a "6", you own version 3.6, etc.  As of the date of this bug sheet, the current cartridge version is 3.6.

!1. OFFSETS 
Using a TYPE declaration will generate a spurious error whenever the code offset (contents of location $B5) is non-zero.
Affects:  All versions of the cartridge to date. (Presumably only noticed if using RunTime disk, though.)
Fix: Make all TYPE declarations before changing the code offset.
Example:
{{{
     ; Beginning of program --
     ; First, declare TYPEs
     TYPE IOCB =
      [
      BYTE Id, Devnum,
           Command, Status
      ]
      ; Then, if desired,
      ; change offset
      SET $B5 = $1000
      ; example: offset=4096
}}}

!2. OFFSETS
Using a code offset greater than $7FFF (i.e., a negative offset, if you consider it to be of type INT) causes the compiler to generate improper code.
Affects:  All versions, especially when used with the RunTime disk.
Fix:  No direct fix, but you may use the relocator program described later in this document (which is also usable with assembly language).

!3. ATARI DOS
Exiting to Atari DOS from ACTION! can cause a system crash if DUP.SYS is not present on the disk in drive 1.
Affects:  All versions, but only when used with Atari DOS.
Fix: Use DOS XL (or be careful when exiting to DOS).

!4. ARRAYS AND ELSEIF
We have just learned that there is a relatively obscure bug in ACTION! related to the use of ELSEIF. In particular, statements similar to the form ELSEIF a(i) = 0 THEN ... (where a is an ARRAY and i is a CARD OR INT), or statements like ELSEIF p^ = 0 THEN (where p is a POINTER) produce incorrect code.
Affects:  All versions
Fix:  There is no direct fix at this time. The best way around the problem seems to be to code something like this:
{{{
    t = a(i) ; t is an INTEGER
      ...
    ELSEIF t=0 THEN ...
}}}
This works properly.

!5. WRITING OBJECT FILES
If a monitor Write command fails because of a disk error (e.g., disk full, 162, or device done, 144), the IOCB is not properly closed. If the disk is hanged before another disk operation is performed, the new disk can have invalid data written to it.
Affects:  All versions
Fix:  If you get an error when writing an ACTION! object file, type the following command to the monitor:
{{{
      X Close( 1 ) [RETURN]
}}}
You can then erase the file which caused the error.

!6. HEX ARRAY SIZES
Hexadecimal values as array dimensions cause incorrect code to be generated.
Affects:  All versions
Fix:  Use decimal array dimensions.

!7. TYPE POINTER ARGUMENTS
PROC/FUNC declarations with record pointer arguments other than the first don't compile correctly. For example, the following code generates an error 7 (invalid argument list):
{{{
   TYPE REC=[...]
      ...
   PROC Test( BYTE x, REC POINTER p )
}}}
Affects:  All versions
Fix:  Omit the comma in the argument list for the PROC/FUNC, as in:
{{{
    PROC Test( BYTE x
               REC POINTER p )
}}}
As this is just a temporary fix, it may not work in future versions, but the correct declaration (with the comma) will.

!8. MONITOR LOCKUP
Typing the following command from the monitor will lock up the system:
{{{
      R* [[RETURN]
}}}
Affects:  All versions
Fix:  Don't do it!  If you do type that command, hit [[RESET]

!9. PADDLE FUNCTION
The Paddle function does not work properly in all versions of the ACTION! cartridge.
Affects:  Versions 3.0 to 3.5
Fix:  Make the following declaration in your program:
{{{
     BYTE ARRAY Paddle(4) = 624
}}}

!10. SOUND ON CHANNELS 3 AND 4
If you use a Sound() procedure call after having done any disk I/O, sound channels 3 and 4 will remain silent. This is because Atari's OS does not reset some of the serial control registers completely.
Affects:  Versions 3.0 to 3.5
Fix:  Type in and use the following procedure. You should call this before doing any Sound() calls and/or in place of any SndRst() calls:
{{{
   ; Contributed by Michael Ross
     PROC SoundOff()
         BYTE AudCtl = $D208,
              SSKCtl = $232,
              SKCtl  = $D20F
         SSKCtl = 3
         SKCtl  = 3
         AudCtl = 0
         SndRst()
     RETURN
}}}

!11. TYPE FIELDS AS PARAMETERS
Using fields of TYPEs as parameters to PROCs or FUNCs generates incorrect code. For example,
{{{
 MoveBlock( rec.addr1,
    rec.addr2, length )
}}}
Affects:  Versions 3.0 to 3.5
Fix:  Assign the TYPE field to a temporary variable and pass that as a parameter:
{{{
      temp1 = rec.addr1
      temp2 = rec.addr2
      MoveBlock(temp1,temp2,length)
}}}

!12. SASSIGN PROBLEMS
SAssign does not work properly when the source string has a length of zero.
Affects:  Versions 3.0 to 3.5
Fix:  No fix available at this time.

!13. CARD FIELDS IN TYPES
Accessing CARD fields of TYPEs generates incorrect code.
Affects:  Versions 3.0 to 3.2
Fix:  No fix available at this time.

!14. MOVEBLOCK PROBLEMS
MoveBlock does not move more than 256 bytes of data.
Affects:  Versions 3.0 to 3.2
Fix:  No fix at this time. You could write an ACTION! routine to do the equivalent.

!15. CONTROL-SHIFT RETURN
Using [[CS] RETURN to split a line into two lines generates garbage in the second line.
Affects:  Versions 3.0 and 3.1
Fix:  No fix available, but not a disastrous problem.

!16. DIVISION ERRORS
On old cartridges, neither the "/" operator nor the "MOD" operator works properly under certain conditions.
Affects:  Versions 3.0 and 3.1
Fix:  Insert the following code into your program before any of your own PROCedure or FUNCtion declarations (this can be done easily using INCLUDE):
{{{
    ; Copyright (c) 1983 by
    ; Action Computer Services
    ;
    ; Permission is granted to duplicate and/or distribute
    ; the contents of this file to ACTION! users.  Copies of
    ; this file may not be sold or used for monetary gain.

    PROC DivI=*() 
    [$20 $A06C $85 $86 $A2 $10
     $26 $82 $26 $83 $26 $86 $26
     $87 $38 $A5 $86 $E5 $84 $A8
     $A5 $87 $E5 $85 $90 $04 $85
     $87 $84 $86 $CA $D0 $E5 $A5
     $82 $2A $26 $83 $A6 $83
     $4C $A032]

    PROC RemI=*()
    [$20 DivI $86A5 $87A6 $60]

    SET $4EA=DivI
    SET $4EC=RemI
}}}

!17. ERROR ROUTINE NOT INITIALIZED
The address of the Error PROCedure is not restored by ACTION! if a user program has changed it.
Affects:  Versions 3.0 and 3.1
Fix:  Make sure to restore the original Error vector upon exiting a program, if you changed it.

!18. COMPLEX EXPRESSIONS IN UNTIL
Complex relational expressions in an UNTIL statement generate incorrect code. For example, 
{{{
    DO
     ...
     UNTIL a>0 AND b=3
    OD
}}}
Affects:  Versions 3.0 and 3.1
Fix:  Assign the expression to a temporary variable and test that variable, instead:
{{{
    DO
     ...
     temp = a>0 AND b=3
     UNTIL temp
    OD
}}}

!19. BANK SWITCH BUG
When loading and running compiled ACTION! object files from DOS, the system can crash when using older cartridges. This is because the ACTION! library is not accessible.
Affects:  Version 3.0 only
Fix:  Put the following program lines at the VERY BEGINNING of your main procedure (i.e., the last procedure in your program):
{{{
    BYTE bank = $D500
    ; This declares the variable
    ; 'bank' to reside at $D500.

    bank = 0 ; This must be the
    ; first executable statement.
}}}

!20. .COM PROGRAMS
Running compiled ACTION! programs as .COM files under OS/A+ causes those programs to execute twice.
Affects:  All versions, but only when using a version of OS/A+. DOS XL is not affected.
Fix:  Insert the following as the first global variable you declare:
{{{
    BYTE RTS=[$60]
    ; This MUST be the first line in your program,
    ; aside from comments and SET commands.
}}}

!21. PROC ADDRESSING
Under certain conditions, specifying the address of a procedure (e.g., to interface to a machine code routine) causes ACTION! to generate incorrect code which could cause your program to"hang".
Affects:  Versions 3.1 and 3.4
Fix:  Insert an empty code block after the declaration of a procedure whose address is specified.  For example:
{{{
    PROC CIO = $E456() []
    ; An empty code block!
}}}

!22. ERROR #3
If you get an ERROR 3 during a compile, the system hangs when you return to the editor.
Affects:  All versions
Fix:  Do not go to the editor until you type the following line to the monitor.  This command resets the ACTION! memory pointer.
{{{
    SET $E=$491^
}}}

!23. STRING INPUT
When using the string input library functions (InputS, InputSD, and InputMD), there must be room in the string for the termination EOL, even though the resulting string length will not include it.
Affects:  All versions
Fix:  Adjust your declaration appropriately.