Classic Computer Magazine Archive ANTIC VOL. 3, NO. 2 / JUNE 1984

Assembly language

Shortcuts to Success
A Guide to Atari Macro Graphics

by Thomas McNamee

Synopsis

This article explains the use of macros in assembly-language programming, and supplies a library of macros for graphics programming. To use the accompanying programs, you must use MAC/65, a macro assembler from Optimized Systems Software. The macros and demonstration program will run on any Atari computer.

Quick! Identify the following language:

0250  GRAPHICS 3
0260  COLOR 1
0270  SETCOLOR 4,0,4
0280  SETCOLOR 0,4,14
0290  PLOT 5,5
0300  DRAWTO 5,15
0310  DRAWTO 15,5
0320  DRAWTO 15,5
0330  DRAWTO 5,5
It's not BASIC, of course - that would have been too easy. But, when executed, it draws the same pink square on a grey background that BASIC would have drawn. This is, or will become, assembly language. More precisely, it is a series of commands, called macro calls, which can be expanded and compiled into executable 6502 machine code by a powerful tool called a macro assembler.

This article will explain macro assembly and demonstrate the ways in which macros can be used to simplify program generation. It will also provide you with a graphics library that can be used as easily as the above listing suggests. The MAC/65 macro assembler from Optimized Systems Software (OSS) must be used to run the macros and the demonstration program- included in this article.

What is Macro Assembly?

There is an unwritten rule in commercial software development: Never write the same code twice. Because macros are reusable, tested modules, they allow you to stick to this guideline. Also, because numeric and string parameters can be passed on to them, their execution can be affected during compilation without making it necessary to change the code.

I should explain at this point that there is an important distinction between run-time and compile-time behavior. Run-time behavior is, quite simply, what the code does during the process of execution. Once the assembler produces machine code, run-time behavior is frozen. For example, an LDA #$FF always loads 255 into the accumulator. Compile-time behavior, on the other hand, concerns the disposition of operations, operands, and pseudo-ops as they go through the assembly process.

Take a calculation, for example: LDA #$C0 + 1 becomes LDA #$Cl in machine code. Compile-time behavior depends to a significant degree on the assembler being used.

Consider this simple macro:

.MACRO LOADX
.IF %1 <255
  LDX #%1
  .ELSE
  LDX %1
  .ENDIF
.ENDM
All keywords that start with "." are commands to the assembler. They only affect compile-time behavior, and do not appear in the machine code after assembly. For example, a two- or three-byte LDX instruction would be compiled from the above listing.

Several commands are introduced in LOADX. The command % 1 means parameter 1." This parameter is passed in the macro call as shown in the following example:

0250 LOADX 7
The seven replaces every occurrence of % 1 in the macro. First, the .IF statement determines if it's less than 255. The .IF/.ELSE/.ENDIF assembler commands all make conditional assembly possible. In this case, the <255 test is true, so LDX #7 is compiled. If it were false, the assembler would assume that the passed parameter was a non-Zero-Page memory location, and the LDX would be compiled to a three-byte, absolute-addressed instruction.

As a macro call is assembled, it goes through a process called expansion. Listing 1 shows an example of this. Note that each time you call a macro, it is included in the program in its expanded form. As a result, if you use large macros, your program begins to consume huge amounts of memory. This is an important consideration when you're using macros. Because of this, it's usually more practical to incorporate a subroutine call to a single macro into your programs.

Macro Advantages

The use of macros is advantageous primarily because passed parameters can be used to customize a macro for any application. The GRAPHICS macro in Listing 3 will accept any argument that the BASIC GRAPHICS command will; it will also use a memory location if the argument is nine or greater. Another advantage is that once you've tested a macro, you have a known, useful piece of software at your disposal. Thus, a macro library, such as the one in Listing 3, constitutes a collection of reusable, tested routines that can be used any time they're needed in a program.

Library and Equate Files

Listing 3 contains macros that simulate many BASIC graphics commands. Once you've typed it in and saved it, you can use .INCLUDE to incorporate it into any of your programs. The use of macro libraries adds a great deal of efficiency to the process of program development, because it saves a good deal of composition and testing time.

It's also helpful to use function-oriented EQUate files in your programs These files give standard Atari mnemonic labels to commonly-used locations, and they can also be .INCLUDEd during assembly.

Listing 2 contains equates used by Listing 3, and should be .INCLUDEd before assembling the graphics macros.

The Graphics.lib File

The commands included in Listing 3 simulate Atari BASIC's commands as closely as possible. When compiled, however, they execute many times faster than BASIC. The following list describes each of these macros in brief:

GRAPHICS - Allows you to call Graphics Modes 0-8. However, you must allocate enough memory to permit the S: driver to open the screen. To do this, first calculate the memory requirements for the screen, display list and text window. Subtract this quantity from the address of the top of RAM, and store the result in APPMHI, which is equated in Listing 2. This macro uses all registers; upon exit, the Y-register contains the status.

COLOR - Stores the selected color-register number in a spare byte that is equated in Listing 2. Only the accumulator is used.

POSITION - Positions the cursor at the selected screen location. Only the accumulator is used. Note that the passed parameters must be literals, not memory locations.

PLOT - Plots a point in the selected COLOR at the X and Y coordinates, which are passed as %1 and % 2.

DRAWTO - Draws a straight line from the last point plotted to the passed coordinates. All registers are used.

SETCOLOR - Sets the selected register to the indicated hue and color. All registers are used.

Demonstration Program

Listing 4 is a short program that demonstrates the use of the above graphics macros, as well as the use of .INCLUDEd files. Before you assemble it, make sure that you have all four .INCLUDE files on a disk in your drive. GREQU.M65 is Listing 2 and GRAPHICS.LIB is Listing 3.

These listings and the application program detail the use of each graphics macro. With some experience, you can create your own library, thereby saving yourself a fair amount of programming and testing time. A good starting point would be to code two routines: SAVEREG and RESTORE. These should allow you to preserve all registers while making a subroutine jump or macro call.

Thomas McNamee is a software engineer for ManTech International in Alexandria, Virginia. He programs in FORTH, C, BASIC and 6502 assembly language, and has written for a number of computer publications.

Listing 1

            0350     COLOR 1
    =0001   M        .IF %1<16
3000 A901   M        LDA #%1
            M        .ELSE
            M        LDA %1
            M        .ENDIF
3002 8DF502 M        STA SPARE1
            M        .ENDM
            0360     SETCOLOR 4,0,4
     = 0001 M      .IF %1<16
3005 A204   M      LDX #%l
            M      .ELSE
            M      LDX %l
            M      .ENDIF
      =0000 M      .IF %2>16
            M      LDA   %2
            M      ASL   A
            M      ASL   A
            M      ASL   A
            M      ASL   A
                   .ELSE
3007 A900   M      LDA #%2*16
            M      .ENDIF
      =0001 M      .IF %3<16
3009 A004   M      LDY #%3
            M      .ELSE
            M      LDY %3
            M      .ENDIF
300B 9DC402 M      STA     COLOR0,X
300E 98     M      TYA
300F 290E   M      AND     #$0E
3011 18     M      CLC
3012 7DC402 M      ADC      COLOR0,X
3015 9OC402 M      STA      COLOR0,X
            M      .ENDM


Listing 2

0100  ;FILENAME: GREQU.M65
0110      .TITLE "GRAPHICS EQUATE FILE"
0120      .PAGE "GRAPHICS EQUATES"
0130  ;
0140  ; CURSOR
0150  ROWCRS =  $54     ; FULL SCREEN
0160  COLCRS =  $55
0170  TXTROW =  $0290   ; SPLIT SCREEN
0180  TXTCOL =  $0291
0190  ;
0200  ; SCREEN MEMORY
0210  SAVMSC =  $58      ; FULL SCREEN
0220  TXTMSC =  $0294    ; SPLIT SCREEN
0230  ;
0240  ; GRAPHICS MODE
0250  DINDEX = $57       ; FULL SCREEN
0260  TINDEX = $0293     ; SPLIT SCREEN
0270  ;
0280  ; SCREEN MARGINS
0290  LMARGN = $52
0300  RMARGN = $53
0310  ;
0320  ; DISPLAY LIST
0330  VDSLST = $0200      ; VECTOR FOR DLI
0340  SDLSTL = $0230      ; START OF DL
0350  WSYNC = $D40A
0360  ;
0370  ; MISC.
0380  BOTSCR = $02BF       ; LINES IN SCRE
EN (4 OR 24)
0390  SPARE1 = $02F5       ; SPARE BYTES
0400  SPARE2 = $02F6
0410  SPARE3 = $02F7
0420  SPARE4 = $02F8
0430  SPARE5 = $02F9
0440  ATACHR = $02FB       ; USED BY FILL &
DRAW
0450  ;
0460  ; CHARACTER SET
0470  CHBAS = $02F4        ; SHADOW
0480  CHBASE = $D409       ; HARDWARE
0490  CHACT = $02F4        ; CHAR. MODE REG
0500  ;
0510  ; COLORS
0520  ; SHADOW      REGISTERS
0530  COLOR0 = $02C4
0540  COLOR1 = $02C5
0550  COLOR2 = $02C6
0560  COLOR3 = $02C7
0570  COLOR4 = $02C8
0580  ; HARDWARE REGISTERS
0590  COLPF0 = $D016
0600  COLPF1 = $D017
0610  COLPF2 = $D018
0620  COLPF3 = $D019
0630  COLBK = $D01A
0640  ;
0650  ; INTERRUPT CONTROL
0660  NMIEN = $D40E      ; NMI ENABLE
0670  NMIST = $D40F      ; NMI STATUS
0680  NMIRES = $D40F      ; NMI RESET
0690  ;BIT: 7   6   5   43210
0700  ;    DLI VBI RESET.....
0710  ;
0720  ;   SCROLLING
0730  HSCROL = $D404
0740  VSCROL = $D405
0750  ;
0760  ; CIO COMMANDS
0770  CDRAW = $11
0780  CFILL = $12
0790  ;


Listing 3

0100  ;FILENAME: GRAPHICS.LIB
0110       .TITLE "GRAPHICS LIBRARY"
0120       .PAGE  "GRAPHICS MACRO"
0130  ;
0140       .IF .NOT  .DEF ROWCHS
0150         .ERROR  "GREQU.M65 missing!"
0160         .ENDIF
0170       .IF .NOT  .DEF CPALOC
0180         .ERROR  "SYSEQU.M65 missing!"
0190         .ENDIF
0200  ;
0210  ;MACRO: GRAPHICS
0220  ;
0230  ;FORM: GRAPHICS N
0240  ;If N is  <9, then N is a memory
0250  ;location,   else N is a literal
0260  ;
0270      .MACRO GRAPHICS
0280  ;
0290       JMP @CONT
0300   @AX1
0310        .BYTE 0
0320   @AX2
0330        .BYTE 0
0340   @CONT
0350            XIO 12,6,0,0,"S:"
0360            .IF %1<9
0370             LDA #%1
0380            .ELSE
0390            LDA %1
0400            .ENDIF
0410            STA @AX2
0420            AND #$F0
0430            EOR #$10
0440            ORA #$0C
0450            STA @AX1
0460            OPEN 6,@AX1,@AX2,"S:"
0470            .ENDM
0480            ,PAGE "COLOR, POSITION & PLOT
MACROS"
0490  ;
0500  ;MACRO: COLOR
0510  ;
0520  ;FORM: COLOR N
0530  ;If N < 16, then N is literal
0540  ;Else N is a memory location.
0550  ;
0560      .MACRO COLOR
0570      .IF %1<16
0580        LDA #%1
0590        .ELSE
0600        LDA %1
0610        .END IF
0620       STA SPARE 1
0630       .ENDM
0640  ;
0650  ;MACRO: POSITION
0660  ;
0670  ;FORM: POSITION X,Y
0680  ;X and Y must be literals, not
0690  ; memory locations
0700  ;
0710      .MACRO POSITION
0720      LDA # <%1
0730      STA COLCRS
0740      LDA # >%1
0750      STA COLCRS+1
0760      LDA #%2
0770      STA ROWCHS
0780      .ENDM
0790  ;
0800  ;MACRO: PLOT
0810  ;
0820  ;FORM: PLOT X,Y
0830  ; X and Y must be literals , not
0840  ;memory locations
0850  ;
0860      .MACRO PLOT
0870       POSITION %1,%2
0880       @CH 6
0890      LDA #CPBINR
0900      STA ICCOM,X
0910      LDA #0
0920      STA ICBLEN,X
0930      STA ICBLEN+1,X
0940      LDA SPARE1
0950      JSR CIO
0960      .ENDM
0970      .PAGE "DRAWTO & SETCOLOR MACR
0S"
0980  ;
0990  ;MACRO: DRAWTO
1000  ;
1010  ;FORM: DRAWTO X,Y
1020  ; X and Y must be literals as in
1030  ;POSITION
1040  ;
1050      .MACRO DRAWTO
1060       POSITION %1,%2
1070      LDA SPARE1
1080      STA ATACHR
1090       @CH  6
1100      LDA  #CDRAW
1110      STA  ICCOM,X
1120      LDA  #CCLOSE
1130      STA  ICAUX1,X
1140      LDA  #0
1150      STA  ICAUX2,X
1160      JSR  CIO
1170      .ENDM
1180  ;
1190  ;MACRO: SETCOLOR
1200  ;
1210  ;FORM: SETCOLOR REG,HUE,LUM
1220  ;Any parameter <16 is considered
1230  ;a memory location
1240  ;
1250      .MACRO SETCOLOR
1260      .IF %1<16
1270       LDX #%1
1280       .ELSE
1290       LDX %1
1300       .ENDIF
1310      .IF %2>16
1320       LDA %2
1330       ASL A
1340       ASL A
1350       ASL A
1360       ASL A
1370       .ELSE
1380       LDA #%2*16
1390       .ENDIF
1400       .IF %3<16
1410        LDY #%3
1420        .ELSE
1430        LDY %3
1440        .ENDIF
1450      STA COLOR0,X
1460      TYA
1470      AND  #$0E
1480      CLC
1490      ADC COLOR0,X
1500      STA CDLOR0,X
1510      .ENDM
1520  ;
1530  ;*** END OF GRAPHICS.LIB ***


Listing 4

0100  ;FILENAME: GRTEST.M65
0110      .OPT NO LIST ; Don't list ] INC
LUDE  filies
0120  ;
0130  ;These fiIes are on MAC/65 d1sk
0140      .INCLUDE #D:SYSEQU.M65
0150      .INCLUDE #D:IOMAC.LIB
0160  ;
0170  ; See text for these files
0180      .INCLUDE #D:GREQU.M65
0190      .INCLUDE #D:GRAPHICS.LIB
0200  ;
0210  GRMEM = 460         ;Bytes of memory
for  GR. 3
0220  ;
0230      *=    $3000
0240  ;
0250      .OPT LIST
0260  ;
0270  ;Set top of applications memory
0280      LDA # <$BFFF-GRMEM
0290      STA APPMHI
0300      LDA # >$BFFF-GRMEM
0310      STA APPMHI+1
0320  ;
0330  ; This Iooks like BASIC . . .
0340      GRAPHICS 3
0350      COLOR 1
0360      SETCOLOR 4,0,4
0370      SETCOLOR 0,4,14
0380      PLOT 5,5
0390      DRAWTO  5,15
0400      DRAWTO  15,15
0410      BRAWTO  15,5
0420      DRAWTO  5,5
0430  ;
0440  ;Loop until SYSTEM RESET
0450      END JMP END
0460          .OPT NO LIST
Listing 1: MACRO1.M65 Download / View

Listing 2: MACRO2.M65 Download / View

Listing 3: MACRO3.M65 Download / View

Listing 4: MACRO4.M65 Download / View