User Tools

Site Tools


magazines:discovery3
no way to compare when less than two revisions

Differences

This shows you the differences between two versions of the page.


magazines:discovery3 [2015-04-17 04:35] (current) – created - external edit 127.0.0.1
Line 1: Line 1:
 +<code>
  
 +        __  __             ______
 +        ||__|  ______   /  __  \   ______   __  __   ______    ____   __  __
 +   ____|  | __  /  __  \ |  |  |__|_/  __  \ |  ||  | /  __  \  /    \ |  ||  |
 +  /  __ / ||  ||  |__|__||  | |____/  |  |  ||  ||  ||  |__|  ||  ||__||  ||  |
 +  |  |  ||  |`\____  \ |  | |____\  |  |  ||  ||  ||   _____||  |  W |  ||  |
 +  |__|  ||  ||  |__|  ||  |__|  ||  |__|  ||  ||  ||  |__|  ||  |  a |  ||  |
 + `\_______||__|`\______/'`\______/'`\______/'`\____/'`\______/'| /'  D `\    /'
 +          _      _ __ ___ ____ ______________________________|/________|  |
 +                _ __ ___ ____ _________________________________________/'
 +
 +
 +             The   Journal   of   the   Commodore   Enthusiast
 +
 +
 +                      I s s u e  3  :  March 26, 1997
 +
 +
 +                             P R E A M B L E
 +
 +
 +Welcome to the third issue of disC=overy, the Journal of the Commodore
 +Enthusiast.  We greet you proudly, the ones who still hold the beloved
 +Commodore 8-bit machines in high regard and respect.  We thank you from
 +the bottom of our hearts and look forward to forging a solid productive
 +relationship with the C= 8-bit community.
 +
 +  - Mike Gordillo, Steven Judd, Ernest Stokes, George Taylor, and the
 +    authors of disC=overy.
 +
 +
 +
 +:::::::::::d:i:s:C=:o:v:e:r:y:::::::::::::::::i:s:s:u:e::3::::::::::::::::::::
 +::::::::::::::::::::::T A B L E  O F  C O N T E N T S:::::::::::::::::::::::::
 +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 
 +
 +
 +-Software Section-
 +
 +/S01 - "Rommaging around : $A480-$A856"
 +$a480   by Stephen L. Judd
 +
 +/S02 - "A Closer Look at the VIC II's Output"
 +$d000   by Adrian Gonzalez and George Taylor
 +
 +/S03 - "Innovation in the 90s : Revisiting The Super Hi-Res Flexible Line
 +$d000    Interpretation Technique"
 +        by Roland Toegel, 'Count Zero', and George Taylor
 +
 +/S04 - "Defeating Digital Corrosion (AKA "Cracking") - A beginner's guide
 +$dd00    to software archiving"
 +        by Jan Lund Thomsen
 +
 +/S05 - "A possibility to be explored : Real Time Video with the Ram Expansion
 +$df00    Unit"
 +        by Nate Dannenberg
 +
 +/S06 - "A look into 'The Fridge'"
 +$f00d   by Stephen L. Judd
 +
 +/S07 - "C128 CP/M, trailblazer in a jungle of formats"
 +0100h   by Mike Gordillo
 +
 +
 +-Hardware Section-
 +
 +/H01 - "The X-10 Powerhouse, What is it?"
 +        by Dan Barber
 +
 +/H02 - "The Metal Shop"
 +        with 'XmikeX', David Wood, Marc-Jano Knopp and Daniel Krug
 +
 +
 +-Legal Section-
 +
 +/L01 - Articles of Operation, Distribution, et al.
 +
 +
 +
 +:::::::::::d:i:s:C=:o:v:e:r:y:::::::::::::::::i:s:s:u:e::3::::::::::::::::::::
 +/S01::$A480:::::::::::::::::::S O F T W A R E:::::::::::::::::::::::::::::::::
 +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 +
 +
 +Rommaging around : $A480-$A856
 +----------------              by
 +                                Stephen L. Judd  (sjudd@nwu.edu)
 +                                
 +"Disassemble? ...Disassemble!!!" -- No. 5, 'Short Circuit'
 +
 +        This series has a simple goal: to completely disassemble and document
 +the Commodore 64 ROMs.  There is a nice ROM disassembly available on the
 +internet, with the actual hex code displayed and HTML hypertexted.  This
 +version, on the other hand, is written in a more 'human readable' form,
 +heavily commented and labeled, and is intended to complement the other.
 +To that end, it does not duplicate very much information which is easily
 +obtainable elsewhere (ftp.funet.fi, or Marko Makela's homepage, for instance).
 +
 +        BLARG is a program which adds several hires graphics commands to BASIC,
 +and was the main motivation to finally get started on this project.  This
 +article will thus focus on the BASIC routines from $A480 (Main Loop) to 
 +$A856 (END), with a goal of understanding how to add new commands to BASIC.
 +
 +        The first part of the article gives an overview of BASIC and its
 +internal workings, and sets up some of the things used later on.  The
 +second part discusses the parts of BASIC which relate specifically to
 +the disassembled ROM, with a focus on the vectored routines.  The third
 +part gives a brief overview of BLARG.  The ROM source, BLARG source,
 +and BLARG binaires are all included.  These files are all available at
 +
 +                http://stratus.esam.nwu.edu/~judd/fridge
 +
 +        About the ROM listings: I did them up in Merlinesque format of
 +course.  Probably the only unfamiliar thing is the concept of global
 +and local lables.  Local labels are prefixed with a colon, and their
 +definition is only valid between two global lables.  Otherwise they
 +may be redefined.  Thus a piece of code like
 +
 +PROC1   BNE :CONT
 +        INC TEMP1
 +:CONT   RTS
 +
 +PROC2   BNE :CONT
 +        INY
 +:CONT   DEC TEMP1
 +        RTS
 +
 +contains two global labels (PROC1 and PROC2).  PROC1 will branch to the RTS
 +instruction and PROC2 will branch to the DEC TEMP1 instruction, since the
 +:CONT label is redefined once the global label PROC2 appears.  The bottom line
 +is that if you see a branch to a local label, that label is nearby and
 +after the last global label.
 +
 +BASIC overview
 +--------------
 +
 +        Before starting, there are some important things to know about
 +BASIC.  When you type in a line of text, and hit [RETURN], that text
 +is entered into a text buffer located at $0200.  The text from this buffer
 +is then tokenized by the BASIC interpreter.  If it is an immediate mode
 +command (doesn't start with a line number) that command is then executed,
 +otherwise it is stored in memory as a BASIC program line.
 +        BASIC lines are stored in memory as follows:
 +
 +      ______________________________   _______________________  ...__
 +     /                              \ /                            \
 +0 [link] [line #] [Basic line] [0] [link] [line #] [Basic] [0]  ...  [0] [0]
 +|    |                |           
 +|    |                |          Link to next line
 +|    |                |       
 +|    |                |      End of line marker
 +|    |                |
 +|    |           Tokenized line of basic program
 +|    |       |
 +|    |     Two byte (lo,hi) line number
 +|    |
 +|  Two byte (lo,hi) pointer to next line in program
 +|
 +Beginning of program
 +
 +        A zero marks the beginning of the program, which normally begins
 +at $0800 (2048).  The next two bytes are the address in (lo,hi) form of
 +the next line in the program.  The following two bytes are the line
 +number for the current line.  Then the tokenized line of BASIC follows;
 +a null byte marks the end of the line.  The next line follows immediately.
 +A line link of value 0 (actually only the high byte needs to be 0) marks
 +the end of the program.
 +        Thus a program like
 +
 +        10 PRINT "HELLO"
 +
 +will in memory look like
 +
 +2048    0               ;Zero byte at beginning
 +2049    15              ;Next link = $080F = 15+8*256 = 2063
 +2050    8
 +2051    10              ;Line number = 10 + 0*256 = 10
 +2052    0
 +2053    153             ;PRINT token
 +2054    32              ;space
 +2055    34      "       ;quote
 +2056    72      H       ;PETSCII string
 +2057    69      E
 +2058    76      L
 +2059    76      L
 +2060    79      O
 +2061    34      "
 +2062    0               ;end of line
 +2063    0               ;end of program
 +2064    0
 +
 +        Variables begin immediately following the end of the program.
 +Strings are stored beginning at the top of memory ($9FFF) and work
 +their way downwards towards the variables.
 +
 +        Another very important feature of BASIC is that the important
 +routines are vectored.  These are indeed filled vectors -- filled with
 +the address of the routines in question.  The BASIC indirect vector
 +table is located at $0300-$030B:
 +
 +IERROR  $0300-$0301  Vector to print BASIC error message routine
 +IMAIN   $0302-$0303  Vector to main BASIC program loop
 +ICRNCH  $0304-$0305  Vector to CRUNCH routine (tokenize ASCII text)
 +IQPLOP  $0306-$0307  Vector to QPLOP routine (tokens -> ASCII)
 +IGONE   $0308-$0309  Vector to GONE, executes BASIC tokens
 +IEVAL   $030A-$030B  Vector to routine which evaluates single-term math
 +                     expression
 +
 +Calls to these routines are vectored through these addresses via an
 +indirect JMP -- they are called using JMP (IMAIN) for instance.  These
 +vectors may then be redirected to new routines, and so they provide
 +a smooth way of adding new keywords to BASIC.  CRUNCH is used to
 +tokenize lines of text when they are entered.  QPLOP is used by
 +LIST to print tokens to ASCII text.  GONE is used to execute tokens.
 +        Before modifying these vectors, keep in mind that many programs,
 +such as JiffyDOS, have already modified them!
 +
 +        Finally, the routines CHRGET and CHRGOT are very important
 +in BASIC.  They are copied into zero page when the system first starts
 +up, and are located at $0073:
 +
 +$73     CHRGET  INC TXTPTR      ;Increment low byte
 +$75             BNE CHRGOT
 +$77             INC TXTPTR+1    ;High byte if necessary
 +$79     CHRGOT  LDA             ;Entry here doesn't increment TXTPTR
 +$7A     TXTPTR  $0207           ;low byte, high byte -- the LDA operand.
 +                                ;Generally points at BASIC or points
 +                                ;at input buffer at $0200 when in
 +                                ;immediate mode.
 +$7C     POINTB  CMP #$3A        ;Set carry if > ASCII 9
 +$7E             BCS EXIT        ;Exit if not a numeral
 +$80             CMP #$20        ;Check for ASCII space
 +$82             BEQ CHRGET      ;...skip space and move to next char
 +$84             SEC
 +$85             SBC #$30        ;Digits 0-9 are ASCII $30-$39
 +$87             SEC
 +$88             SBC #$D0        ;Carry set if < ASCII 0 ($30)
 +$8A     EXIT    RTS
 +
 +On exit, the accumulator contains the character that was read; Carry clear
 +means character is ASCII digit 0-9, Carry set otherwise; Zero set if
 +character is a statement terminator 0 or an ASCII colon ($3A), otherwise
 +zero clear.
 +        Wedge programs make this their entry point -- by redirecting
 +CHRGET and CHRGOT a program can look at the input and act accordingly.
 +Scanning text can get awfully slow, which is why most wedge programs you
 +see use a single character to prefix wedge commands.
 +        Finally, a list of BASIC tokens is a handy thing to have, along
 +with the address of the routine which executes the statement:
 +
 +$80     END     43057 $A831
 +$81     FOR     42818 $A742
 +$82     NEXT    44318 $AD1E
 +$83     DATA    43256 $A8F8
 +$84     INPUT#  43941 $ABA5
 +$85     INPUT   43967 $ABBF
 +$86     DIM     45185 $B081
 +$87     READ    44038 $AC06
 +$88     LET     43429 $A9A5
 +$89     GOTO    43168 $A8A0
 +$8A     RUN     43121 $A871
 +$8B     IF      43304 $A928
 +$8C     RESTORE 43037 $A81D
 +$8D     GOSUB   43139 $A883
 +$8E     RETURN  43218 $A8D2
 +$8F     REM     43323 $A93B
 +$90     STOP    43055 $A82F
 +$91     ON      43339 $A94B
 +$92     WAIT    47149 $B82D
 +$93     LOAD    57704 $E168
 +$94     SAVE    57686 $E156
 +$95     VERIFY  57701 $E165
 +$96     DEF     46002 $B3B3
 +$97     POKE    47140 $B824
 +$98     PRINT#  43648 $AA80
 +$99     PRINT   43680 $AAA0
 +$9A     CONT    43095 $A857
 +$9B     LIST    42652 $A69C
 +$9C     CLR     42590 $A65E
 +$9D     CMD     43654 $AA86
 +$9E     SYS     57642 $E12A
 +$9F     OPEN    57790 $E1BE
 +$A0     CLOSE   57799 $E1C7
 +$A1     GET     43899 $AB7B
 +$A2     NEW     42562 $A642
 +
 +$A3     TAB(                    ;Keywords which never begin a statement
 +$A4     TO
 +$A5     FN
 +$A6     SPC(
 +$A7     THEN
 +$A8     NOT
 +$A9     STEP
 +
 +$AA           47210 $B86A     ;Math operators
 +$AB           47187 $B853
 +$AC           47659 $BA2B
 +$AD     /       47890 $BB12
 +$AE           49019 $BF7B
 +$AF     AND     45033 $AFE9
 +$B0     OR      45030 $AFE6
 +$B1     >       49076 $BFB4
 +$B2           44756 $AED4
 +$B3     <       45078 $B016
 +
 +$B4     SGN     48185 $BC39     ;Functions
 +$B5     INT     48332 $BCCC
 +$B6     ABS     48216 $BC58
 +$B7     USR     784   $0310
 +$B8     FRE     45949 $B37D
 +$B9     POS     45982 $B39E
 +$BA     SQR     49009 $BF71
 +$BB     RND     57495 $E097
 +$BC     LOG     47594 $B9EA
 +$BD     EXP     49133 $BFED
 +$BE     COS     57956 $E264
 +$BF     SIN     57963 $E26B
 +$C0     TAN     58036 $E2B4
 +$C1     ATN     58126 $E30E
 +$C2     PEEK    47117 $B80D
 +$C3     LEN     46972 $B77C
 +$C4     STR$    46181 $B465
 +$C5     VAL     47021 $B7AD
 +$C6     ASC     46987 $B78B
 +$C7     CHR$    46828 $B6EC
 +$C8     LEFT$   46848 $B700
 +$C9     RIGHT$  46892 $B72C
 +$CA     MID$    46903 $B737
 +
 +$CB     GO                      ;Makes GO TO legal.
 +
 +BASIC ROM
 +---------
 +        
 +        The BASIC ROM begins at $A000:
 +
 +$A000-$A001     Cold start vector
 +$A002-$A003     Warm start vector
 +$A004-$A00B     ASCII text "CBMBASIC"
 +
 +$A00C-$A051     Statement dispatch table
 +
 +        This is the first of several important tables used by BASIC.
 +When a new BASIC statement is to be executed the interpreter looks
 +here to find the address of the statement routine.  Each entry is
 +a two-byte vector containting the routine address minus one.  The
 +address is pushed onto the stack, so that the next RTS will jump
 +to the correct location.  The addresses are in token order, beginning
 +with token $80 (END) and ending with token $A2 (NEW):
 +
 +$A052-$A07F     Function dispatch vector table
 +
 +        This is another table of two-byte vectors for BASIC functions --
 +that is, commands which are followed by an argument inside of parenthesis,
 +for example INT(3.14159).  The entries are again in token order beginning
 +with token $B4 (SGN) and ending with token $CA (MID$).
 +
 +$A080-$A09D     Operator dispatch vector table
 +
 +        This table is for math operators, beginning with token $AA (+)
 +and ending with token $B3 (<).
 +
 +$A09E-$A19D     List of keywords
 +
 +        This is a table of all the reserved BASIC keywords.  The
 +high bit of the last character set, so it is easy to detect the end
 +of a keyword.  The keywords are listed in token order, so to find
 +the token corresponding to a given keyword the BASIC interpreter
 +simply moves down this list, counting as it goes.  If a match
 +occurs, then the token value is simply the counter value.
 +        The table is searched using SBC instead of CMP.  If the
 +result of the subtraction is $80 -- keywords end with the high bit set --
 +then a valid keyword has been found.  When input is placed into the
 +input buffer at $0200, character codes 192-223 are used for shifted
 +characters.  From this it should be clear why the keyboard shortcuts work,
 +for instance typing pO instead of poke.  It should also be clear why poK will
 +also work, but pokE will not work.
 +
 +$A19E-$A327     ASCII text of BASIC error messages (dextral character inverted)
 +$A328-$A364     Error message vector table
 +$A365-$A389     Miscellaneous messages (null-terminated)
 +
 +$A38A-$A47F     Some BASIC routines, to be be disassembled at a later date
 +
 +$A480           Main loop
 +
 +        Since the goal is to get a good enough understanding of BASIC to
 +add new keywords, the main program loop is a good place to start.  This
 +routine is vectored through IMAIN at $0302.  It gets a line of input
 +from the keyboard, checks for a line number, and processes the line
 +appropriately.
 +        When I started programming BLARG, I had no idea what routines like
 +CRUNCH were expected to return -- is the Y register expected to have
 +a certain value upon exit?  Or maybe a certain variable needs to be
 +set up so that another routine may reference it?  Thus it is a good
 +idea to begin at the main loop and see how a line is normally
 +processed.  The disassembly listing begins at this point.
 +
 +        Other important vectored routines are:
 +
 +$A579           CRUNCH
 +
 +        This routine goes through the BASIC text buffer at $0200 and
 +tokenizes any keywords which aren't in quotes.  As the routine begins
 +to scan the input buffer it discards any characters which have their
 +high bit set, such as shifted characters.  (This is only in the
 +initial search for keywords -- shifted characters within quotes or
 +as part of a keyword are taken care of by another routine).  As
 +a practical matter, this means that any routine which adds extra
 +tokens must call this routine _first_, since it will just skip over
 +custom tokens otherwise!
 +        When it is finished processing the input buffer, the
 +input buffer contains the tokenized line, terminated by a null
 +byte, _and_ with another null byte at the end of the line +2 (much
 +like the terminating byte which marks the end of a program).  See
 +the disassembly and blarg source for other things which are set up.
 +
 +$A717   QPLOP
 +
 +        This is the part of the LIST routine (which begins at $A69C)
 +which converts tokens into ASCII characters and prints them to the
 +screen.
 +
 +$A7E4   GONE
 +
 +        This is the routine which gets the next token (every statement
 +begins with a token or an implied LET) and executes the appropriate command.
 +Invalid tokens generate a SYNTAX ERROR.  Character values less than 128 cause
 +LET to be executed.
 +        The IF/THEN routine actually bypasses the IGONE vector and jumps
 +directly into this routine, which means that lines like
 +        IF A=0 THEN MYCOMMAND
 +will generate a syntax error.  BLARG currently has no mechanism for
 +getting around this (because I did not discover this until recently,
 +and the article deadline was several days ago :), except to place a
 +colon after the THEN, i.e. IF A=0 THEN:MYCOMMAND.  Apparently some
 +programs get around this by defining their own IF statement; probably
 +the best way to get around it is to redirect the IERROR vector.
 +When an error is generated, check to see if it is a custom token,
 +then check to see if it was preceded by a THEN token.
 +
 +BLARG
 +-----
 +        By now, we have all the necessary information to add new keywords
 +to BASIC.  To that end I present BLARG, which adds several hires bitmap
 +commands to BASIC.  As a bonus, BLARG can take advantage of a SuperCPU
 +if you have one.  These commands are much faster than the 128's BASIC7.0
 +commands and in my quite biased opinion much more intuitive.  The CIRCLE
 +and LINE commands are adaptations of my routines from C=Hacking; look there
 +for more info on the actual routines.
 +        Some things in BLARG are done a little differently than their
 +corresponding BASIC routines, in large part because I wrote some of the
 +routines before disassembling the BASIC ones.
 +        BLARG documentation is below.
 +
 +References
 +----------
 +        I have found Mapping the 64 to be an invaluable reference, along
 +with "Programming the Commodore 64", by Raeto West.  ftp.funet.fi has
 +some good documentation, and I use Marko Makela's web page quite
 +often at http://www.hut.fi/~msmakela -- there are many useful documents
 +there, including a complete html cross-referenced ROM listing.
 +
 +
 +
 +*                       
 +* A480-A856  (MAIN-END)
 +*   Basic ROM disassembly starting with main loop
 +*
 +* Stephen L. Judd 1997
 +*
 +
 +*
 +* Labels are at the end of the listing, along with a list
 +* of major routines and their addresses.
 +*
 +                          
 +*                          
 +* MAIN -- Main loop, receives input and executes
 +* immediately or stores as a program line.
 +*
 +
 +* $A480                          
 +JMPMAIN  JMP (IMAIN)      ;Main loop, below
 +                          ;Vectored through IMAIN, so it
 +                          ;may be redirected.
 +MAIN     JSR INLIN        ;Input a line from keyboard
 +         STX TXTPTR       
 +         STY TXTPTR+1     
 +         JSR CHRGET       ;Get 1st char out of buffer
 +         TAX             
 +         BEQ JMPMAIN      ;Empty line
 +         LDX #$FF         ;Signal that BASIC is in immediate
 +         STX CURLIN+1     ;mode.
 +         BCC MAIN1        ;CHRGET clears C when digit is read
 +         JSR CRUNCH       ;Tokenize line
 +         JMP JMPGONE      ;Execute line
 +
 +*                          
 +* MAIN1 -- Add or replace a line of program text.
 +*
 +* TEMP2 points to the current line to be deleted
 +* TEMP1 will point to the start of memory to be copied
 +* INDEX1 will point to the destination for the copy
 +
 +* $A49C
 +MAIN1    JSR LINGET       ;Convert ASCII to binary line number
 +         JSR CRUNCH       ;Tokenize buffer
 +         STY COUNT        ;Y=length of line
 +         JSR FINDLINE     ;Find the address of the line number
 +         BCC :NEWLINE
 +         LDY #$01         ;Replace line of text
 +         LDA (TEMP2),   ;$5F = pointer to line
 +         STA TEMP1+1      ;(TEMP1) = xx, Hi byte of next line
 +         LDA VARTAB       ;End of BASIC program
 +         STA TEMP1        ;(TEMP1) = basic end, high next
 +         LDA TEMP2+1    
 +         STA INDEX1+1     ;(INDEX1) = xx, Hi byte current line
 +         LDA TEMP2        ;Compute -length of current line
 +         DEY              
 +         SBC (TEMP2),   ;Current address - next address
 +         CLC              
 +         ADC VARTAB       ;end - (length of line to be deleted)
 +         STA VARTAB
 +         STA INDEX1       ;(INDEX1) = bytes to delete, high current
 +         LDA VARTAB+1     ;Back up end of program if necessary
 +         ADC #$FF         
 +         STA VARTAB+1     
 +         SBC TEMP2+1      ;Number of pages of memory to move
 +         TAX 
 +         SEC
 +         LDA TEMP2        ;Pretty confusing, eh?
 +         SBC VARTAB
 +         TAY              ;256 - number of bytes to move
 +         BCS :CONT1       
 +         INX              
 +         DEC INDEX1+1
 +:CONT1   CLC              
 +         ADC TEMP1        ;old basic end - number of bytes to move
 +         BCC :CONT2       
 +         DEC TEMP1+1
 +         CLC              
 +:CONT2   LDA (TEMP1),   ;Delete old line, fall through to create
 +         STA (INDEX1),  ;new line.
 +         INY              
 +         BNE :CONT2      
 +         INC TEMP1+1      
 +         INC INDEX1+1          
 +         DEX              
 +         BNE :CONT2       
 +
 +:NEWLINE JSR RESCLR       ;Reset variables and TXTPTR
 +         JSR LINKPRG      ;Relink program lines
 +         LDA BUF          
 +         BEQ JMPMAIN      ;Empty statement -- nothing to do
 +         CLC              
 +         LDA VARTAB       ;Start of variables
 +         STA $5A          
 +         ADC COUNT
 +         STA $58          ;Start of vars after line is added
 +         LDY VARTAB+1     
 +         STY $5B          
 +         BCC :CONT3       
 +         INY              
 +:CONT3   STY $59          
 +         JSR MALLOC       ;Open up some space in memory
 +         LDA LINNUM       ;Number of line to be added
 +         LDY LINNUM+1     
 +         STA H01FE        ;Rock bottom on the stack.
 +         STY H01FF        
 +         LDA STREND       ;Bottom of strings to top of variables
 +         LDY STREND+1     
 +         STA VARTAB       
 +         STY VARTAB+1     
 +         LDY COUNT        ;Number of chars in BUF
 +         DEY              
 +:LOOP    LDA BUF-4,     ;Copy buffer contents into program
 +         STA (TEMP2),   
 +         DEY              
 +         BPL :LOOP        
 +         JSR RESCLR        
 +         JSR LINKPRG      
 +         JMP JMPMAIN      ;Wheeeeeeee...
 +
 +*
 +* LINKPRG -- Relink lines of program text
 +*
 +* $A533                          
 +LINKPRG  LDA TXTTAB       ;Start of BASIC text
 +         LDY TXTTAB+1     
 +         STA TEMP1        
 +         STY TEMP1+1      
 +         CLC              
 +:LOOP1   LDY #$01         
 +         LDA (TEMP1),   
 +         BEQ :RTS         ;0 means end of program
 +         LDY #$04         ;Skip link, line number, and 1st char
 +:LOOP2   INY              
 +         LDA (TEMP1),   
 +         BNE :LOOP2       ;Find end of line
 +         INY              
 +         TYA              
 +         ADC TEMP1        ;Add offset to pointer to get address
 +         TAX              ;of next line
 +         LDY #$00         
 +         STA (TEMP1),   ;And store in link
 +         LDA TEMP1+1      
 +         ADC #$00         
 +         INY              
 +         STA (TEMP1),   
 +         STX TEMP1        ;Move to next line
 +         STA TEMP1+1      
 +         BCC :LOOP1       ;Keep on truckin'!
 +:RTS     RTS              
 +
 +*
 +* INLIN -- Input a line from keyboard to buffer
 +*
 +* $A560
 +INLIN    LDX #$00         
 +:LOOP    JSR HE112        ;BASIC's way of calling Kernal routines
 +         CMP #$0D         
 +         BEQ :DONE        
 +         STA BUF,X        
 +         INX              
 +         CPX #$59         ;Maximum buffer size = 88 chars
 +         BCC :LOOP        
 +         LDX #$17         ;STRING TOO LONG error
 +         JMP ERROR        
 +:DONE    JMP HAACA        ;Part of the PRINT routine
 +
 +*
 +* CRUNCH -- Tokenize a line of text contained in the input buffer
 +*
 +* $A579
 +*
 +* On exit:
 +*   Y = last character of crunched text + 4
 +*   X = last char of input buffer read in.
 +*   TEXTPTR = $01FF
 +*   GARBFL = 00 if colon was read, $49 if DATA statement,
 +*            04 otherwise.
 +*   ENDCHR = $22 (if quote was found) or 0 (if REM)
 +*   COUNT = Last token read - 128 (contrary to what
 +*                                  Mapping the 64 says)
 +*   TEMP1 = More or less random
 +*   BUF = Tokenized text, followed by a 00, random byte, and 00
 +*
 +
 +CRUNCH                    ;$A579
 +         JMP (ICRNCH)     
 +         LDX TXTPTR       ;Low byte
 +         LDY #$04         
 +         STY GARBFL       
 +                          
 +MAINLOOP LDA BUF,X        ;Search input buffer for text
 +         BPL :GOTCHAR     ;characters or #$FF
 +         CMP #$FF         
 +         BEQ STALOOP      
 +         INX              
 +         BNE MAINLOOP         
 +                          
 +:GOTCHAR CMP #$20         ;Is it a space?
 +         BEQ STALOOP      
 +         STA ENDCHR       
 +         CMP #$22         ;Is it a quote?
 +         BEQ QUOTE2       
 +         BIT GARBFL       ;This either equals 00 if a
 +                          ;colon was hit, $49 if a DATA
 +                          ;statement was found, and #04
 +                          ;initially.  Thus, it prints the
 +                          ;text within DATA statements.
 +         BVS STALOOP      
 +         CMP #'?'         ;Short print
 +         BNE :CONT1       
 +         LDA #$99         ;Print token
 +         BNE STALOOP      
 +                          
 +:CONT1   CMP #'0'         ;Check for a number,
 +         BCC :NOTNUM       
 +         CMP #'<'         ;colon, or semi-colon
 +         BCC STALOOP      
 +                          
 +:NOTNUM  STY TEMP1        ;So, search for a keyword
 +         LDY #$00         
 +         STY COUNT        
 +         DEY              
 +         STX TXTPTR       
 +         DEX              
 +                          
 +FINDWORD INY              ;Find keyword
 +         INX              
 +CMPWORD  LDA BUF,X        ;Match against keyword table
 +         SEC              
 +         SBC RESLST,    
 +         BEQ FINDWORD     
 +         CMP #$80         ;High bit of last char is set
 +                          ;Also means p shift-O gives short
 +                          ;version of POKE (for instance),
 +                          ;as should po shift-K.
 +         BNE NEXTWORD     
 +         ORA COUNT        ;A now contains token value
 +STABUF   LDY TEMP1        ;Crunched text index
 +STALOOP  INX              ;Store text in crunched buffer
 +         INY              
 +         STA BUF-5,     
 +         LDA BUF-5,     ;Goofy -- use AND #$FF or CMP #0
 +         BEQ ALLDONE      ;Zero byte terminates string
 +         SEC              
 +         SBC #$3A         ;Is it a colon?
 +         BEQ :COLON       
 +         CMP #$49         ;Was it $83, a DATA statement?
 +         BNE :SKIP        
 +:COLON   STA GARBFL       
 +:SKIP    SEC              
 +         SBC #$55         ;Was it $8F, a REM statement?
 +         BNE MAINLOOP         
 +         STA ENDCHR       ;If REM, then read rest of line
 +                          
 +QUOTE    LDA BUF,X        ;Look for matching quote char
 +         BEQ STALOOP      ;or end of statement, and embed
 +         CMP ENDCHR       ;text directly.
 +         BEQ STALOOP      
 +QUOTE2   INY              
 +         STA BUF-5,     
 +         INX              
 +         BNE QUOTE        
 +                          
 +NEXTWORD LDX TXTPTR       ;Skip to next keyword
 +         INC COUNT        ;Next token
 +:LOOP    INY              
 +         LDA RESLST-1,  ;Find last char
 +         BPL :LOOP        
 +         LDA RESLST,    
 +         BNE CMPWORD      
 +         LDA BUF,X        
 +         BPL STABUF       
 +                          
 +ALLDONE  STA BUF-3,     
 +         DEC TXTPTR+1     
 +         LDA #$FF         
 +         STA TXTPTR       
 +         RTS              
 +
 +*
 +* FINDLINE
 +*   Search for the line number contained in $14.  If found, set $5F
 +*   to link address and set carry.  Carry clear means line number
 +*   not found.
 +*
 +
 +* $A613                          
 +FINDLINE LDA TXTTAB       ;Start of program text
 +         LDX TXTTAB+1     
 +:LOOP    LDY #$01         
 +         STA TEMP2        
 +         STX TEMP2+1      
 +         LDA (TEMP2),   
 +         BEQ :EXIT        ;Exit if at end of program
 +         INY          
 +         INY              
 +         LDA LINNUM+1     ;High byte
 +         CMP (TEMP2),   
 +         BCC :RTS         ;Less than -> line doesn't exist
 +         BEQ :CONT1        
 +         DEY              
 +         BNE :CONT2       ;...always taken
 +:CONT1   LDA LINNUM       ;Compare low byte
 +         DEY              
 +         CMP (TEMP2),   
 +         BCC :RTS         ;Punt when past line number
 +         BEQ :RTS         ;Success!
 +:CONT2   DEY              ;Get next line link
 +         LDA (TEMP2),Y
 +         TAX              
 +         DEY              
 +         LDA (TEMP2),   
 +         BCS :LOOP
 +:EXIT    CLC              
 +:RTS     RTS
 +                          
 +* Perform NEW
 +* $A642
 +NEW      BNE *-2          ;RTS above
 +         LDA #$00
 +         TAY
 +         STA (TXTTAB),  ;Zero out first two bytes of program
 +         INY              
 +         STA (TXTTAB),  
 +         LDA TXTTAB       
 +         CLC              
 +         ADC #$02         
 +         STA VARTAB       ;Move end of BASIC to begin+2
 +         LDA TXTTAB+1     
 +         ADC #$00         
 +         STA VARTAB+1     
 +RESCLR   JSR RUNC         ;Reset TXTPTR
 +         LDA #$00         
 +
 +* Perform CLR (Calcium Lime and Rust remover!)
 +* $A65E
 +CLEAR    BNE CLEAREND     
 +         JSR CLALL        ;Close files
 +         LDA MEMSIZ       ;Highest address used by BASIC
 +         LDY MEMSIZ+1
 +         STA FRETOP       ;Bottom of string text storage
 +         STY FRETOP+1
 +         LDA VARTAB       ;End of BASIC program/variable start
 +         LDY VARTAB+1     
 +         STA ARYTAB       ;Start of array storage
 +         STY ARYTAB+1
 +         STA STREND       ;End of array storage/start of free RAM
 +         STY STREND+1     
 +         JSR RESTORE      
 +         LDX #$19         
 +         STX TEMPPT       ;Temporary string stack
 +         PLA              
 +         TAY              
 +         PLA              
 +         LDX #$FA         ;Reset stack
 +         TXS              
 +         PHA              ;Restore correct return address
 +         TYA              
 +         PHA              
 +         LDA #$00         
 +         STA OLDTXT+1     ;Address of current basic statement
 +         STA SUBFLG       ;
 +CLEAREND RTS              
 +
 +*                          
 +* RUNC -- reset current text character pointer to the
 +* beginning of program text.
 +*
 +* $A68E
 +RUNC     CLC              
 +         LDA TXTTAB       
 +         ADC #$FF         
 +         STA TXTPTR       
 +         LDA TXTTAB+1     
 +         ADC #$FF         
 +         STA TXTPTR+1     
 +         RTS              
 +                         
 +
 +* LIST -- perform LIST
 +* entered via return from CHRGET
 +*
 +* $A69C
 +LIST     BCC :SKIP        ;Is next char an ASCII digit
 +         BEQ :SKIP        ;Is next char ':' or 00
 +         CMP #$AB         ;Is next char '-' (token)
 +         BNE CLEAREND     ;RTS, above
 +:SKIP    JSR LINGET       ;Read decimal, convert to number
 +         JSR FINDLINE     ;Find line number
 +         JSR CHRGOT       ;Get char again
 +         BEQ :CONT        ;statement terminator
 +         CMP #$AB         
 +         BNE NEW-1        ;RTS
 +         JSR CHRGET       ;Advance and get end of
 +         JSR LINGET       ;range to list xx-xx
 +         BNE NEW-1        ;RTS
 +:CONT    PLA              
 +         PLA              
 +         LDA LINNUM       
 +         ORA LINNUM+1     
 +         BNE LISTLOOP     
 +         LDA #$FF         ;Signal to list program to end
 +         STA LINNUM       
 +         STA LINNUM+1     
 +LISTLOOP LDY #$01         
 +         STY GARBFL       
 +         LDA (TEMP2),   
 +         BEQ ENDLIST      
 +         JSR TESTSTOP     ;Test for STOP key
 +         JSR HAAD7        ;part of PRINT routine
 +         INY              
 +         LDA (TEMP2),   
 +         TAX              
 +         INY              
 +         LDA (TEMP2),   
 +         CMP LINNUM+1     ;Check to see if at last line
 +         BNE :CONT1       
 +         CPX LINNUM       
 +         BEQ :CONT2       
 +:CONT1   BCS ENDLIST      
 +:CONT2   STY FORPNT       ;temporary storage
 +         JSR LINPRT       ;Print line number
 +         LDA #$20         ;space
 +LISTENT1 LDY FORPNT       
 +         AND #$7F         ;strip high bit
 +LISTENT2 JSR HAB47        ;Prints char, AND #$FF
 +         CMP #$22         ;Look for a quote
 +         BNE :CONT        
 +         LDA GARBFL       
 +         EOR #$FF         
 +         STA GARBFL       
 +:CONT    INY              ;$A700
 +         BEQ ENDLIST      ;256 character lines perhaps?
 +         LDA (TEMP2),   
 +         BNE JMPPLOP      ;Print the token
 +         TAY              ;Get line link
 +         LDA (TEMP2),   
 +         TAX              
 +         INY              
 +         LDA (TEMP2),   
 +         STX TEMP2        
 +         STA TEMP2+1      
 +         BNE LISTLOOP     
 +ENDLIST  JMP HE386        ;Exit through warm start
 +
 +*                          
 +* QPLOP -- print BASIC tokens as ASCII characters.
 +*
 +* $A717
 +JMPPLOP  JMP (IQPLOP)     
 +QPLOP    BPL LISTENT2     ;Exit if not a token
 +         CMP #$FF         
 +         BEQ LISTENT2     
 +         BIT GARBFL       
 +         BMI LISTENT2     ;Exit if inside a quote
 +         SEC              
 +         SBC #$7F         ;Table offset+1
 +         TAX              
 +         STY FORPNT       ;Temp storage
 +         LDY #$FF         
 +:LOOP1   DEX              ;Traverse the keyword table
 +         BEQ :PLOOP       
 +:LOOP2   INY              ;read a keyword
 +         LDA RESLST,  
 +         BPL :LOOP2       
 +         BMI :LOOP1       
 +:PLOOP   INY              ;Print out the keyword
 +         LDA RESLST,  
 +         BMI LISTENT1     ;Exit if on last char
 +         JSR HAB47        ;Print char, AND #$FF
 +         BNE :PLOOP       
 +
 +*                          
 +* Perform FOR
 +*
 +* $A742
 +FOR      LDA #$80         
 +         STA SUBFLG       
 +         JSR LET
 +         JSR FINDFOR
 +         BNE :CONT
 +         TXA              
 +         ADC #$0F         
 +         TAX              
 +         TXS              
 +:CONT    PLA
 +         PLA              
 +         LDA #$09         
 +         JSR CHKSTACK     
 +         JSR ENDSTAT      
 +         CLC              
 +         TYA              
 +         ADC TXTPTR       
 +         PHA              
 +         LDA TXTPTR+1     
 +         ADC #$00         
 +         PHA              
 +         LDA CURLIN+1     
 +         PHA              
 +         LDA CURLIN       
 +         PHA              
 +         LDA #$A4         
 +         JSR CHKCOM       
 +         JSR HAD8D        
 +         JSR FRMNUM       
 +         LDA FACSGN       
 +         ORA #$7F         
 +         AND $62          
 +         STA $62          
 +         LDA #$8B         
 +         LDY #$A7         
 +         STA TEMP1        
 +         STY TEMP1+1      
 +         JMP HAE43        
 +                          
 +         LDA #$BC         
 +         LDY #$B9         
 +         JSR MTOFAC       
 +         JSR CHRGOT       
 +         CMP #$A9         
 +         BNE HA79F        
 +         JSR CHRGET       
 +         JSR FRMNUM       
 +HA79F    JSR SIGN         
 +         JSR HAE38        
 +         LDA $4A          
 +         PHA              
 +         LDA FORPNT       
 +         PHA              
 +         LDA #$81         
 +         PHA              
 +      
 +*                    
 +* NEWSTT -- Set up next statement for execution.
 +*
 +* $A7AE
 +NEWSTT   JSR TESTSTOP     
 +         LDA TXTPTR       
 +         LDY TXTPTR+1     
 +         CPY #$02         ;Text buffer?
 +         NOP              
 +         BEQ :CONT        
 +         STA OLDTXT       
 +         STY OLDTXT+1     
 +:CONT    LDY #$00         ;End of last statement.
 +         LDA (TXTPTR),  
 +         BNE HA807        ;branch into GONE
 +         LDY #$02         
 +         LDA (TXTPTR),  ;End of program?
 +         CLC              
 +         BNE :CONT2       
 +         JMP HA84B        ;exit through END
 +
 +:CONT2   INY              
 +         LDA (TXTPTR),  ;Line number
 +         STA CURLIN       
 +         INY              
 +         LDA (TXTPTR),  
 +         STA CURLIN+1     
 +         TYA              
 +         ADC TXTPTR       ;Advance pointer
 +         STA TXTPTR       
 +         BCC JMPGONE      
 +         INC TXTPTR+1     
 +                         
 +
 +* GONE -- Read and execute next statment
 +*
 +* $A7E1
 +JMPGONE  JMP (IGONE)      
 +         JSR CHRGET       
 +         JSR GONE         
 +         JMP NEWSTT       
 +* $A7ED
 +GONE     BEQ :RTS         ;Exit if statement terminator
 +         SBC #$80         
 +         BCC :JMPLET      ;If not a token then a variable
 +         CMP #$23         ;Tokens above $A3 never begin
 +         BCS CHKGOTO      ;a statement (except GO TO)
 +         ASL              ;Otherwise, get entry point
 +         TAY              ;of the statement...
 +         LDA STATVEC+1,Y  
 +         PHA              
 +         LDA STATVEC,   
 +         PHA              
 +         JMP CHRGET       ;... so CHRGET can RTS to it.
 +                          
 +:JMPLET  JMP LET          
 +                          
 +HA807    CMP #':'
 +         BEQ JMPGONE
 +JMPSYN   JMP SYNERR       
 +                          
 +CHKGOTO  CMP #$4B         ;Is it "GO TO"?
 +         BNE JMPSYN       
 +         JSR CHRGET       
 +         LDA #$A4         ;Make sure next char is "TO"
 +         JSR CHKCOM       ;token, and skip it.
 +         JMP GOTO
 +
 +
 +* Perform RESTORE
 +*
 +* $A81D
 +RESTORE  SEC              
 +         LDA TXTTAB       ;Set DATA pointer to start of program
 +         SBC #$01         
 +         LDY TXTTAB+1     
 +         BCS :CONT
 +         DEY              
 +:CONT    STA DATPTR       ;Address of current DATA item
 +         STY DATPTR+1
 +:RTS     RTS              
 +                          
 +TESTSTOP JSR STOP         
 +         BCS END+1        
 +
 +*
 +* END -- perform END
 +*
 +* $A831
 +END      CLC
 +         BNE $A870        ;RTS
 +         LDA TXTPTR
 +         LDY TXTPTR+1
 +         LDX CURLIN+1     ;Current line number
 +         INX              
 +         BEQ :CONT1       ;Branch if in immediate mode
 +         STA OLDTXT       ;Save statement address for CONT
 +         STY OLDTXT+1
 +         LDA CURLIN
 +         LDY CURLIN+1
 +         STA OLDLIN       ;Restored by CONT
 +         STY OLDLIN+1
 +:CONT1   PLA              ;Discard return address
 +         PLA
 +* $A84B
 +HA84B    LDA #$81         ;Message at $A381
 +         LDY #$A3
 +         BCC :CONT2
 +         JMP $A469        ;BREAK
 +:CONT2   JMP $E386        ;BASIC warm start
 +
 +                          
 +
 +ENDCHR   = $0008          ;See CRUNCH
 +COUNT    = $0B            
 +GARBFL   = $000F          ;Work byte
 +SUBFLG   = $0010          
 +LINNUM   = $14            
 +TEMPPT   = $0016          ;Next available space in temp string stack
 +TEMP1    = $22            ;Temporary pointer/variable
 +INDEX1   = $0024          
 +TXTTAB   = $002B          ;Pointer to start of BASIC text
 +ARYTAB   = $002F          ;Pointer to start of arrays
 +STREND   = $0031          ;End array storage/start free RAM
 +FRETOP   = $0033          ;End of string text/top free RAM
 +MEMSIZ   = $0037          ;Highest address used by BASIC
 +CURLIN   = $39            ;Current BASIC line number
 +OLDTXT   = $003D          ;Pointer to current BASIC statement
 +DATPTR   = $0041          ;Pointer to current DATA item
 +FORPNT   = $0049          ;Temp pointer to FOR index variable
 +TEMP2    = $5F            
 +FAC1     = $61
 +FACSGN   = $0066          
 +TEMP1    = $71            
 +FBUFPT   = $0071          
 +CHRGET   = $0073          ;Get next BASIC text char
 +CHRGOT   = $0079          ;Get current BASIC text char
 +TXTPTR   = $7A            ;Text pointer
 +H01FE    = $01FE          
 +H01FF    = $01FF          
 +BUF      = $0200          ;Text input buffer
 +IMAIN    = $0302          ;System vectors
 +ICRNCH   = $0304          
 +IQPLOP   = $0306          
 +IGONE    = $0308          
 +STATVEC  = $A00C          ;Statement dispatch vector table
 +RESLST   = $A09E          ;Reserved keywords list
 +FINDFOR  = $A38A          ;Find FOR on stack
 +MALLOC   = $A3B8          ;Make space for new line or var
 +CHKSTACK = $A3FB          ;Check for space on stack
 +ERROR    = $A437          ;General error handler
 +END      = $A831          ;Perform END
 +GOTO     = $A8A0          ;Perform GOTO
 +ENDSTAT  = $A906          ;Search for end of statement
 +                          ;(00 or colon)
 +LINGET   = $A96B          ;Convert ASCII decimal to 2-byte line number
 +LET      = $A9A5          ;Perform LET
 +HAACA    = $AACA          
 +HAAD7    = $AAD7          
 +HAB47    = $AB47          
 +FRMNUM   = $AD8A          ;Eval expression/check data type
 +HAD8D    = $AD8D          
 +HAE38    = $AE38          
 +HAE43    = $AE43          
 +CHKCOM   = $AEFF          ;Check for and skip comma
 +SYNERR   = $AF08          ;Print Syntax Error message
 +MTOFAC   = $BBA2          ;Move FP number from mem to FAC1
 +SIGN     = $BC2B          ;Sign of FAC1 in A
 +LINPRT   = $BDCD          ;Print num X,A=lo,hi in ASCII
 +HE112    = $E112          
 +HE386    = $E386          
 +STOP     = $FFE1          ;Kernal
 +CLALL    = $FFE7          
 +
 +*
 +* Major routine entry points
 +*
 +* $A480 JMPMAIN  JMP (IMAIN)      ;Main loop, below
 +* $A483 MAIN     JSR INLIN        ;Input a line from keyboard
 +* $A49C MAIN1    JSR LINGET       ;Convert ASCII to binary line number
 +* $A533 LINKPRG  LDA TXTTAB       ;Start of BASIC text
 +* $A560 INLIN    LDX #$00         
 +* $A579 CRUNCH   JMP (ICRNCH)
 +* $A613 FINDLINE LDA TXTTAB       ;Start of program text
 +* $A642 NEW      BNE *-2          ;RTS above
 +* $A65E CLEAR    BNE CLEAREND     
 +* $A68E RUNC     CLC              
 +* $A69C LIST     BCC :SKIP        ;Is next char an ASCII digit
 +* $A717 JMPPLOP  JMP (IQPLOP)     
 +* $A71A QPLOP    BPL LISTENT2     ;Exit if not a token
 +* $A7AE NEWSTT   JSR TESTSTOP     
 +* $A7E1 JMPGONE  JMP (IGONE)      
 +* $A7ED GONE     BEQ :RTS         ;Exit if statement terminator
 +* $A81D RESTORE  SEC              
 +* $A831 END      CLC
 +
 +
 +BLARG -- Basic Language Graphics extension
 +-----
 +version 1.0 2/10/97
 +
 +BLARG is a little BASIC extension which adds some graphics commands to
 +the normal C-64 BASIC.  In addition it supports the SuperCPU optimization
 +modes, as well as double buffering.  Finally, it is free for use in
 +your own programs, so feel free to do so!
 +
 +My goal was to write a BASIC extension which was compact, fast,
 +and actually available for downloading :).  Also, something that wasn't
 +BASIC7.0.  It doesn't have tons of features but I deem it to be Nifty.
 +
 +Anyways, these are adaptations of my algorithms from C=Hacking and such.
 +They are not the most efficient implementations, but they are fairly zippy,
 +and fairly well beat the snot out of BASIC7.0 commands!  For instance,
 +the times from moire3 (a line drawing test):
 +
 +        Stock 64        1200 jiffies    (1X)
 +        SCPU Mode 17    137 jiffies     (9.1X)
 +        SCPU Mode 16    59 jiffies      (20.2X)
 +        BASIC7.0 (1MHz) 4559 jiffies    (1/3.5 X)
 +
 +So lines are nearly 4x faster on a stock 64 than a 128 running BASIC7.0.
 +Running in mode16 on a SuperCPU is 77 times faster than BASIC7.0!!!
 +
 +Let's not even talk about BASIC7.0 circles.  Well, what the heck, let's
 +talk about them :)
 +circletest1:
 +        Stock 64        360 jiffies     (1x)
 +        SCPU Mode 17    50 jiffies      (7x)
 +        SCPU Mode 16    22 jiffies      (15.4x)
 +        BASIC7.0        17394 j :)      1/49x
 +
 +Bottom line: mode 16 circles are, if you can believe it, 790x faster
 +than BASIC7.0 circles (and much better looking, especially at large
 +radii -- BASIC7.0 circles are actually 128-sided polygons :-/  ).
 +
 +The total size of the program right now is a bit over 2k, and sits at
 +$C000.  To install the program, just load and run.  To re-initialize
 +the system (after a warm reset for instance) just type SYS49152.  The
 +command list is located near $C000, immediately followed by the
 +routine addresses, in case you want to take a peek.
 +
 +A second program, BLARG$8000, is included in the archive.  To use it,
 +load ,8,1 and type SYS32768 to initialize.  This program is included
 +so that it may be loaded from a BASIC program.
 +
 +Several demo programs are included, and offer a good way of learning
 +the commands (for instance, try typing ORIGIN 10,10 before running
 +MOIRE3).
 +
 +Words to the wise:
 +
 +        1 - If you use a DOS extension like JiffyDOS then be sure to
 +            enclose filenames etc. in quotes (unless you want them to
 +            be tokenized, in which case feel free to omit quotes).
 +
 +        2 - If it looks like your machine has completely frozen try
 +            typing RUN-STOP, shift-clear, MODE 17 (Sometimes you can
 +            break the program before it can tell VIC where the screen
 +            is located).  MODE16 and MODE17 will always fix stuff up,
 +            whereas run/stop-restore doesn't always do the trick.
 +
 +        3 - Always keep in mind that MODE 16,17, and 18 may hose
 +            string variables.
 +
 +        4 - IF/THEN bypasses the IGONE vector, so a statement like
 +            IF A=0 THEN GRON will fail.  The statement IF A=0 THEN:GRON
 +            will work fine.
 +
 +Without further ado:
 +
 +GRON [COLOR] -- Turns graphics on.  If the optional parameter COLOR is
 +        specified the bitmap is cleared and the colormap is initialized to
 +        that value, specifically,
 +        COLOR = 16*foreground color + background color
 +
 +        Examples:
 +                GRON  -- Turn on bitmap without clearing it.
 +                GRON20 -- Turn on bitmap, clear, purple bg, white fg
 +
 +GROFF -- Turns graphics off (sticks you back into text mode, or
 +        whatever mode you were in when you last called GRON)
 +
 +CLEAR [color] -- Clear current graphics buffer.  CLEAR is part of
 +        the GRON routine, but will not set VIC or CIA#2.
 +
 +COLOR n -- COLOR 1 sets the drawing color to the foreground color;
 +        COLOR 0 sets it to background.
 +
 +ORIGIN CX, CY -- Sets the upper-left corner of the screen to have
 +        coordinates CX,CY.  More precisely, commands will subtract
 +        CX,CY from coordinates passed into it.  Among other things,
 +        this provides a mechanism for negative numbers to be
 +        handled -- LINE -10,0,40,99 will not work, but ORIGIN 10,0:
 +        LINE 0,0,50,99 will.  This value is initialized to (0,0) whenever
 +        SYS49152 is called.
 +
 +PLOT X,Y -- Sticks a point at coordinates X,Y.  (Actually at
 +        coordinates X-XC, Y-YC).  X may be in the range 0..319
 +        and Y may be 0..199; points outside this range will not be
 +        plotted.
 +
 +LINE X1,Y1,X2,Y2 -- Draws a line from X1,Y1 to X2,Y2 (subtracting
 +        XC,YC as necessary).  X1 may be any 16-bit value and Y2
 +        may be any 8-bit value.  Coordinates off of the screen will
 +        simply not be plotted!
 +
 +CIRCLE XC,YC,R -- Draws a circle of radius R centered at XC,YC
 +        (translating as necessary).  The algorithm is smart and can
 +        handle R=0..255 correctly (as far as I know!).  I used a
 +        modified version of my algorithm, which makes very nice
 +        circles in my quite biased opinion, except for a few radii
 +        which come out a little ovalish.  Oh well.
 +
 +MODE n -- New graphics MODE.
 +        MODE 16 -- SuperCPU mode.  This moves the bitmap screen to
 +                $A000, the colormap to $8C00, the text screen to $8800,
 +                and sets the SuperCPU bank 2 optimization mode.
 +                $9000-$9FFF is totally unused :(.
 +        MODE 17 -- Normal mode.  Bitmap->$E000, Colormap ->$CC00,
 +                text screen -> $0400.
 +        MODE 18 -- Double buffer mode.  MODE16 memory configuration,
 +                no SCPU optimization.
 +        MODE16, MODE17, and MODE18 reset the BASIC memtop and stringtop
 +        pointers, so any defined strings may get hosed.
 +        (They also execute GROFF, and hence turn on the text screen).
 +        Any other MODE parameter will be set to the BITMASK parameter.
 +        What is BITMASK?  Anything drawn to the screen is first ANDed
 +        with BITMASK.  (Try MODE 85 sometime).
 +        (Although these numbers are reserved for future expansion).
 +
 +BUFFER n -- Set drawing buffer.
 +        When double-buffer mode is activated (MODE 18), both buffers
 +        are available for drawing and displaying.  It is then
 +        possible to draw in one buffer while displaying the other.
 +        BUFFER n selects which buffer the PLOT,LINE,CIRCLE, and CLEAR
 +        commands will affect.  If n=0 then it swaps the target
 +        buffer.  Otherwise, n=odd references the buffer at $A000
 +        and n=even selects the buffer at $E000.
 +
 +SWAP -- Swap displayed buffer.
 +        Assuming MODE18 is selected, SWAP simply selects which buffer
 +        is displayed on the screen; specifically, it flips between
 +        the two.  SWAP only affects what is displayed on the
 +        screen; BUFFER only affects the target of the drawing commands.
 +
 +I think that's it :).
 +
 +----------------------------------------------------------------------------
 +
 +*                       
 +* GRABAS
 +*
 +* A graphics extension for C-64 BASIC
 +*
 +* SLJ 12/29/96 (Completed 2/10/97)
 +* v1.0
 +*
 +         ORG $0801        
 +                          
 +* Constants
 +                          
 +TXTPTR   = $7A            ;BASIC text pointer
 +IERROR   = $0300          
 +ICRUNCH  = $0304          ;Crunch ASCII into token
 +IQPLOP   = $0306          ;List
 +IGONE    = $0308          ;Execute next BASIC token
 +                          
 +CHRGET   = $73            
 +CHRGOT   = $79            
 +CHROUT   = $FFD2          
 +GETBYT   = $B79E          ;BASIC routine
 +GETPAR   = $B7EB          ;Get a 16,8 pair of numbers
 +CHKCOM   = $AEFD          
 +NEW      = $A642          
 +CLR      = $A65E          
 +                          
 +LINNUM   = $14            ;Number returned by GETPAR
 +                          
 +TEMP     = $FF            
 +TEMP2    = $FB            
 +POINT    = $FD            
 +Y1       = $05            
 +X1       = LINNUM         
 +X2       = $02            
 +Y2       = $04            
 +DY       = $26            
 +DX       = $27            
 +BUF      = $0200          ;Input buffer
 +                          
 +CHUNK1   = $69            ;Circle routine stuff
 +OLDCH1   = $6A            
 +CHUNK2   = $6B            
 +OLDCH2   = $6C            
 +CX       = $A3            
 +CY       = $A5            
 +X        = $6D            
 +Y        = $6E            
 +RADIUS   = $6F            
 +LCOL     = $A6            ;Left column
 +RCOL     = $A7            
 +TROW     = $A8            ;Top row
 +BROW     = $A9            ;Bottom row
 +                          
 +                          
 +                          
 +         DA :LINK         ;link
 +         DA 1997          
 +         DFB $9E          ;SYS
 +         TXT '2063:'      
 +         DFB $A2          ;NEW
 +         DFB 00           ;End of line
 +:LINK    DA 0             ;end of program
 +                          
 +INSTALL  LDA #<PBEGIN     
 +         STA POINT        
 +         LDA #>PBEGIN     
 +         STA POINT+1      
 +         LDA #<PEND       ;Number of bytes to copy
 +         SEC              
 +         SBC #<PBEGIN     
 +         STA TEMP2        
 +         LDA #>PEND       
 +         SBC #>PBEGIN     
 +         STA TEMP2+1      
 +         LDA #$C0         ;Copy to $C000
 +         STA X2+1         
 +         LDY #00          
 +         STY X2           
 +:LOOP    LDA (POINT),   
 +         STA (X2),      
 +         INY              
 +         BNE :LOOP        
 +         INC POINT+1      
 +         INC X2+1         
 +         DEC TEMP2+1      
 +         BNE :LOOP        
 +         LDY TEMP2        
 +:LOOP2   LDA (POINT),   
 +         STA (X2),      
 +         DEY              
 +         CPY #$FF         
 +         BNE :LOOP2       
 +         LDX #5           ;Copy CURRENT vectors
 +:LOOP3   LDA ICRUNCH,   
 +         STA OLDCRNCH,  
 +         DEX              
 +         BPL :LOOP3       
 +         JMP INIT         
 +                          
 +         TXT 'so, you want a secret message, eh? '
 +         TXT 'narnia, narnia, narnia, awake.'
 +         TXT ' love. think. speak. be walking trees.'
 +         TXT ' be talking beasts. be divine waters.'
 +         TXT 'stephen l. judd wuz here 1/20/97'
 +                          
 +PBEGIN                    
 +         ORG $C000        
 +                          
 +*
 +* Init routine -- modify vectors
 +* and set up values.
 +*
 +INIT                      
 +         LDX #5           ;Copy vectors
 +:LOOP    LDA :TABLE,    
 +         STA ICRUNCH,   
 +         DEX              
 +         BPL :LOOP        
 +         INX              
 +         STX ORGX         
 +         STX ORGY         
 +
 +         JMP MODE17       ;Mode 17
 +:TEMP    DFB 05           
 +:TABLE   DA CRUNCH        
 +         DA LIST          
 +         DA EXECUTE       
 +JMPCRUN  DFB $4C          ;JMP
 +OLDCRNCH DS 2             ;Old CRUNCH vector
 +OLDLIST  DS 2             
 +OLDEXEC  DS 2             
 +                          
 +*
 +* Keyword list
 +* Keywords are stored as normal text,
 +* followed by the token number.
 +* All tokens are >128,
 +* so they easily mark the end of the keyword
 +*
 +                          
 +KEYWORDS                  
 +         TXT 'plot',E0    
 +         TXT 'line',E1    
 +         TXT 'circle',E2  
 +         TXT 'gr',91,E3   ;grON
 +         TXT 'groff',E4   ;Graphics off
 +         TXT 'mode',E5    
 +         DFB $B0          ;OR
 +         TXT 'igin',E6    
 +         TXT 'clear',E7   ;Clear bitmap
 +         TXT 'buffer',E8  ;Set draw buffer
 +         TXT 'swap',E9    ;Swap foreground and background
 +         TXT 'col',B0,EA  ;Set color
 +         DFB 00           ;End of list
 +                          
 +*
 +* Table of token locations-1
 +* Subtract $E0 first
 +* Then check to make sure number isn't greater than NUMWORDS
 +*
 +TOKENLOC                  
 +:E0      DA PLOT-1        
 +:E1      DA LINE-1        
 +:E2      DA CIRCLE-1      
 +:E3      DA GRON-1        
 +:E4      DA GROFF-1       
 +:E5      DA MODE-1        
 +:E6      DA ORIGIN-1      
 +:E7      DA CLEAR-1       
 +:E8      DA BUFFER-1      
 +:E9      DA SWAP-1        
 +:EA      DA COLOR-1       
 +HITOKEN  EQU $EB          
 +                          
 +*
 +* CRUNCH -- If this is one of our keywords, then tokenize it
 +*
 +CRUNCH                    
 +         JSR JMPCRUN      ;First crunch line normally
 +         LDY #05          ;Offset for KERNAL
 +                          ;Y will contain line length+5
 +:LOOP    STY TEMP         
 +         JSR ISWORD       ;Are we at a keyword?
 +         BCS :GOTCHA      
 +:NEXT                     
 +         JSR NEXTCHAR     
 +         BNE :LOOP        ;Null byte marks end
 +         STA BUF-3,     ;00 line number
 +         LDA #$FF         ;'tis what A should be
 +         RTS              ;Buh-bye
 +* Insert token and crunch line
 +:GOTCHA                   
 +         LDX TEMP         ;If so, A contains opcode
 +         STA BUF-5,     
 +:MOVE    INX              
 +         LDA BUF-5,     
 +         STA BUF-5,     ;Move text backwards
 +         BEQ :NEXT        
 +         INY              
 +         BPL :MOVE        
 +                          
 +*
 +* ISWORD -- Checks to see if word is
 +* in table.  If a word is found, then
 +* C is set, Y is one past the last char
 +* and A contains opcode.  Otherwise,
 +* carry is clear.
 +*
 +* On entry, TEMP must contain current
 +* character position.
 +*
 +ISWORD                    
 +         LDX #00          
 +:LOOP    LDY TEMP         
 +:LOOP2   LDA KEYWORDS,  
 +         BEQ :NOTMINE     
 +         CMP #$E0         
 +         BCS :RTS         ;Tokens are >=$E0
 +         CMP BUF-5,     
 +         BNE :NEXT        
 +         INY              ;Success!  Go to next char
 +         INX              
 +         BNE :LOOP2       
 +:NEXT                     
 +         INX              
 +         LDA KEYWORDS,  ;Find next keyword
 +         CMP #$E0         
 +         BCC :NEXT        
 +         INX              
 +         BNE :LOOP        ;And check again
 +:NOTMINE CLC              
 +:RTS     RTS              
 +                          
 +*
 +* NEXTCHAR finds the next char
 +* in the buffer, skipping
 +* spaces and quotes.  On
 +* entry, TEMP contains the
 +* position of the last spot
 +* read.  On exit, Y contains
 +* the index to the next char,
 +* A contains that char, and Z is set if at end of line.
 +*
 +NEXTCHAR                  
 +         LDY TEMP         
 +:LOOP    INY              
 +         LDA BUF-5,     
 +         BEQ :DONE        
 +         CMP #$8F         ;REM
 +         BNE :CONT        
 +         LDA #00          
 +:SKIP    STA TEMP2        ;Find matching character
 +:LOOP2   INY              
 +         LDA BUF-5,     
 +         BEQ :DONE        
 +         CMP TEMP2        
 +         BNE :LOOP2       ;Skip to end of line
 +         BEQ :LOOP        
 +:CONT                     
 +         CMP #$20         ;Space
 +         BEQ :LOOP        
 +         CMP #$22         ;Quote
 +         BEQ :SKIP        
 +:DONE    RTS              
 +                          
 +*
 +* LIST -- patches the LIST routine
 +* to list my tokens correctly.
 +*
 +LIST                      
 +         CMP #$E0         
 +         BCC :NOTMINE     ;Not my token
 +         CMP #HITOKEN     
 +         BCS :NOTMINE     
 +         BIT $0F          ;Check for quote mode
 +         BMI :NOTMINE     
 +         SEC              
 +         SBC #$DF         ;Find the corresponding text
 +         TAX              
 +         STY $49          
 +         LDY #00          
 +:LOOP    DEX              
 +         BEQ :DONE        
 +:LOOP2   INY              
 +         LDA KEYWORDS,  
 +         CMP #$E0         
 +         BCC :LOOP2       
 +         INY              
 +         BNE :LOOP        
 +:DONE    LDA KEYWORDS,  
 +         BMI :OUT         
 +         JSR $FFD2        
 +         INY              
 +         BNE :DONE        
 +:OUT     CMP #$B0         ;OR
 +         BEQ :OR          
 +         CMP #$E0         ;It might be BASIC token
 +         BCS :CONT        ;e.g. GRON
 +         LDY $49          
 +:NOTMINE AND #$FF         
 +         JMP (OLDLIST)    ;QPLOP
 +:CONT    LDY $49          
 +         JMP $A700        ;Normal exit
 +:OR      LDA #'o'         ;For ORIGIN
 +         JSR CHROUT       
 +         LDA #'r'         
 +         JSR CHROUT       
 +         INY              
 +         BNE :DONE        
 +                          
 +*
 +* EXECUTE -- if this is one of my
 +* tokens, then execute it.
 +*
 +EXECUTE                   
 +         JSR CHRGET       
 +         PHP              
 +         CMP #$E0         
 +         BCC :NOTMINE     
 +         CMP #HITOKEN     
 +         BCS :NOTMINE     
 +         PLP              
 +         JSR :DISP        
 +         JMP $A7AE        ;Exit through NEWSTT
 +:DISP                     
 +         EOR #$E0         
 +         ASL              ;Mult by two
 +         TAX              
 +         LDA TOKENLOC+1,
 +         PHA              
 +         LDA TOKENLOC,  
 +         PHA              
 +         JMP CHRGET       ;Exit to routine
 +:NOTMINE PLP              
 +         JMP $A7E7        ;Normal routine
 +                          
 +*
 +* PLOT -- plot a point!
 +*
 +ORGX     DFB 00           ;Upper-left corner of the screen
 +ORGY     DFB 00           
 +DONTPLOT DFB 01           ;0=Don't plot point, just compute
 +                          ;coordinates (used by e.g. circles)
 +                          
 +PLOT                      
 +         JSR GETPAR       ;Get coordinate pair
 +         LDA LINNUM       ;Add in origin offset
 +         SEC              
 +         SBC ORGX         
 +         STA LINNUM       
 +         BCS :CONT1       
 +         DEC LINNUM+1     
 +         BMI :ERROR       ;Underflow
 +         SEC              
 +:CONT1   TXA              
 +         SBC ORGY         
 +         BCC :ERROR       
 +         TAX              
 +         CPX #200         ;Check range
 +         BCS :ERROR       
 +         LDA LINNUM       
 +         CMP #<320        
 +         LDA LINNUM+1     
 +         SBC #>320        
 +         BCC SETPOINT     
 +:ERROR   RTS              ;Just don't plot point
 +*:ERROR LDX #14
 +* JMP (IERROR)
 +SETPOINT                  ;Alternative entry point
 +                          ;X=y-coord, LINNUM=x-coord
 +* ;X is preserved
 +* STX TEMP2
 +* STY TEMP2+1
 +                          ;On exit, X,Y are AND #$07
 +                          ;i.e. are set up correctly.
 +         TXA              
 +         AND #248         
 +         STA POINT        
 +         LSR              
 +         LSR              
 +         LSR              
 +         ADC BASE         ;Base of bitmap
 +         STA POINT+1      
 +         LDA #00          
 +         ASL POINT        
 +         ROL              
 +         ASL POINT        
 +         ROL              
 +         ASL POINT        
 +         ROL              
 +         ADC LINNUM+1     
 +         ADC POINT+1      
 +         STA POINT+1      
 +         TXA              
 +         AND #7           
 +         TAY              
 +         LDA LINNUM       
 +         AND #248         
 +         CLC              ;Overflow is possible!
 +         ADC POINT        
 +         STA POINT        
 +         BCC SETPIXEL     
 +         INC POINT+1      
 +SETPIXEL                  
 +         LDA LINNUM       
 +         AND #$07         
 +         TAX              
 +         LDA DONTPLOT     
 +         BEQ :RTS         
 +         LDA POINT+1      
 +         SEC              
 +         SBC BASE         ;Overflow check
 +         CMP #$20         
 +         BCS :RTS         
 +         SEI              ;Get underneath ROM
 +         LDA #$34         
 +         STA $01          
 +                          
 +         LDA (POINT),   
 +         EOR BITMASK      
 +         AND BITTAB,    
 +         EOR (POINT),   
 +         STA (POINT),   
 +                          
 +         LDA #$37         
 +         STA $01          
 +         CLI              
 +* LDX TEMP2
 +* LDY TEMP2+1
 +                          ;On exit, X,Y are AND #$07
 +                          ;i.e. are set up correctly.
 +                          ;for more plotting
 +:RTS     RTS              
 +                          
 +BITMASK  DFB #$FF         ;Set point
 +BITTAB   DFB $80,$40,$20,$10,$08,$04,$02,$01
 +                          
 +*-------------------------------
 +* Drawin' a line.  A fahn lahn.
 +*
 +* To deal with off-screen coordinates, the current row
 +* and column (40x25) is kept track of.  These are set
 +* negative when the point is off the screen, and made
 +* positive when the point is within the visible screen.
 +                          
 +* Little bit position table
 +BITCHUNK HEX FF7F3F1F0F070301
 +CHUNK    EQU X2           
 +OLDCHUNK EQU X2+1         
 +                          
 +* DOTTED -- Set to $01 if doing dotted draws (diligently)
 +* X1,X2 etc. are set up above (x2=LINNUM in particular)
 +* Format is LINE x2,y2,x1,y1
 +                          
 +LINE                      
 +         JSR GETPAR       
 +         STX Y2           
 +         LDA LINNUM       
 +         STA X2           
 +         LDA LINNUM+1     
 +         STA X2+1         
 +         JSR CHKCOM       
 +         JSR GETPAR       
 +         STX Y1           
 +                          
 +:CHECK   LDA X2           ;Make sure x1<x2
 +         SEC              
 +         SBC X1           
 +         TAX              
 +         LDA X2+1         
 +         SBC X1+1         
 +         BCS :CONT        
 +         LDA Y2           ;If not, swap P1 and P2
 +         LDY Y1           
 +         STA Y1           
 +         STY Y2           
 +         LDA X1           
 +         LDY X2           
 +         STY X1           
 +         STA X2           
 +         LDA X2+1         
 +         LDY X1+1         
 +         STA X1+1         
 +         STY X2+1         
 +         BCC :CHECK       
 +                          
 +:CONT    STA DX+1         
 +         STX DX           
 +                          
 +         LDX #$C8         ;INY
 +         LDA Y2           ;Calculate dy
 +         SEC              
 +         SBC Y1           
 +         BCS :DYPOS       ;Is y2>=y1?
 +         EOR #$FF         ;Otherwise dy=y1-y2
 +         ADC #$01         
 +         LDX #$88         ;DEY
 +                          
 +:DYPOS   STA DY           
 +         STX YINCDEC      
 +         STX XINCDEC      
 +                          
 +         LDA X1           ;Sub origin from 1st point
 +         SEC              
 +         SBC ORGX         
 +         STA X1           
 +         LDA X1+1         
 +         SBC #00          
 +         STA X1+1         
 +         PHP              ;Save carry flag
 +         STA TEMP         ;Next compute column
 +         LDA X1           
 +         LSR TEMP         
 +         ROR              
 +         LSR TEMP         
 +         ROR              
 +         LSR TEMP         
 +         ROR              
 +         STA CX           ;X-column
 +         PLP              
 +         BCC :NEGX        ;If negative, then fix up
 +         CMP #40          ;If past column 40, then punt!
 +         BCC :CONT1       
 +         RTS              
 +:NEGX    LDA X1           ;coordinate start and count
 +         AND #$07         
 +         STA X1           
 +         LDA #00          
 +         STA X1+1         
 +         LDA CX           
 +                          
 +:CONT1   LDA Y1           ;Now do the same for Y
 +         SEC              
 +         SBC ORGY         
 +         STA Y1           
 +         TAX              ;X=y-coord
 +         PHP              ;Save carry bit
 +         LSR              
 +         LSR              
 +         LSR              
 +         STA CY           ;Y-column (well, OK, row then)
 +         PLP              
 +         BCC :NEGY        ;If negative, then fix stuff up!
 +         SBC #25          ;Check if we are past bottom of
 +         BCC :CONT2       ;screen
 +         ORA #$80         ;Otherwise, 128+rows past 24
 +         STA CY           ;(for plot range checking)
 +         TXA              
 +         AND #$07         
 +         ORA #8*24        ;Start in last row
 +         TAX              
 +         BMI :CONT2       
 +:NEGY    ORA #$E0         ;Set high bits of column
 +         STA CY           
 +         TXA              
 +         AND #$07         
 +         TAX              ;Start in 1st row
 +:CONT2                    
 +                          
 +         LDA #00          
 +         STA DONTPLOT     
 +         JSR SETPOINT     ;Set up X,Y and POINT
 +         INC DONTPLOT     
 +         LDA BITCHUNK,  
 +         STA OLDCHUNK     
 +         STA CHUNK        
 +                          
 +         SEI              ;Get underneath ROM
 +         LDA #$34         
 +         STA $01          
 +                          
 +         LDX DY           
 +         CPX DX           ;Who's bigger: dy or dx?
 +         BCC STEPINX      ;If dx, then...
 +         LDA DX+1         
 +         BNE STEPINX      
 +                          
 +*
 +* Big steps in Y
 +*
 +*   To simplify my life, just use PLOT to plot points.
 +*
 +*   No more!
 +*   Added special plotting routine -- cool!
 +*
 +*   X is now counter, Y is y-coordinate
 +*
 +* On entry, X=DY=number of loop iterations, and Y=
 +*   Y1 AND #$07
 +STEPINY                   
 +         LDA #00          
 +         STA OLDCHUNK     ;So plotting routine will work right
 +         LDA CHUNK        
 +         SEC              
 +         LSR              ;Strip the bit
 +         EOR CHUNK        
 +         STA CHUNK        
 +         TXA              
 +         BNE :CONT        ;If dy=0 it's just a point
 +         INX              
 +:CONT    LSR              ;Init counter to dy/2
 +*
 +* Main loop
 +*
 +YLOOP    STA TEMP         
 +* JSR LINEPLOT
 +                          
 +         LDA CX           ;Range check
 +         ORA CY           
 +         BMI :SKIP        
 +                          
 +         LDA (POINT),   ;Otherwise plot
 +         EOR BITMASK      
 +         AND CHUNK        
 +         EOR (POINT),   
 +         STA (POINT),   
 +:SKIP                     
 +YINCDEC  INY              ;Advance Y coordinate
 +         CPY #8           
 +         BCC :CONT        ;No prob if Y=0..7
 +         JSR FIXY         
 +:CONT    LDA TEMP         ;Restore A
 +         SEC              
 +         SBC DX           
 +         BCC YFIXX        
 +YCONT    DEX              ;X is counter
 +         BNE YLOOP        
 +YCONT2   LDA (POINT),   ;Plot endpoint
 +         EOR BITMASK      
 +         AND CHUNK        
 +         EOR (POINT),   
 +         STA (POINT),   
 +YDONE                     
 +         LDA #$37         
 +         STA $01          
 +         CLI              
 +         RTS              
 +                          
 +YFIXX                     ;x=x+1
 +         ADC DY           
 +         LSR CHUNK        
 +         BNE YCONT        ;If we pass a column boundary...
 +         ROR CHUNK        ;then reset CHUNK to $80
 +         STA TEMP2        
 +         LDA CX           
 +         BMI :CONT        ;Skip if column is negative
 +         CMP #39          ;End if move past end of screen
 +         BCS YDONE        
 +                          
 +         LDA POINT        ;And add 8 to POINT
 +         ADC #8           
 +         STA POINT        
 +         BCC :CONT        
 +         INC POINT+1      
 +:CONT    INC CX           ;Increment column
 +         LDA TEMP2        
 +         DEX              
 +         BNE YLOOP        
 +         BEQ YCONT2       
 +                          
 +*
 +* Big steps in X direction
 +*
 +* On entry, X=DY=number of loop iterations, and Y=
 +*   Y1 AND #$07
 +                          
 +COUNTHI  DFB 00           ;Temporary counter
 +                          ;only used once
 +STEPINX                   
 +         LDX DX           
 +         LDA DX+1         
 +         STA COUNTHI      
 +         LSR              ;Need bit for initialization
 +         STA Y1           ;High byte of counter
 +         TXA              
 +         BNE :CONT        ;Could be $100
 +         DEC COUNTHI      
 +:CONT    ROR              
 +*
 +* Main loop
 +*
 +XLOOP                     
 +         LSR CHUNK        
 +         BEQ XFIXC        ;If we pass a column boundary...
 +XCONT1   SBC DY           
 +         BCC XFIXY        ;Time to step in Y?
 +XCONT2   DEX              
 +         BNE XLOOP        
 +         DEC COUNTHI      ;High bits set?
 +         BPL XLOOP        
 +XDONE                     
 +         LSR CHUNK        ;Advance to last point
 +         JSR LINEPLOT     ;Plot the last chunk
 +EXIT     LDA #$37         
 +         STA $01          
 +         CLI              
 +         RTS              
 +*
 +* CHUNK has passed a column, so plot and increment pointer
 +* and fix up CHUNK, OLDCHUNK.
 +*
 +XFIXC                     
 +         STA TEMP         
 +         JSR LINEPLOT     
 +         LDA #$FF         
 +         STA CHUNK        
 +         STA OLDCHUNK     
 +         LDA CX           
 +         BMI :CONT        ;Skip if column is negative
 +         CMP #39          ;End if move past end of screen
 +         BCS EXIT         
 +                          
 +         LDA POINT        
 +         ADC #8           
 +         STA POINT        
 +         BCC :CONT        
 +         INC POINT+1      
 +:CONT    INC CX           
 +         LDA TEMP         
 +         JMP XCONT1       
 +*
 +* Check to make sure there isn't a high bit, plot chunk,
 +* and update Y-coordinate.
 +*
 +XFIXY                     
 +         DEC Y1           ;Maybe high bit set
 +         BPL XCONT2       
 +         ADC DX           
 +         STA TEMP         
 +         LDA DX+1         
 +         ADC #$FF         ;Hi byte
 +         STA Y1           
 +                          
 +         JSR LINEPLOT     ;Plot chunk
 +         LDA CHUNK        
 +         STA OLDCHUNK     
 +                          
 +         LDA TEMP         
 +XINCDEC  INY              ;Y-coord
 +         CPY #8           ;0..7 is ok
 +         BCC XCONT2       
 +         STA TEMP         
 +         JSR FIXY         
 +         LDA TEMP         
 +         JMP XCONT2       
 +                          
 +*
 +* Subroutine to plot chunks/points (to save a little
 +* room, gray hair, etc.)
 +*
 +LINEPLOT                  ;Plot the line chunk
 +                          
 +         LDA CX           
 +         ORA CY           
 +         BMI :SKIP        
 +                          
 +         LDA (POINT),   ;Otherwise plot
 +         EOR BITMASK      
 +         ORA CHUNK        
 +         AND OLDCHUNK     
 +         EOR CHUNK        
 +         EOR (POINT),   
 +         STA (POINT),   
 +:SKIP                     
 +         RTS              
 +                          
 +*
 +* Subroutine to fix up pointer when Y decreases through
 +* zero or increases through 7.
 +*
 +FIXY     CPY #255         ;Y=255 or Y=8
 +         BEQ :DECPTR      
 +:INCPTR                   ;Add 320 to pointer
 +         LDY #0           ;Y increased through 7
 +         LDA CY           
 +         BMI :CONT1       ;If negative, then don't update
 +         CMP #24          
 +         BCS :TOAST       ;If at bottom of screen then quit
 +         LDA POINT        
 +         ADC #<320        
 +         STA POINT        
 +         LDA POINT+1      
 +         ADC #>320        
 +         STA POINT+1      
 +:CONT1   INC CY           
 +         RTS              
 +:DECPTR                   ;Okay, subtract 320 then
 +         LDY #7           ;Y decreased through 0
 +         LDA CY           
 +         BEQ :TOAST       
 +         BMI :CONT2       
 +         CMP #$7F         ;It is possible we just decreased
 +         BNE :C1          ;through row 25
 +         LDA #24          
 +         STA CY           ;In which case, set correct row
 +:C1      LDA POINT        
 +         SEC              
 +         SBC #<320        
 +         STA POINT        
 +         LDA POINT+1      
 +         SBC #>320        
 +         STA POINT+1      
 +:CONT2   DEC CY           
 +         RTS              
 +:TOAST   PLA              ;Remove old return address
 +         PLA              
 +         JMP EXIT         ;Restore interrupts, etc.
 +                          
 +*
 +* CIRCLE draws a circle of course, using my
 +* super-sneaky algorithm.
 +*   CIRCLE cx,cy,radius (16,8,8)
 +*
 +                          
 +CIRCLE                    
 +         JSR GETPAR       
 +         STX CY           ;CX,CY = center
 +                          
 +         LDA X1           
 +         SEC              
 +         SBC ORGX         
 +         STA CX           
 +         STA X1           
 +         LDA X1+1         
 +         SBC #00          
 +         STA CX+1         
 +         STA X1+1         
 +         PHP              ;Save carry
 +         LSR              ;Compute which column we start
 +         LDA CX           ;in
 +         ROR              
 +         LSR              
 +         LSR              
 +         PLP              
 +         BCS :CONT        ;Underflow means negative column
 +         TAX              
 +         LDA X1           ;Set X to first column
 +         AND #$07         
 +         STA X1           
 +         LDA #00          
 +         STA X1+1         
 +         TXA              
 +         ORA #$E0         ;so set high bits
 +:CONT    STA RCOL         
 +         STA LCOL         
 +         BMI :SKIP        
 +         CMP #40          ;Check for benefit of SETPOINT
 +         BCC :SKIP        
 +         LDA X1           ;Set X in last column
 +         AND #$07         
 +         ORA #64-8        ;312+X AND 7
 +         STA X1           
 +         LDA #1           
 +         STA X1+1         
 +:SKIP                     
 +         JSR CHKCOM       
 +         JSR GETBYT       
 +CIRCENT                   ;Alternative entry point
 +         STX Y            
 +         STX RADIUS       
 +         TXA              
 +         BNE :C           ;Skip R=0
 +         LDX CY           
 +         JMP SETPOINT     ;Plot it as a point.
 +:C       CLC              
 +         ADC CY           
 +         BCS :BLAH        
 +         SEC              
 +         SBC ORGY         
 +         BCS :C4          ;cy+y<orgy implies circle off screen
 +:RTS     RTS              
 +                          
 +:BLAH    SBC ORGY         ;Always positive
 +         BCS :C3          ;Handle overflow sneaky
 +:C4      TAX              
 +         CMP #200         ;If Y>200 then set pointer to
 +         BCC :C2          ;last row, but set TROW
 +         CLC              ;correctly
 +:C3      TAY              
 +         AND #$07         
 +         ORA #$C0         ;Last row, set Y1 correctly
 +         TAX              
 +         TYA              
 +:C2      ROR              
 +         LSR              
 +         LSR              
 +         STA TROW         ;Top row
 +                          
 +         LDA #00          
 +         STA DONTPLOT     ;Don't plot points
 +         JSR SETPOINT     ;Plot XC,YC+Y
 +         STY Y2           ;Y AND 07
 +         LDA BITCHUNK,  
 +         STA CHUNK1       ;Forwards chunk
 +         STA OLDCH1       
 +         LSR              
 +         EOR #$FF         
 +         STA CHUNK2       ;Backwards chunk
 +         STA OLDCH2       
 +         LDA POINT        
 +         STA TEMP2        ;TEMP2 = forwards high pointer
 +         STA X2           ;X2 = backwards high pointer
 +         LDA POINT+1      
 +         STA TEMP2+1      
 +         STA X2+1         
 +                          
 +         LDA CY           ;Now compute upper points
 +         SEC              
 +         SBC ORGY         
 +         BCS :CSET        
 +         SEC              ;We are so very negative
 +         SBC Y            
 +         CLC              
 +         BCC :BNEG        
 +:CSET    SBC Y            ;Compute CY-Y-ORGY
 +:BNEG    PHP              
 +         TAX              
 +         LSR              ;Compute row
 +         LSR              
 +         LSR              
 +         STA BROW         
 +         PLP              
 +         BCS :CONT        
 +         ORA #$E0         ;Make row negative
 +         STA BROW         
 +         TXA              
 +         AND #07          ;Handle underflow special!
 +         TAX              
 +:CONT    JSR SETPOINT     ;Compute new coords
 +         STY Y1           
 +         LDA POINT        
 +         STA X1           ;X1 will be the backwards
 +         LDA POINT+1      ;low-pointer
 +         STA X1+1         ;POINT will be forwards
 +                          
 +         SEI              ;Get underneath ROM
 +         LDA #$34         
 +         STA $01          
 +                          
 +         LDA Y            
 +         LSR              ;A=r/2
 +         LDX #00          
 +         STX X            ;y=0
 +                          
 +* Main loop
 +                          
 +:LOOP                     
 +         INC X            ;x=x+1
 +                          
 +         LSR CHUNK1       ;Right chunk
 +         BNE :CONT1       
 +         JSR UPCHUNK1     ;Update if we move past a column
 +:CONT1   ASL CHUNK2       
 +         BNE :CONT2       
 +         JSR UPCHUNK2     
 +:CONT2                    ;LDA TEMP
 +         SEC              
 +         SBC X            ;a=a-x
 +         BCS :LOOP        
 +                          
 +         ADC Y            ;if a<0 then a=a+y; y=y-1
 +         TAX              
 +         JSR PCHUNK1      
 +         JSR PCHUNK2      
 +         LDA CHUNK1       
 +         STA OLDCH1       
 +         LDA CHUNK2       
 +         STA OLDCH2       
 +         TXA              
 +                          
 +         DEC Y            ;(y=y-1)
 +                          
 +         DEC Y2           ;Decrement y-offest for upper
 +         BPL :CONT3       ;points
 +         JSR DECYOFF      
 +:CONT3   LDY Y1           
 +         INY              
 +         STY Y1           
 +         CPY #8           
 +         BCC :CONT4       
 +         JSR INCYOFF      
 +:CONT4                    
 +         LDY X            
 +         CPY Y            ;if y<=x then punt
 +         BCC :LOOP        ;Now draw the other half
 +*
 +* Draw the other half of the circle by exactly reversing
 +* the above!
 +*
 +NEXTHALF                  
 +         LSR OLDCH1       ;Only plot a bit at a time
 +         ASL OLDCH2       
 +         LDA RADIUS       ;A=-R/2-1
 +         LSR              
 +         EOR #$FF         
 +:LOOP                     
 +         TAX              
 +         JSR PCHUNK1      ;Plot points
 +         JSR PCHUNK2      
 +         TXA              
 +         DEC Y2           ;Y2=bottom
 +         BPL :CONT1       
 +         JSR DECYOFF      
 +:CONT1   INC Y1           
 +         LDY Y1           
 +         CPY #8           
 +         BCC :CONT2       
 +         JSR INCYOFF      
 +:CONT2                    
 +         LDX Y            
 +         BEQ :DONE        
 +         CLC              
 +         ADC Y            ;a=a+y
 +         DEC Y            ;y=y-1
 +         BCC :LOOP        
 +                          
 +         INC X            
 +         SBC X            ;if a<0 then x=x+1; a=a+x
 +         LSR CHUNK1       
 +         BNE :CONT3       
 +         TAX              
 +         JSR UPCH1        ;Upchunk, but no plot
 +:CONT3   LSR OLDCH1       ;Only the bits...
 +         ASL CHUNK2       ;Fix chunks
 +         BNE :CONT4       
 +         TAX              
 +         JSR UPCH2        
 +:CONT4   ASL OLDCH2       
 +         BCS :LOOP        
 +:DONE                     
 +CIRCEXIT                  ;Restore interrupts
 +         LDA #$37         
 +         STA $01          
 +         CLI              
 +         LDA #1           ;Re-enable plotting
 +         STA DONTPLOT     
 +         RTS              
 +*
 +* Decrement upper pointers
 +*
 +DECYOFF                   
 +         TAY              
 +         LDA #7           
 +         STA Y2           
 +         LDA TROW         ;First check to see if Y is in
 +         BEQ EXIT2        
 +         CMP #25          ;range (rows 0-24)
 +         BCS :SKIP        
 +         LDA X2           ;If we pass through zero, then
 +         SEC              
 +         SBC #<320        ;subtract 320
 +         STA X2           
 +         LDA X2+1         
 +         SBC #>320        
 +         STA X2+1         
 +         LDA TEMP2        
 +         SEC              
 +         SBC #<320        
 +         STA TEMP2        
 +         LDA TEMP2+1      
 +         SBC #>320        
 +         STA TEMP2+1      
 +:SKIP    TYA              
 +         DEC TROW         
 +         RTS              
 +EXIT2    PLA              ;Grab return address
 +         PLA              
 +         JMP CIRCEXIT     ;Restore interrupts, etc.
 +                          
 +* Increment lower pointers
 +INCYOFF                   
 +         TAY              
 +         LDA #00          
 +         STA Y1           
 +         LDA BROW         
 +         BMI :ISKIP       ;If <0 then don't update pointer.
 +         CMP #24          ;If we hit bottom of screen then
 +         BEQ EXIT2        ;just quit
 +         LDA X1           
 +         CLC              
 +         ADC #<320        
 +         STA X1           
 +         LDA X1+1         
 +         ADC #>320        
 +         STA X1+1         
 +         LDA POINT        
 +         CLC              
 +         ADC #<320        
 +         STA POINT        
 +         LDA POINT+1      
 +         ADC #>320        
 +         STA POINT+1      
 +:ISKIP   TYA              
 +         INC BROW         
 +         RTS              
 +                          
 +*
 +* UPCHUNK1 -- Update right-moving chunk pointers
 +*             Due to passing through a column
 +*
 +UPCHUNK1                  
 +         TAX              
 +         JSR PCHUNK1      
 +UPCH1    LDA #$FF         ;Alternative entry point
 +         STA CHUNK1       
 +         STA OLDCH1       
 +         LDA RCOL         
 +         BMI :DONE        ;Can start negative
 +         LDA TEMP2        
 +         CLC              
 +         ADC #8           
 +         STA TEMP2        
 +         BCC :CONT        
 +         INC TEMP2+1      
 +         CLC              
 +:CONT    LDA POINT        
 +         ADC #8           
 +         STA POINT        
 +         BCC :DONE        
 +         INC POINT+1      
 +:DONE    TXA              
 +         INC RCOL         
 +         RTS              
 +                          
 +*
 +* UPCHUNK2 -- Update left-moving chunk pointers
 +*
 +UPCHUNK2                  
 +         TAX              
 +         JSR PCHUNK2      
 +UPCH2    LDA #$FF         
 +         STA CHUNK2       
 +         STA OLDCH2       
 +         LDA LCOL         
 +         CMP #40          
 +         BCS :DONE        
 +         LDA X2           
 +         SEC              
 +         SBC #8           
 +         STA X2           
 +         BCS :CONT        
 +         DEC X2+1         
 +         SEC              
 +:CONT    LDA X1           
 +         SBC #8           
 +         STA X1           
 +         BCS :DONE        
 +         DEC X1+1         
 +:DONE    TXA              
 +         DEC LCOL         
 +         RTS              
 +*
 +* Plot right-moving chunk pairs for circle routine
 +*
 +PCHUNK1                   
 +                          
 +         LDA RCOL         ;Make sure we're in range
 +         CMP #40          
 +         BCS :SKIP2       
 +         LDA CHUNK1       ;Otherwise plot
 +         EOR OLDCH1       
 +         STA TEMP         
 +         LDA BROW         ;Check for underflow
 +         BMI :SKIP        
 +         LDY Y1           
 +         LDA (POINT),   
 +         EOR BITMASK      
 +         AND TEMP         
 +         EOR (POINT),   
 +         STA (POINT),   
 +                          
 +:SKIP    LDA TROW         ;If CY+Y >= 200...
 +         CMP #25          
 +         BCS :SKIP2       
 +         LDY Y2           
 +         LDA (TEMP2),   
 +         EOR BITMASK      
 +         AND TEMP         
 +         EOR (TEMP2),   
 +         STA (TEMP2),   
 +:SKIP2                    
 +         RTS              
 +                          
 +*
 +* Plot left-moving chunk pairs for circle routine
 +*
 +PCHUNK2                   
 +                          
 +         LDA LCOL         ;Range check in X
 +         CMP #40          
 +         BCS :SKIP2       
 +         LDA CHUNK2       ;Otherwise plot
 +         EOR OLDCH2       
 +         STA TEMP         
 +         LDA BROW         ;Check for underflow
 +         BMI :SKIP        
 +         LDY Y1           
 +         LDA (X1),      
 +         EOR BITMASK      
 +         AND TEMP         
 +         EOR (X1),      
 +         STA (X1),      
 +                          
 +:SKIP    LDA TROW         ;If CY+Y >= 200...
 +         CMP #25          
 +         BCS :SKIP2       
 +         LDY Y2           
 +         LDA (X2),      
 +         EOR BITMASK      
 +         AND TEMP         
 +         EOR (X2),      
 +         STA (X2),      
 +:SKIP2                    
 +         RTS              
 +                          
 +*
 +* GRON -- turn graphics on.  If a number appears
 +* afterwards, then initialize the colormap to that
 +* number and clear the bitmap.
 +*
 +BASE     DFB $E0          ;Address of bitmap, hi byte
 +BANK     DFB 0            ;Bank 3=default
 +OLDBANK  DFB $FF          ;VIC old bank
 +OLDD018  DFB 00           
 +                          
 +GRON                      
 +         LDA $D011        ;Skip if bitmap is already on.
 +         AND #$20         
 +         BNE CLEAR        
 +         LDA $DD02        ;Set the data direction regs
 +         ORA #3           
 +         STA $DD02        
 +         LDA $DD00        
 +         PHA              
 +         AND #$03         
 +         STA OLDBANK      
 +         PLA              
 +         AND #252         
 +         ORA BANK         
 +         STA $DD00        
 +                          
 +         LDA $D018        
 +         STA OLDD018      
 +         LDA #$38         ;Set color map to base+$1C00
 +         STA $D018        ;bitmap to 2nd 8k
 +                          
 +         LDA $D011        ;And turn on bitmap
 +         ORA #$20         
 +         STA $D011        
 +                          
 +CLEAR    JSR CHRGOT       ;See if there's a color
 +         BEQ GRONDONE     
 +         JSR GETBYT       ;Get the char
 +CLEARCOL LDA #00          ;Low byte of base address
 +         STA POINT        
 +         LDA BASE         ;Colormap is at base-$14
 +         SEC              
 +         SBC #$14         
 +         STA POINT+1      
 +         TXA              
 +         LDY #00          
 +         LDX #4           
 +:LOOP    STA (POINT),   
 +         INY              
 +         BNE :LOOP        
 +         INC POINT+1      
 +         DEX              
 +         BNE :LOOP        
 +         LDA BASE         ;Now clear bitmap
 +         STA POINT+1      
 +         LDX #32          
 +         TYA              
 +:LOOP2   STA (POINT),   
 +         INY              
 +         BNE :LOOP2       
 +         INC POINT+1      
 +         DEX              
 +         BNE :LOOP2       
 +                          
 +GRONDONE RTS              
 +                          
 +* GROFF -- Restore old values if graphics are on.
 +GROFF                     
 +         LDA $D011        
 +         AND #$20         
 +         BEQ GDONE        
 +GSET     LDA $DD02        ;Set the data direction regs
 +         ORA #3           
 +         STA $DD02        
 +         LDA $DD00        
 +         AND #$7C         
 +         ORA OLDBANK      
 +         STA $DD00        
 +                          
 +         LDA OLDD018      
 +         STA $D018        
 +                          
 +         LDA $D011        
 +         AND #$FF-$20     
 +         STA $D011        
 +GDONE    RTS              
 +                          
 +*
 +* COLOR -- Set drawing color
 +*
 +COLOR                     
 +         JSR GETBYT       
 +COLENT   CPX #00          ;MODE enters here
 +         BEQ :C2          
 +:C1      CPX #01          
 +         BNE :RTS         
 +         LDX #$FF         
 +:C2      STX BITMASK      
 +:RTS     RTS              
 +                          
 +*
 +* MODE -- catch-all command.  Currently implemented:
 +*   00  Erase (background color)
 +*   01  Foreground color
 +*   16  SuperCPU mode -- screen -> A000, etc.
 +*   17  Normal mode
 +*   18  Double buffer mode
 +*
 +*  Anything else -> BITMASK
 +*
 +MODENUM  DFB 17           ;Current mode
 +MODE                      
 +         JSR GETBYT       
 +         CPX #2           
 +         BCC COLENT       
 +:C16     CPX #16          
 +         BNE :C18         
 +         STX MODENUM      
 +:SET16   LDA #$A0         ;Bitmap -> $A000
 +         STA BASE         
 +         LDA #01          
 +         STA BANK         ;Bank 2
 +         STA OLDBANK      
 +         LDA #$FF         ;End of BASIC memory
 +         STA $37          
 +         STA $33          
 +         LDA #$87         
 +         STA $38          
 +         STA $34          
 +         LDA #$24         ;Screen mem -> $8800
 +         STA OLDD018      
 +         JSR GSET         ;Part of GROFF
 +         LDA #$88         
 +         STA 648          ;Tell BASIC where the screen is
 +         STA $D07E        ;Enable SuperCPU regs
 +         STA $D074        ;Bank 2 optimization
 +         STA $D07F        ;Disable regs
 +         RTS              
 +:C18     CPX #18          ;Double-buffer mode!
 +         BNE :C17         
 +         STX MODENUM      
 +         JSR :SET16       ;Set up mode 16
 +         STA $D07E        
 +         STA $D077        ;Turn off optimization
 +         STA $D07F        
 +         RTS              
 +:C17     CPX #17          
 +         BNE MODEDONE     
 +MODE17   STX MODENUM      
 +         LDA #$E0         
 +         STA BASE         
 +         LDA #00          ;Bank 3
 +         STA BANK         
 +         LDA #3           ;Bank 0 == normal bank
 +         STA OLDBANK      
 +         LDA #$FF         
 +         STA $37          
 +         STA $33          
 +         LDA #$9F         
 +         STA $38          
 +         STA $34          
 +         LDA #$14         ;Screen mem -> $0400
 +         STA OLDD018      
 +         JSR GSET         ;Part of GROFF
 +         LDA #$04         
 +         STA 648          ;Tell BASIC where the screen is
 +         STA $D07E        
 +         STA $D077        ;No optimization
 +         STA $D07F        
 +         RTS              
 +MODEDONE STX BITMASK      
 +         RTS              
 +                          
 +                          
 +*
 +* BUFFER -- Sets the current drawing buffer to 1 or 2,
 +*   depending on arg being even or odd.  If double-
 +*   buffer mode is not enabled then punt.
 +*
 +*   Now, buffer=0 swaps draw buffers, even/odd otherwise.
 +*
 +BUFFER                    
 +         JSR GETBYT       
 +         LDA MODENUM      
 +         CMP #18          
 +         BNE :PUNT        
 +         LDY #$A0         
 +         TXA              
 +         BNE :CONT        
 +         CPY BASE         
 +         BNE :CONT        
 +         LDA #1           
 +:CONT    LSR              
 +         BCC :LOW         ;even = low buffer
 +         LDY #$E0         ;odd = high buffer
 +:LOW     STY BASE         
 +:PUNT    RTS              
 +                          
 +*
 +* SWAP -- Swap displayed buffers.  MODE 18 must
 +*   be enabled first.
 +*
 +SWAP                      
 +         LDA MODENUM      
 +         CMP #18          
 +         BNE :PUNT        
 +         LDA $DD00        ;Ooooooohhh, real tough!
 +         EOR #$01         
 +         STA $DD00        
 +:PUNT    RTS              
 +                          
 +*
 +* ORIGIN -- Set upper-left corner of the screen to
 +*   new coordinate offset.
 +*
 +ORIGIN                    
 +         JSR GETBYT       
 +         STX ORGX         
 +         JSR CHKCOM       
 +         JSR GETBYT       
 +         STX ORGY         
 +         RTS              
 +                          
 +         ORG              ;re-org
 +PEND                      ;To get that label right :)
 +
 +--
 +The BLARG distribution binary is available from 'The Fridge', Mr. Judd's
 +archival web page on the internet at http://stratus.esam.nwu.edu/judd/fridge
 +
 +
 +
 +:::::::::::d:i:s:C=:o:v:e:r:y:::::::::::::::::i:s:s:u:e::3::::::::::::::::::::
 +/S02::$d000:::::::::::::::::::S O F T W A R E:::::::::::::::::::::::::::::::::
 +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 +
 +
 +A CLOSER LOOK AT THE VIC II'S OUTPUT
 +by Adrian Gonzalez (DW/Style) & George Taylor (Repose/Style)
 +------------------------------------------------------------------------------
 +                                                         7
 +123456789012345678901234567890123456789012345678901234567890123456789012345678
 +
 +
 +Contents
 +--------
 +
 +0.  Preface
 +
 +1.  Introduction
 +     1.1  Target audience
 +     1.2  The legal stuff
 +
 +2.  The NTSC Y/C video signal
 +     2.1  A little history
 +     2.2  A closer look at black and white TV
 +     2.3  Let's talk about color
 +     2.4  The chroma signal
 +
 +3.  Wrapup
 +
 +    Bibliography
 +
 +
 +0.  Preface
 +-----------
 +
 +This text was originally formatted to 78 columns for ease of use.  This
 +ensures compatibility with MSDOS "edit" with scrollbars, as well as 80 column
 +readers that cause double spacing if the 81st character is a carriage return.
 +The text is written in conversation style to ease the problem of dual
 +authorship.  Subsections not marked may be considered generic text and may
 +have been written by either of us.  You will not be able to view the ASCII
 +diagrams in 40 columns. Major headings are marked with ---'s.
 +
 +
 +1.  Introduction
 +----------------
 +
 +DW:
 +
 +While working on an image conversion project, I stumbled upon the need to
 +find RGB values for the c64's colors.  My first idea was using two monitors
 +and matching the colors "by eye", however, this turned out to be more
 +difficult than I expected.  After trying other methods I decided the next
 +logical step was to analyze the c64's output and determine the RGB values
 +from there.  Simple enough, eh?  The only problem was that I had no clue as
 +to what the VIC-II's output looked like.  After digging up some books on TV
 +theory, I decided to embark on a quest to find RGB values for the c64's
 +colors, and I found many interesting things along the way. 
 +
 +This article is the result of many hours of research, programming, and taking
 +measurements.  I hope you find it interesting and perhaps even learn
 +something new from it (!).
 +
 +Repose:
 +
 +Coincidently, I was working on exactly the same kind of image conversion
 +project.  So I got together with DW to discuss our common problem of finding
 +the RGB colors of the 64.  I also put out a request to comp.sys.cbm and was
 +sent measurements from several people, including an excellent effort from
 +Marko Makela.
 +
 +1.1  Target audience
 +
 +This article should be very interesting for people doing emulators, image
 +converters, and other similar projects.  Due to the rather technical nature
 +of its content, it is not meant for beginners, however, the end result could
 +be very useful for anybody interested in using other platforms to do
 +graphics work for the c64.  If you're not sure whether this article is for
 +you or not, here are some terms you should be familiar with:  scanline,
 +frame, refresh rate, CRT, RGB, vertical and horizontal blanking.  These terms
 +are used all throughout the article, and it is assumed you already have a
 +basic knowledge of how a TV works.
 +
 +1.2  The legal stuff
 +
 +Part of this article deals with taking measurements from your c64.  If you
 +decide to tinker with your c64 and something goes wrong, it's your fault, not
 +ours.  The authors will not be held responsible for damaged equipment, data
 +loss, loss of sleep, loss of sanity, etc.  Now, on with the show.
 +
 +
 +
 +2.  The NTSC Y/C video signal
 +-----------------------------
 +
 +There's basically three ways you can connect your c64 to a TV or monitor and
 +get a color picture.  The first and perhaps the most common is to use the RF
 +modulated output with a TV tuned to channel 3 or 4.  The second and third
 +use the Video/Audio connector and require either a monitor or a TV/VCR with
 +A/V inputs.  We will get to each of these later on, but first, a little bit
 +of history.
 +
 +2.1  A little history.
 +
 +DW:
 +
 +In 1953, the National Television Systems Committee (NTSC) developed a
 +standard that allowed the transmission of color images while remaining
 +compatible with the large amount of black and white TV sets in widespread use
 +at the time.   In the US, public broadcasting (using the color NTSC system)
 +began in 1954.  The same system was adopted in Japan, where it came into
 +service in 1960. Other countries favored modifications of the NTSC system,
 +such as PAL (Phase Alternating Line) and SECAM (Systeme Electronique Couleur
 +Avec Memoire).
 +
 +Repose:
 +
 +PAL is used in many western european countries, and has technical advantages
 +to NTSC.  SECAM is used in eastern and middle eastern europe.  It is only a
 +semi standard in a way because video production is always done in PAL format,
 +and only converted to SECAM for final transmission.  The main point of this
 +was information control, as it offers no advantages over PAL.  As far as I
 +know, VIC IIs were only made to conform to PAL or NTSC standards.
 +
 +2.2  A closer look at black and white TV.
 +
 +In designing a TV system, the engineers had to make several considerations.
 +One had to do with bandwidth, which is the space that a TV channel takes in
 +the radio frequency spectrum.  To allow for many channels, and also to be
 +easy for the ancient technology of that time, it was decided to split up the
 +picture into two parts, and send each half sequentially.
 +
 +The display on your TV is made up of a several hundred scanlines, composed
 +of two fields which are interlaced to form a complete display, called a
 +frame.  This interlacing doesn't happen on the c64, but we will get to that
 +later.  First let's look at the fields:
 +
 +Odd field                                Even field
 +
 +                                     Scanline     1 +++++++++++++++++++++++
 +Scanline   2 ----------------------
 +                                     Scanline     3 +++++++++++++++++++++++
 +Scanline   4 ----------------------
 +                                     Scanline     5 +++++++++++++++++++++++
 +Scanline   6 ----------------------      .
 +.                                        .
 +.
 +                                     Scanline 2*n-1 +++++++++++++++++++++++
 +Scanline 2*n ----------------------
 +                                     Scanline 2*n+1 +++++++++++++++++++++++
 +
 +Each of the fields is 262 1/2 lines long (NTSC), (312 1/2 PAL) which means
 +each frame is 525 (625 PAL) lines long.  Your TV displays odd fields and
 +even fields one after another, and thanks to what is called "persistence of
 +vision" we see something like:
 +
 +Scanline     1 +++++++++++++++++++++++
 +Scanline     2 -----------------------
 +Scanline     3 +++++++++++++++++++++++
 +Scanline     4 -----------------------
 +Scanline     6 +++++++++++++++++++++++
 +.
 +.
 +
 +The second consideration the engineers had was how to represent a 2d image as
 +a 1d voltage.  To do this, they needed markers to separate a horizontal line
 +and also odd and even fields.
 +
 +So, let's take a closer look at what the voltage waveform for black and
 +white scanlines looks like:
 +
 +^  Voltage
 +|
 +|             Scanline n                                  Scanline n+2
 +|          ___________________________________         _________________..
 +|           White level                    |         |
 +|                                          |         |
 +|                                          |         |
 +|                                          |         |
 +|                                          |         |
 +|___  ____|   Black level                    |___  ____|
 +|  |  |                                          |
 +|  |__| <- Horizontal sync pulses ------------> |__|
 +|
 +-------------------------------------------------------------------------> 
 +Time
 +
 +The scanline in this example is a simple white line.  If you were to feed
 +enough of  these  to  your  TV  plus  some vertical sync signals, you would
 +get a white screen.  The horizontal sync pulses tell the TV receiver when a
 +scanline starts.  They  make  up  25% of  the  total  height  of  the signal.
 +
 +The brightness at a particular point of the scanline is defined by the
 +voltage of  the  waveform  at that instant.  With this in mind, if we wanted
 +to create a display with a simple white vertical line at the middle of the
 +screen, the waveform would look like this:
 +
 +^  Voltage
 +|
 +|                   Scanline n                              Scanline n+2
 +|                        __                                           __
 +|           White level |  |                                          |
 +|                        |                                          |
 +|                        |                                          |
 +|                        |                                          |
 +|           Black level |  |                                          |
 +|___  __________________|  |_____________________  __________________|  |
 +|  |  |                                          |
 +|  |__| <- Horizontal sync pulses ------------> |__|
 +|
 +-------------------------------------------------------------------------> 
 +Time
 +
 +
 +Let us now turn our attention to the visible display area on your TV:
 +
 +___                                                          ___
 +        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX     6% of frame
 +        XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ___ Vert. blank
 +        XXXXXXXX                                               ^
 +        XXXXXXXX                                               |
 +        XXXXXXXX                                               |
 +        XXXXXXXX                                               |
 + | Field  XXXXXXXX                                               |
 + | period XXXXXXXX                                               |
 + | (60hz) XXXXXXXX                                               |
 +        XXXXXXXX                                               |
 +        XXXXXXXX                                               |
 +        XXXXXXXX                                               |
 +        XXXXXXXX                                               |
 +        XXXXXXXX                                               |
 +        XXXXXXXX                                               |
 +        XXXXXXXX                                               |
 +_v_       XXXXXXXX                                              _v_
 +          |<---->|<---------------------------------------->|
 +           17% of                  83% of line
 +           line                    is visible
 +           Horiz.
 +           blank
 +          |<-------------------------------------------------->|
 +                      Line period: 63.5 microseconds
 +
 +The X's in the graph represent areas in which the in which your screen is
 +not visible.  At the top we have the vertical blanking interval, and at the
 +left we have the horizontal blanking interval.  Please note that whether
 +these intervals occur at the top or bottom, left or right or both, is not
 +relevant. It is shown this way in the diagram for the sake of clarity. So,
 +with that out of the way, let's see what happens in the vertical blank
 +interval (vblank from now on):
 +
 +^ Voltage
 +|
 +|    last                                                        time   ---->
 +|    scanline
 +|  __ _______ ___ ___ ___ ___ ___ __                            _ ___ ___ _..
 +|    |                  |    |           | | |     |
 +|    |                  |____|___|___|___|___|___|_| |     |
 +                                                ^            ^
 +Horizontal   End of even field         Serrated vertical sync    6 equalizing
 +sync pulse   6 equalizing pulses       pulse                     pulses
 +
 +Please note that the time scale has been compressed to be able to cover most
 +of the vblank interval.  Basically the vblank interval is composed of 6
 +equalizing pulses, one serrated vertical sync pulse, and 6 more equalizing
 +pulses.  The equalizing pulses and the serrations in the vertical sync pulse
 +are spaced half a scanline apart.  An interesting thing happens if we take
 +away the equalizing pulses and serrations:
 +
 +^ Voltage
 +|
 +|    last                                                        time   ---->
 +|    scanline
 +|  _________________________________                            ___________..
 +|                                                            |
 +|                                   |__________________________|
 +
 +                                       Vertical sync pulse
 +
 +We end up with a vertical sync pulse that looks very much like the
 +horizontal sync pulses, except it runs at a much lower frequency.  In NTSC,
 +the field frequency is 60 Hz, and the frame frequency is 30hz (PAL has a 50Hz
 +field rate and 25Hz frame rate).   In other words, we get one of these
 +vertical pulses on every field, to let the TV know when the field starts
 +(just like the horizontal sync pulses tell it when a line starts).  According
 +to an old book on TV theory, "serrations are placed in the vertical sync
 +pulse to stabilize the operation of the horizontal scanning generator during
 +vertical retrace time".
 +
 +One last thing remains before we move on to color television: interlacing.
 +Interlacing is achieved by making the field size 262 1/2 lines long, which
 +also changes the spacing between the equalizing pulses and the vertical sync
 +pulse. It will not be discussed any further, though, because the c-64's
 +output is not interlaced.  Instead, it is composed of always fields, thus
 +there are visible spaces between the scanlines.  The field rate may be
 +considered also the frame rate, since one field is a complete image in
 +itself.
 +
 +Note:  it is not known to us if the c64 produces even or odd fields.
 +
 +2.3  Let's talk about color.
 +
 +Up until now, we've only talked about black and white TV signals, but if you
 +remember the little bit of history in section 2.1, you know that color has
 +to be introduced in a way that doesn't interfere with the BW signal.  The
 +VIC-II really outputs two signals (NTSC version only):  the Luminance (Y)
 +signal and the Chrominance (C) signal.  The Y signal contains the brightness
 +information of the output, while the C signal contains color information.
 +The Y signal is just like the one described in the previous section, except
 +it is not interlaced.  The c64 has circuitry to mix the Y and C signals into
 +a composite video signal which has both BW and color info.  It then goes to
 +an RF modulator which allows these signals (plus audio) to be viewed on a TV
 +tuned to channel 3 or 4 (in the North American TV frequency).
 +
 +Before we move on to describe the color signal, we will talk briefly about
 +RGB.  RGB stands for Red Green Blue, or in other words, a set of three
 +primary colors, which are mixed in different amounts in order to obtain a
 +broad gammut (range) of colors.  An interesting thing to note is that it is
 +impossible to reproduce the entire spectrum of visible light with a set of
 +three (or any finite number) of real primary colors, however, RGB and other 
 +color systems do a fair job of being able to represent typical images.
 +RGB color is probably quite familiar to you, as it is the basis of the video
 +circuitry in most computers and their monitors.  However, NTSC/PAL signals
 +use an encoding called YUV.  Y is the brightness information, while UV are
 +the C or color information.  U and V are components of a vector.  You can 
 +picture this vector as originating from the centre of a circle.  It's angle
 +is the tint of the color, and it's radius is the saturation of the color.
 +The angle represents a full sprectrum, from red, to orange, yellow, green,
 +blue, purple, back to red again.  A highly satured color will be pure, while
 +no saturation would give a grey.  There are usually controls related to these
 +properties on a TV, called tint and color, or hue and saturation.
 +
 +2.4  The color signal
 +
 +Color was added to B/W NTSC in a very clever way.  It was added as a carrier
 +on top of the normal signal.  It is basically a sinewave of 3.574545Mhz
 +(NTSC) (4.43Mhz PAL) with a varying phase and amplitude.  To a B/W TV, this
 +will be seen as a fine wavey detail in the luminance.  But, a color TV uses a
 +filter to separate the high frequencies as the color signal, and pass on the
 +lower frequencies as the normal B/W signal.  This separation is not perfect,
 +and can cause several strange effects on the picture, known as "crawling
 +dots", "hanging dots", and "color moire patterns" (NTSC, similar effects may
 +appear in PAL).  That is why, coincidently, the S-VHS format was invented, to
 +physically separate the color signal from the luma signal.  One question,
 +that may have occurred to you, is how do you measure phase without a
 +reference point?  Fortunately, at the start of every rasterline there is a
 +calibration color signal known as the color burst, and from this sinewave,
 +the phase of the color signal is measured.
 +
 +The sinewave then continues, at the same time as the luminence portion of 
 +rasterline is sent, both signals varying to specify a color and luminance.
 +
 +   ***
 +  *             *
 +             
 +             *
 +*-------*-------*----> Time
 +             *
 +             
 +          *   *
 +           *** 
 +ColorBurst Reference Signal
 +
 +     ***
 +    *   *
 +       
 +       *
 +--*-------*-------*--> Time
 +             *
 +             
 +*             *
 +             *** 
 +An Orange color 30 degrees
 +out of phase with ColorBurst
 +
 +
 +3.  Wrapup
 +----------
 +
 +For now, we will end here.  Look forward to a second part, which will 
 +describe the signals as measured on the 64 in more detail, and finally 
 +provide the most accurate measurements of the 64's 16 colors known.  One 
 +important point which will be explained is how gamma affects RGB color 
 +measurements, and why any measurement must be given with gamma information,
 +and why putting the same RGB values into two different monitors will not 
 +cause the same colors to be seen.
 +
 +Also provided will be a program which can display the 64s colors on a PC and
 +let you play with hue and saturation controls.  When our measurements are
 +finalized, we would expect all emulator writers to add our calibrated 
 +colors to their programs, so that the original feeling of the 64 can be
 +retained.
 +
 +Please see http://nlaredo.globalpc.net/~agonzalez/index.html
 +for up to date information.
 +
 +
 +Bibliography
 +------------
 +
 +Introduction to Digital Video, Charles Poynton.
 +comp.graphics FAQ.
 +Television Theory and Servicing, second edition.  Clyde N. Herrick
 +
 +
 +
 +:::::::::::d:i:s:C=:o:v:e:r:y:::::::::::::::::i:s:s:u:e::3::::::::::::::::::::
 +/S03::$d000:::::::::::::::::::S O F T W A R E:::::::::::::::::::::::::::::::::
 +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 + 
 + 
 +                        : Innovation in the 90s :
 + 
 +Revisiting The Super Hi-Res Interlace Flexible Line Interpretation Technique
 +
 +         by  Roland Toegel (Crossbow/Crest), Count Zero/TRC*SCS, and
 +             George Taylor (aa601@chebucto.ns.ca)
 +
 +
 +Prelude from George Taylor, technical editor
 +----------------+--+--+---------------------
 +Once you have FLI, why not just overlay some sprites on it to make better
 +graphics?  A simple idea you may have thought of, but as you will see,
 +implementing the concept was very difficult.  There are two key concepts
 +to making it work.  The following article is a brilliant piece of work on
 +the subject.  It was presented in disC=overy (issue 2) and subsequently
 +raised a great deal of discussion.  There are some confusing concepts
 +involved so I have added extra interpretation to the original text as
 +as editorial notes, which I hope will help bridge the gap from foreign
 +language translated text and difficult explanations.
 + 
 +Prelude from Count Zero
 +--------+--+--+--------
 +
 +First seen earlier this year, the new SHIFLI video technique that is described
 +in this article is -the- paramount example of programming brilliance.  The
 +inventor of the technique, Roland Toegel (Crossbow of Crest), was helpful
 +in providing the original SHIFLI documentation, which I translated from 
 +German into the English text that follows for the exclusive use of the
 +disC=overy journal.
 +
 +So without further ado, let us now learn from Mr. Toegel how to achieve
 +the award winning :
 + 
 +   'Super Hires InterLace Flexible Line Interpretation' Graphics mode !
 + 
 +Please note that the technique is described primarily for Commodore computers
 +based on the European/Australian PAL TV standard. NTSC-based Commodore machines
 +require an extra 2 cycles per line to be added to the raster routine.  
 +This may require the programmer to time out the routines by hand, but this
 +should not be a major obstacle to overcome.
 + 
 +Count Zero
 +--
 + 
 +i.      Foreword
 + 
 +As the inventor of the SHI-FLI mode, I am pleased to have the services of
 +Count Zero and the disC=overy journal for the dissemination of my technique
 +into the English language.  I must add that the text below does require the
 +reader to be already familiar to a high degree with VIC-II programming on the
 +C64.  I would suggest books such as 'Mapping the 64' and the programming texts
 +found at ftp.funet.fi/pub/cbm/documents, for a solid base of instruction.  Also,
 +some terms used in this document (e.g., mix-color) are meant to be uniquely
 +descriptive and hence, will not be found in any 'standard' programming text.
 +The terminology is a result of the strain that occurs when new methodology
 +meets old semantics.  However, the experienced programmer should find the
 +words to be self-evident in the context which they are used.
 +
 +[Mix-color: a new color derived from the original 16 by the process
 +of alternating normal colors at such a high rate of speed that they
 +blend to the eye.  Also know as flashcolors. -GT]
 +--
 + 
 +1.      Introduction to Super Hires
 +
 +[Hires FLI: a graphics mode which uses rasters to enable the use of a separate
 +color memory on each line, thus giving 2 colors chosen freely in each
 +8x1 hires pixel area. Interlace: alternating any two graphics modes to allow
 +the use of mix colors. FLI without the 'hires' modifier usually means
 +the use of the FLI technique with a multicolor mode as the basis.  Super
 +Hires FLI might be more aptly named as Sprite Hires FLI, but the super means
 +that sprites are overlayed on top of another graphics mode. -GT] 
 +
 +Super-Hires Interlace FLI : The absolute successor of the Super-Hires-Modes.
 +Just like normal Super-Hires, the width is 96 Hires Pixels, which is equal to
 +12 Characters or 4 Sprites next to each other.  For visual enjoyment this
 +area is centered though using Char-Position 15 to 26 inclusive on the
 +screen.  The Y-Axis is 167 pixels high having nearly 21 Character lines or
 +8 Sprites and to have as much flexibility as possible on choosing colors or
 +pixels, 2 layers of sprites in a row of 4 beside each other are used
 +(8 sprites on the rasterline) over the bitmap graphics.  Due to the fact that
 +all 8 sprites are used for a 96 * 21 pixel-wide area, a small multiplexer is
 +needed to repeat the 8 layered sprites for 8 times, at 21 pixel intervals as
 +you go dowards on the screen, with each row using their own bitmaps.  
 +We thereby win 2 colors plus the 2 normal colors of the Hires-Bitmap Mode 
 +in an 8*8 pixel block.  Please note that the 2 additional colors
 +are the same throughout the whole picture.
 + 
 + 
 +2.      Super Hires with FLI !?!
 + 
 +FLI is, for most coders, still quite hard. Sprites over FLI, for most, quite
 +impossible. Maybe one or two sprites, but 8 !?! next to each other and
 +still FLI in each rasterline!  Hard to believe, eh?
 + 
 +First of all you need to know how to do FLI and what it does and also
 +what effect sprites have on it.
 + 
 + 
 +2.1     Normal FLI
 + 
 +On each eighth rasterline (the Badlines, the first rasterline of each charline)
 +the VIC stops the processor for 40-43 cycles to read the new Characters and
 +colors of the video and color-ram.  This is the case when the bits 0-2 of the
 +registers $D011 and $D012 are the same.  Now if you change on each rasterline
 +the bits 4-7 of $D018, which holds the length of the video-ram (handling the
 +colors on bitmap graphics) and set the bits 0-2 of $D011 to get a badline on
 +each rasterline, you will get new colors on each rasterline in the bitmap
 +graphics.  The only condition to be followed is that on each rasterline 23
 +cycles are used but for the *used cycles - 22* char of the textline the
 +next 3 chars have the byte $FF (light grey) read from the video ram and the
 +FLI effect starts after that (the FLI bug).  In the multicolor mode, for the
 +color-ram the next byte in the program after writing to $D011 is chosen as
 +the color.  As we are using the Hires Mode here, this is irrelevant.
 + 
 +> NOTE: The last 3 sentences were pretty hard to translate and I advise you
 +>       to read other articles about FLI aswell, if you want to know more
 +>       about Multicolor FLI. (CZ)
 + 
 + 
 +2.2     Sprites over FLI
 + 
 +So what does a sprite do over FLI?  Pretty simple, as it just eats up some
 +cycles.  All 8 sprites use 19 cycles per rasterline, meaning in the case where 
 +we code our FLI routine without loops, we just need 2 x (LDA, STA) commands 
 +(for $D018 and $D011), using 12 cycles per rasterline.  All together with the
 +8 used sprites that makes 31 cycles.  Thus, the 'light grey' FLI-Bug occurs on
 +char-positions 9,10 and 11 and from char 12+, the FLI effect comes up.  This
 +doesn't matter much to us, as the Super Hires Picture starts at Char-Pos 15.
 +We therefore get 3 cycles per rasterline for other commands.
 +
 +[The explanation of when the FLI effect starts in 2.1 was unclear.  Here
 +we can understand that the effect starts 3 cycles after the write to $d011.
 +The only catch is that this code is delayed by the extra DMA time used by
 +the sprites.  Thus the formula (12+19)-22=9 gives the start of the grey
 +pattern, and 9+3=12 is the start of the FLI effect.  The constant 22 comes
 +from a measurement of when the CPU continues after DMA is released, relative
 +to the position on the raster line. -GT]
 +
 + 
 +3.      Mulitplexing over FLI
 + 
 +Now we have to increase the Y-Coordinates of the sprites by 21 pixels
 +each 21 rasterlines and give them new patterns.  As we use 8 different
 +video-rams on FLI for the colors and the sprite-pointers are always at the
 +end of the video-ram, we are supposed to write 8 * 8 values for the patterns
 +plus 8 values for the Y-Coordinates, resulting in 72 different addresses.
 +Thats far too much for a single rasterline and adding the FLI routine will
 +bust the limits.  Therefore we have to do a little trick.
 + 
 + 
 +3.1     Changing the sprite-pointers
 +
 +The trick is not to change anything at all!  On the other hand we don't want
 +the patterns to look the same everywhere.  Luckily, the height of a sprite
 +(21 pixels) is not capable of being divided by the height of a textline
 +(8) and the smallest mutual multiple is 168 (meaning 21 * 8).  As we are
 +writing (due to the FLI) a new value to $D018 on each rasterline and we use
 +8 video rams, we can abuse this and have different sprite-pointers on every
 +video-ram.  The handling of where the graphics for the sprite-patterns are
 +located becomes a little bit confusing, but it doesn't eat up any rastertime
 +as we don't have to change the pointers.
 +
 +[Put another way, we take advantage of the fact that the video
 +matrix location is changing every raster line (and therefore also the
 +sprite pointers at the end of the video matrix), and slice up the sprites
 +so that the bitmap definition is located in a different place in memory
 +for each line of the sprite.  This is very confusing, and the graphics
 +are spread throughout memory in essentially random locations to make
 +them fit around the other graphics areas.  But at least it is possible
 +to give every part of every sprite a separate bitmap without changing
 +sprite pointers at all, and is the first key concept to making this
 +technique work, and a brilliant invention by Mr. Togel. -GT]
 +
 +
 +3.1.1   Table to illustrate the sprite pattern-handling
 + 
 +Spriteline      Video-Ram     Screenline (NOT equal to rasterline!)
 + 
 +1                           1
 +2                           2
 +3                           3
 +4                           4
 +5                           5
 +6                           6
 +7                           7
 +8                           8
 + 
 +9                           9
 +10              2             10
 +11              3             11
 +12              4             12
 +13              5             13
 +14              6             14
 +15              7             15
 +16              8             16
 + 
 +17              1             17
 +18              2             18
 +19              3             19
 +20              4             20
 +21              5             21
 +--------------------------------
 +1                           22
 + 
 +2                           23
 +3                           24
 + 
 +4                           25
 +.                           .
 +.                           .
 +.                           .
 +20              1             41
 +21              2             42
 +--------------------------------
 +1                           43
 +2                           44
 +3                           45
 +.                           .
 +.                           .
 +.                           .
 + 
 + 
 +3.1.2   Example
 + 
 +Small example for Sprite 0 under the following conditions:
 + 
 +Used 8 Video-Rams            : $4000 - $5FFF
 +content of the sprite-pointer: $43F8  80 00 00 00 00 00 00 00
 +                               $47F8  81 00 00 00 00 00 00 00
 +                               $4BF8  82 00 00 00 00 00 00 00
 +                               $4FF8  83 00 00 00 00 00 00 00
 +                               $53F8  84 00 00 00 00 00 00 00
 +                               $57F8  85 00 00 00 00 00 00 00
 +                               $5BF8  86 00 00 00 00 00 00 00
 +                               $5FF8  87 00 00 00 00 00 00 00
 + 
 +Thus the Sprite-Patterns are in memory from $6000-$61FF.
 + 
 +Therefore the pattern-handling looks like this:
 + 
 +Screenline      Memorylocation
 + 
 +1               $6000-$6002
 +2               $6043-$6045
 +3               $6086-$6088
 +4               $60C9-$60CB
 +5               $610C-$610E
 +6               $614F-$6151
 +7               $6192-$6194
 +8               $61D5-$61D7
 +9               $6018-$601A
 +10              $605B-$605D
 +11              $609E-$60A0
 +12              $60E1-$60E3
 +13              $6124-$6126
 +14              $6167-$6169
 +15              $61AA-$61AC
 +16              $61ED-$61EF
 +17              $6030-$6032
 +18              $6073-$6075
 +19              $60B6-$60B8
 +20              $60F9-$60FB
 +21              $613C-$613E
 +22              $6180-$6182
 +23              $61C3-$61C5
 +.               .
 +.               .
 +.               .
 + 
 + 
 +3.1.3   Remark to the display-routine of the editor
 + 
 +As the changing of the video-ram on the editor-routine happens inside of the
 +textscreen (but the spritepointers are read inside the sideborder), the change
 +takes effect one rasterline later.  
 +
 +[To state this again, the changes in the raster routine are made at a time
 +when the sprite pointers have already been read by the VIC, therefore,
 +even though the changes are made on the same raster line, they don't
 +take effect until the next raster line. -GT]
 +
 +This means that whenever the colors for the bitmap of color ram 2 are read,
 +the sprite pointers or video ram 1 are still active.  This is the reason why
 +the editor uses only 167 screenlines (instead of 168) and why the first
 +textline of the first video-ram and the first rasterline of the bitmap
 +stays empty.
 +
 +[I would consider this a minor bug which potentially could be fixed in
 +a future version, by starting the raster routine one line earlier. -GT]
 +
 + 
 +3.2     Changing the Sprite Y-Values
 + 
 +As the changing of the sprite pointers more or less happens by itself, we just
 +have to make sure the correct Y-Value comes into the game.  These are still
 +8 values, but they don't have to be set in one rasterline and we got 21
 +rasterlines to set them.  As we have just 3 cycles left on each rasterline on
 +the FLI routine described and that wouldn't be enough for a simple LDA : STA,
 +we have to change the FLI routine a little bit.
 + 
 + 
 +3.2.1   Load new sprite Y-Value
 + 
 +As the height of all sprites is the same, we just have to do a single
 +LDX #$VALUE.  Therefore, 2 of the 3 free cycles are used and we cannot do
 +anything else with the last free cycle.
 + 
 +LDX #$VALUE
 +LDA #$08
 +STA $D018
 +LDA #$38
 +STA $D011
 + 
 + 
 +3.2.2   Preload the Upcoming $D011 Value
 + 
 +As a STA $SPRITE0Y needs 4 cycles, we cannot include it in the next rasterline,
 +but we can already load the next $D011 value into the Y-Register.  The free
 +cycle stays unused.
 +
 +LDY #$3A
 +LDA #$18
 +STA $D018
 +LDA #$39
 +STA $D011
 + 
 + 
 +3.2.3   Write new Sprite Y-Value
 + 
 +As we already did the loading of the $D011 value for the next line, we now
 +have 5 cycles left and therefore enough time for a STA $SPRITE0Y.
 + 
 +STX $SPRITE0Y
 +LDA #$28
 +STA $D018
 +STY $D011
 + 
 +Now plot 3.2.2 and 3.2.3 have to be repeated for the remaining 7 sprites with
 +changed values for $D011 and $D018.  So there is now 1 rasterline for loading
 +the new sprite Y-value and 8 * 2 rasterlines to write the new sprite Y-Value.
 +We now have 17 rasterlines and the 4 remaining ones just need an additional
 +NOP so that all rasterlines use the same amount of cycles.
 +
 +[This tricky piece of raster code is the second brilliant concept to
 +making the technique work.  Note also that there will be some staggering
 +in the timing of FLI effect, due to the unused cycles, but still
 +within the parameters required.  Also it seems that parts of the
 +row of 4 sprites in 2 layers would gradually be moved downward after
 +parts of them have already been drawn, therefore causing a repetition
 +of graphics, except for the fact that the sprite pointers are different
 +in the new position, and that the sprites are really sliced apart in
 +lines, so it doesn't matter.  I find this a very difficult concept. -GT] 
 +
 + 
 +3.2.4   Remark to the Display-routine of the editor
 + 
 +For simplification of the routine, which generates the FLI routine, in the
 +remaining 4 rasterlines an LDX #$VALUE was used instead of an NOP.
 + 
 + 
 +4.      Memory-allocation
 +
 +Now video-rams, the bitmap, and the sprites have to be placed reasonably in
 +a VIC-Bank.  As the banks from $0000 - $3FFF and $8000 - $BFFF are useless
 +for graphics due to the overlay of the Char-rom we choose the back from
 +$4000 - $7FFF for now.
 + 
 + 
 +4.1     Video-rams
 + 
 +The 8 video-rams need $2000 Bytes.  They are located from $4000 - $5FFF.
 +
 + 
 +4.2     Bitmap
 + 
 +The bitmap needs $1F40 Bytes.  It's located at $6000 - $7F3F.
 + 
 + 
 +4.3     Sprites
 + 
 +As we need 2 sprites overlayed {two layers of 4 sprites next to each other}
 +(four times next to each other and 8 times below each other), we need
 +2 * 4 * 8 sprites, meaning 64 overall.  We need $1000 bytes for the
 +sprites.  We check what the video-rams and the bitmaps already allocate
 +and recognize that only $7F40 - $7FFF, enough memory for 3 sprites, is
 +left open.  How do we rectify this situation?
 + 
 +As the video-rams and the bitmap just need a small part for displaying the
 +picture, the sprites can be put into the spare parts of the video-rams and
 +the bitmap.  They have to be masked by choosing the right color in the video-
 +rams.
 + 
 +A textline of a bitmap covers $140 bytes.  Our Super Hires cutout just needs
 +$60 bytes though and is centered.  Thus the first and the last $70 bytes of
 +a textline of the bitmap is free.  As a sprite needs $40 bytes, we can put 2 
 +sprites in each textline of the bitmap (one to the left and one to the right).
 +Due to the height of the picture (21 textlines), this results in space for
 +42 sprites.  From textline 22 on (in memory from $7A40) we can use the whole
 +textline for sprites, resulting in 5 sprites per line.  Continuing this until
 +textline 24 inclusive, we have space for 15 additional sprites.  So overall
 +we already have 57 sprites and just 7 are missing now.  These we could place
 +in the remaining free area of the bitmap ($7E00-$7FFF), but that's not very
 +efficient as we have some space left in the video-rams.
 + 
 +The Textline of a video-ram contains $28 bytes.  The Super Hires cutout just
 +needs the middle $0C bytes.  As the sprites we put to the left and to the right
 +of the picture are supposed to be invisible, we need to set a background-color
 +in the video-ram (in our case, the color light-grey $FF).  So we don't have
 +enough spare room for the sprites to the left and the right of the picture
 +in the video-ram.
 +
 +If we finish the FLI Routine from textline 22 on and keep the video-ram on
 +until the end of the screen (filling the this area ($4370-$43E8) with the
 +backgroundcolor $FF to hide the sprites) we can use the remaining 7 video-rams
 +from textline 22 (from $4770, $4B70, $4F70, $5370, $5770, $5B70, $5F70) for
 +one sprite each.  Now we have placed all 64 sprites and the allocation of the
 +sprite pointers looks like this:
 + 
 +$43F8  80 84 85 89 8A 8E 8F 93
 +$47F8  94 98 99 9D 9E A2 A3 A7
 +$4BF8  A8 AC AD B1 B2 B6 B7 BB
 +$4FF8  BC C0 C1 C5 C6 CA CB CF
 +$53F8  D0 D4 D5 D9 DA DE DF E3
 +$57F8  E4 E8 E9 EA EB EC ED EE
 +$5BF8  EF F0 F1 F2 F3 F4 F5 F6
 +$5FF8  F7 1E 2E 3E 4E 5E 6E 7E
 + 
 +The pointers from $80 to $E4 are the 2 sprites which are left and right
 +next to the picture in the bitmap.
 + 
 +The pointers from $E8 to $F7 are the sprites from textline 22 to 24 below
 +the picture in the bitmap.
 + 
 +The pointers from $1E to $7E are the sprites from textline 22 to 24 below
 +the picture in the video-rams.
 + 
 + 
 +5.      Interlace
 + 
 +Until now we had the normal Super Hires FLI mode, supplying the basics for
 +interlace.  For the interlace mode we need 2 pictures of this kind switching,
 +displayed 25 times per second (PAL).  [30 times/sec in NTSC -GT]  As such
 +a picture fits into the VIC-Bank from $4000 - $7FFF and we have another
 +VIC-Bank ($C000-$FFFF) with the same assumptions we can easily place the
 +2nd picture there.
 + 
 +We had in the Super Hires FLI mode (on a 8 * 1 pixel-area) the choice between
 +4 colors (2 sprite-colors, being the same for the whole picture + 2 FLI
 +colors).  Now, in the interlace mode, we have the choice between 16 mix-colors,
 +meaning the combined 4 colors from picture one and two.  When using interlace,
 +mix-colors are created except for the case when the same colors are used for
 +both pictures on the same 8 * 1 pixel-area (Check the following example) :
 + 
 + 
 +      Pic2 ->        Sprite1:$E [ Sprite2:$0 [ FLI1:$6 [ FLI2:$9
 +----------------------------------------------------------------
 +Pic1    Sprite1:$1  [   $1E        $10       $16     $19
 +  [     Sprite2:$3  [   $3E        $30       $36     $39
 +  V     FLI1   :$E  [   $EE        $E0       $E6     $E9
 +        FLI2   :$6  [   $6E        $60       $66     $69
 + 
 + 
 +This results in the following 16 mixcolors:
 + 
 + 1. White-Lightblue
 + 2. Cyan-Lightblue
 + 3. Lightblue-Lightblue (pure Lightblue)
 + 4. Blue-Lightblue
 + 5. White-Black
 + 6. Cyan-Black
 + 7. Lightblue-Black
 + 8. Blue-Black
 + 9. White-Blue
 +10. Cyan-Blue
 +11. Lightblue-Blue
 +12. Blue-Blue (pure Blue)
 +13. White-Brown
 +14. Cyan-Brown
 +15. Lightblue-Brown
 +16. Blue-Brown
 + 
 + 
 +When choosing the colors you should take care that the brightness-values of
 +the 2 mix-colors are about the same and that they do not differ by more than
 +2 brightness steps, as things otherwise start to flicker too much.
 +(e.g. Black-White flickers a lot).
 + 
 +Here is a table with brightness-values from light to dark.
 +(Colors on the same line have the same brightness)
 + 
 +$1     : White
 +$7, $D : Yellow, Lightgreen
 +$3, $F : Cyan,   Lightgrey
 +$5, $A : Green,  Lightred
 +$C, $E : Grey,   Lightblue
 +$4, $8 : Lilac (Purple), Orange
 +$2, $B : Red ,   Darkgrey
 +$6, $9 : Blue,   Brown
 +$0     : Black
 +
 +[On very old 64's (64 cycle raster line NTSC VICs), there are only 5 luminance
 +values in the 16 colors, making them less distinct.  Yellow and cyan are
 +the same brightness, then green, grey, and purple, then red and blue.  White
 +and black form the last 2 values of brightness.  The pairing of colors above
 +are included. -GT] 
 +
 + 
 +6.      Additional Graphics (Not handled by the editor)
 + 
 +We found out that on the left or right of the picture in the bitmap, $70 bytes
 +was left for spritedata.  We used just $40 bytes of that space, meaning we
 +still have $30 bytes (6 Chars or 48 Pixels) left to both sides of the picture.
 + 
 + 
 +6.1     Left to the picture
 + 
 +Our Super Hires Picture starts at position 15.  The spare $30 bytes are from
 +position 9 to 14.  As we use 14 cycles in our FLI routine and the 8 sprites use
 +19 cycles per rasterline, the light-grey FLI Bug now uses the chars 11, 12, 14.
 +Thus meaning we could use char 14 for Hires FLI.  On chars 9 and 10 we could
 +just use 2 different colors (respectively 4 mix-colors for interlace) on the
 +height of 21 textlines in the bitmap, as the FLI effect starts from Char 14 and
 +before that no new data (colors in this case) are read from the video-ram.
 +The colors are in the first video-ram in memory from $4008+$4009 respectively
 +$C008+$c009.
 +
 +[The shifli pic could probably be expanded by rearranging the raster
 +code very carefully, and even areas outside the shifli effect could still
 +use normal graphics modes, but I expect only a small improvement. -GT] 
 +
 + 
 +6.2     Right to the picture
 + 
 +Our Super Hires Picture lasts until char-position 26.  The spare $30 bytes in
 +the bitmap are from position 27 - 32.  Here we could use all 6 chars for Hires
 +FLI (or Interlace Hires FLI).
 + 
 + 
 +7.      Memory-allocation of a picture startable with RUN
 + 
 +The included SHIFLI picture, once unpacked, can be easily modified for your own
 +use, as follows :
 + 
 +$0801-$080C Basic Startline
 +$080D-$0860 Routine for copying the Graphic-data to the correct memory area
 +$0861-$095B Routine which is setting the I/O registers and creates the
 +            display-routine (from $085F-$10FB)
 +$095C-$475B Data of the 1. Picture (to be copied to $4000)
 +$475C-$855B Data of the 2. Picture (to be copied to $C000)
 +
 + 
 +8.      Conclusion
 + 
 +For questions or comments concerning this article :
 +Roland Toegel is available at      : toegelrd@trick.informatik.uni-stuttgart.de
 +Count Zero/TRC*SCS is available at : count0@mail.netwave.de
 +
 +
 +
 +:::::::::::d:i:s:C=:o:v:e:r:y:::::::::::::::::i:s:s:u:e::3::::::::::::::::::::
 +/S04::$dd00:::::::::::::::::::S O F T W A R E:::::::::::::::::::::::::::::::::
 +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 +
 +
 +                   Defeating Digital Corrosion (aka "cracking")
 +
 +                    - a beginners guide to software archiving
 +
 +                      By Jan Lund Thomsen (aka QED/Triangle)
 +
 +
 +   Pontus Berg briefly touched the subject of tape cracking in his disC=overy
 +1 article (/S08: Software analysis and reconstructive therapy, a historical
 +view on "cracking"). But then again, "great minds think alike". :)
 +   The purpose of this article is to provide a broader, more detailed view at
 +the general components - as well as some insight on the way a cracker did his
 +"thing" back in the old days. Although some degree of technical knowledge is
 +required to make the most of this article the casual C64 enthusiast should also
 +be able benefit from it.
 +
 +
 +Disclaimer
 +----------
 +   Despite the issues discussed in this article it is in no way written to
 +encourage software piracy. You are not allowed to use the knowledge found here
 +to make copies for other people. If you go ahead and do this despite what I
 +have just said it is not my problem and I can't be held responsible in any way.
 +
 +[Ed. note : As always, disC=overy and the editors and staff of disC=overy can
 + not be held responsible for the use or misuse of any information presented
 + in this article.]
 +
 +Preface
 +-------
 +   In a world of digital corrosion the need to create backups is something
 +most of us deal with sooner or later. You might never have had any problems
 +yourself - but tapes or disks have been known to "go bad". And what if your
 +tape deck suddenly blows up, rendering you unable to play your favourite games?
 +Wouldn't it be nice to have a backup? Some people (myself included) prefer
 +using the backup copy and storing the original in a safe place. Copies can be
 +stored on floppy disks or hard drives for easier/faster loading. Creating an
 +exact copy of a backup is not only very easy; it eliminates the risk of
 +losing data due to corroded tapes.
 +
 +   Yes, the techniques described here are exactly the same as software pirates
 +have been using since the dawn of time; defeating a protection scheme in order
 +to create something that can easily be backed up. This article is *not* about
 +Software Piracy (and I will not answer any comments on that issue). I strongly
 +believe that owners of original software have every right to create backups. 
 +
 +   During the course of this article I will be looking into the specifics of
 +transferring original tape software to disk. I have several reasons for
 +choosing the subject of tape rather than disk software:
 +
 + - I have far more tape originals than disk originals. (I.e. more research
 +   material.)
 +
 + - From a beginners point of view, Tape software is far easier to crack.
 +
 + - Disk originals are easier to reproduce, and therefore not as vulnerable to
 +   digital corrosion as tapes.
 +
 +
 +Requirements
 +------------
 +   Apart from a tape deck and one or more original tape programs it goes
 +without saying that a good deal of 6510 Assembly skills are required to be
 +able to be a successful cracker. A good cartridge is really a must as well.
 +I prefer the Action Replay Mk V or the Expert V4.2 due to their awesome
 +debugging features.
 +
 +
 +Why don't I just use the backup option in my cartridge?
 +-------------------------------------------------------
 +   To be able to answer this question we need to go back in time and take a
 +look at the C64 crackers of yesteryear. As different people all over the world
 +were pirating software, cracking soon became a quest for quality rather than
 +quantity. Of course some people cared less about quality and more about
 +releasing a steady stream of software.
 +   A real cracker didn't care about speed. Any cracker could produce a working
 +copy in a couple of hours - but the real cracker wasn't satisfied with just
 +producing a "working copy". Why would anyone capable of doing a *great* crack
 +settle for less? For some crackers "good" simply wasn't good enough. Bugs were
 +fixed, cheat modes installed, and excess data was surgically removed to
 +produce shorter, cleaner cracks.
 +   Real cracking is about technical achievement, pride, dignity, and a
 +dedication to quality. Needless to say, no cracker worth his salt will want
 +to freeze/backup anything. I, for one, have never used this feature of my
 +Action Replay - not even for the purpose of producing copies for my eyes only.
 +
 +   Although a backup created with the "backup" option of the Action Replay,
 +Expert, or any other freezer cartridge might run just fine, it can *never* be
 +as good as the result produced by a dedicated cracker who knows what he is
 +doing. 
 +
 +   In short: *Anyone* can press a button.
 +
 +
 +Getting started
 +---------------
 +   As this article is aimed at the beginner level we will only deal with
 +"single-loaders" - i.e. programs loaded into memory in a single pass. Programs
 +using additional I/O (highscore savers, intermission screens, levels, etc.)
 +are known as "multi-loaders" and will be briefly mentioned in chapter 5: What's
 +next?
 +
 +   Cracking (let's not beat about the bush and call it something else just to
 +be politically correct) a tape game boils down to the following four steps:
 +
 +       1) Transferring the loader to disk.
 +       2) Analysing the loader.
 +       3) Modifying the loader and pulling the files off tape.
 +       4) Wrapping up.
 +
 +
 +Chapter 1: Transferring the loader to disk  (or "One small step...")
 +--------------------------------------------------------------------
 +   By definition, copy protection prevents the user from duplicating a piece
 +of software. In the case of tape software programs are stored in a non-standard
 +format, incorporating a fast loader of some sort. The "loader" - a short
 +assembly program at the start of the tape contains the program code necessary
 +to load the rest of the data. As the loader is stored in the standard tape
 +format it is fitted with an autostart feature to prevent tampering.
 +
 +   Therefore, the first step to transferring a tape original to a copyable
 +form is to load the "Loader" program *without* starting it. Luckily Commodore
 +themselves come to our rescue with the following ROM routines:
 +
 +        Decimal  Hex.    Description
 +        -----------------------------------------------
 +        #63278   $F72C   Read program header off tape
 +        #62828   $F56C   Read rest of program off tape
 +
 +By inserting a tape and issuing the 'SYS 63278' command the program header
 +will be read into the tape buffer at $033C-03FC. The first bytes of a typical
 +program header will look something like this:
 +
 +   .:033C 03 A7 02 04 03 4C 4F 41 .....LOA
 +   .:0344 44 45 52 00 00 00 00 00 DER.....
 +
 +As you might have noticed, the filename is stored from $0341 onwards. However,
 +the five bytes from $033C-0340 are of much more interest to us. The first
 +byte describes the type of header: in this case "03" - a machine language
 +program. The next four bytes contain the start and end address (Low/High byte)
 +of the program. This header above denotes "LOADER", a machine language
 +program loaded from $02A7-0304. As the $0300-0304 area contains a number of
 +system vectors that can be modified to to point at the loader program and
 +this explains the autostart.
 +
 +If we modify the start/end address before reading the rest of the program
 +(using the routine at $F56C) the file will be relocated, thereby circumventing
 +the autostart. I recommend adding #$10 to each of the high bytes (thus
 +shifting the entire loader $1000 bytes upwards in memory) as this makes
 +further studies a lot easier. The file in question would be relocated to
 +$12A7-$1304.
 +
 +Having read the "loader" program to another memory location we are now able
 +to save it to disk. But that's not all! Program code can also be stored in the
 +tape buffer so be sure to examine the contents of $033C-03FC before moving on
 +to step 2. If the buffer contains any other data than the five control bytes
 +and the filename discussed earlier, save it to disk as well.
 +
 +Congratulations! You have now taken the first step... there's much more to
 +come!
 +
 +
 +Chapter 2: Analysing the loader.
 +--------------------------------
 +   Brace yourselves! This is the tough part.
 +
 +   There are a *lot* of different protections out there. It would be rather
 +impossible to discuss even a fraction of them here. Some tape protections are
 +quite easy to crack once you've gotten past the initial autostart loader.
 +Others might require you to decrypt data in one way or another. Some particular
 +nasty systems even load a new copy of the loader on top of the old one to
 +prevent tampering (the Firebird Gold loader being a good example of this).
 +Cyberload, the mother of all tape protection schemes, not only uses this
 +technique - it also features encryption as well as two different load
 +systems. If you can force a Cyberloader to it's knees, you have every
 +reason to be proud of yourself.
 +
 +   It really goes without saying that a good deal of assembly language skills
 +are required in order to understand what goes on. However, as long as you are
 +able to grasp the overall function of the various parts of the program under
 +scrutiny - you do not need to know every detail about the inner workings of it.
 +Having said that it should be obvious that the odds increase the more you are
 +able to understand. In other words: Practice! Practice! Practice!
 +
 +Consider the following example:
 +
 +        l1     JSR $XXXX        ; get byte from tape
 +               STA ($F9),     ; store in memory
 +               INC $F9          ; increase pointers
 +               BNE l2
 +               INC $FA
 +        l2
 +               [...]            ; check for end-of-file/last file/etc.
 +               BNE l1
 +               SEI
 +               LDA #$35
 +               STA $01
 +               JMP $1000        ; start the program.
 +        
 +        XXXX   [...]
 +        l3     LDA $DC0D
 +               AND #$10
 +               BEQ l3
 +               LDA $DD0D
 +               STX $DD07
 +               LSR
 +               LSR
 +               LDA #$19
 +               STA $DD0F
 +               [...]
 +               RTS
 +
 +   The subroutine at XXXX seems to be doing something with certain I/O
 +registers. Understanding exactly what goes on isn't all that important because
 +by looking at the code following the JSR (at l1) we can clearly see that
 +something is stored in memory after calling the routine - i.e. the routine at
 +XXXX must be some kind of loader. As Sir Arthur Conan Doyle's famous detective
 +would put it, "Elementary, my dear Watson."
 +
 +   Sometimes you will have to overcome various obstacles to get to the heart
 +of a loader. Some protections schemes rely on encryption, others on obfuscated
 +coding. The creators of the most sophisticated protection schemes knew that
 +understanding what goes on is the key issue regarding cracking, and went to
 +great lengths to discourage the "professional" as well as the casual cracker.
 +
 +
 +Chapter 3: Modifying the loader and pulling the files off tape.
 +---------------------------------------------------------------
 +   Now that you have penetrated the outer layers, you will want to pull the
 +individual files off the tape and store them on disk. One approach would be
 +to locate the piece of code that launches the main program and replace it with
 +something that halts the computer using a infinite loop, allowing you to enter
 +your cartridges in-built monitor, and save a memory dump to disk. In some cases
 +it is advisable to halt the computer after each file has loaded and save the
 +data to disk before carrying on to the next file.
 +   Whatever approach you choose the key issue is to halt the C64 and save the
 +relevant data. 
 +
 +If space permits, I prefer to insert the following piece of code:
 +
 +        SEI
 +        LDA #$37
 +        STA $01
 +     l1 INC $D020
 +        CLC
 +        BCC l1
 +
 +If there is no room in loader for big modifications like the above make a note
 +of the original code before modifying the loader.
 +
 +     l1 CLC
 +        BCC l1
 +
 +also works quite well, not to mention only taking up three bytes. However,
 +this requires you not to enter the monitor until you are completely sure the
 +program has entered the infinite loop. I have used this approach so much that
 +I know the assembly opcodes ($18,$90,$FD) by heart, even though I haven't used
 +them in years.
 +
 +   Now that the C64 is halted and we are ready to save the data to disk we
 +need to obtain the relevant addresses. I mean, why take up too much diskspace?
 +:)  Using the example from the previous chapter the data was stored at the
 +memory location held in $F9/$FA <STA ($F9),Y>. Thus, looking at the content of
 +$F9/$FA will give us the end address of the file. For the start-address we can
 +either make an educated guess using the 'M'emorydump or 'I'nterrogate to scroll
 +backwards until we encounter something that does not look like it belongs to
 +the file (after lots of practice real crackers can be quite good at this.)
 +A more precise (not to mention subtle) approach is to patch the loader to store
 +the content of the pointer elsewhere and modify the loader back to normal to
 +prevent the start-address from being increased due to the pointer being
 +increased.
 +
 +
 +Chapter 4: Wrapping up.
 +-----------------------
 +   Having transfered the files to disk it is time to wrap everything up. This
 +is by far the easiest step. Link the relevant files, then use a Char/RLE
 +packing program (EBC, Link & Crunch, X-Terminator, etc.) followed by a
 +"cruncher" program (DarkSqueezer, Byteboiler, Cruelcrunch, etc.)
 +
 +   For shorter, cleaner cracks be sure to removing any excess data. Try
 +having a look at the game code - be sure to examine any memory-ranges that
 +are cleared by the startup code. Often quite a bit of data can be surgically
 +removed without causing any damage to the "patient".
 +
 +   Loading pictures are most often turned into stand-alone files. Just add a
 +short piece of code to get the graphics on screen and pack everything.
 +
 +   *Test* the finished product. In the old days a lot of bad quality could
 +have been avoided if crackers had taken the time to make sure everything worked
 +before releasing it onto the public. Again, this boils down to real cracking
 +being more than just churning out a heap of "warez" every day. I suppose the
 +modern day term is "quality assurance". :)
 +
 +
 +Chapter 5: What's next?
 +-----------------------
 +
 + Practice
 + --------
 +    Just because you suddenly find yourself able to breach one protection
 +scheme doesn't mean that you have suddenly become an expert cracker. Lots of
 +practice and further studies are needed to become successful. If you have more
 +than one original tape using the same copy protection, don't be afraid of
 +experimenting. Maybe you'll want to try out some new approaches. A lot can be
 +learned from writing a program to automatically transfer files saved by a
 +specific system. Gradually progress to other systems. If a system seems
 +impossible to breach, try sharpening your skills on easier systems and coming
 +back to it later.
 +
 +As mentioned earlier, there are a *lot* of different loaders on the market.
 +Although the schemes used vary from one program to another, chapters 2 and 3
 +should give you a rough idea about the basic idea and the steps needed to
 +circumvent various systems.
 +
 +
 + Multiloaders
 + ------------
 +    Multi-loaders (Programs using additional I/O such as intermission screens,
 +levels, etc.) will require you to replace the original loader with a custom
 +disk-loader. If you poke around the original loader you will most likely
 +discover some sort of internal level-counter that can be used to refer to the
 +name of the file you want to load next. Be sure to compress data files with
 +a Levelpacker for a result consuming a lot less disk space. Levelpackers
 +include a short loader/depacker program that will decompress the files on
 +the fly.
 +
 +
 + Disk originals
 + --------------
 +    Feeling confident about tape cracking? Why not move on to disks? Be
 +prepared to encounter everything from minor obstacles to the meanest mothers
 +in the business. Disk cracking is, as they say, "A whole different ballgame!"
 +
 +
 +---
 +The author has been a C64 enthusiast for the past 11 years - and a general
 +8-bit addict for even longer. In his earlier years he was part of the European
 +C64 cracking scene. He is an active participant both on the #c-64 IRC channel,
 +and in the comp.emulators.cbm and comp.sys.cbm newsgroups. Recently he took his
 +group "Triangle 3532" to the World Wide Web. When he isn't busy playing Lode
 +Runner on his C64 he is available for questions and/or general comments at the
 +following Internet address: kwed@pip.dknet.dk
 +
 +
 +
 +:::::::::::d:i:s:C=:o:v:e:r:y:::::::::::::::::i:s:s:u:e::3::::::::::::::::::::
 +/S05::$df00:::::::::::::::::::S O F T W A R E:::::::::::::::::::::::::::::::::
 +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 +
 +
 + A possibility to be explored : Real Time Video with the Ram Expansion Unit
 +
 +                    by Nate Dannenberg (Natedac@dfw.net)
 +
 +
 +A few weeks ago, there was a discussion on the comp.sys.cbm usenet newsgroup
 +concerning the viability of using the Ram Expansion Unit as a medium for
 +displaying real-time video animation on the C64 or C128.  I thought about
 +the possibility and came to a few conclusions.  The following text is how
 +I would undertake such a project.  Along the way, I shall illustrate some
 +previous "reu-animation" efforts and how the peculiar qualities of the REU
 +allowed such efforts to be accomplished.
 +--
 +
 +While I've never actually done video, Commodore did it at least twice.
 +
 +On the 1750 and 1764 Test/Demo disks there is a "Pound" demo and a "Globe" 
 +demo.  These two are full motion displays using your REU.  The "Pound" 
 +demo is a 3-dimensional # sign transforming in and out, the "Globe" is a
 +full rotating Earth/globe. 
 +
 +The controlling program for these is written in BASIC, with a small ML
 +program to decompress the graphic data that's stored on the disk, as it's
 +loaded into the REU.
 +
 +The REU has a transfer rate of about 1,022,000 bytes per second.  Since a
 +single video frame is 1/60 of a second, that gives you 16,666 clock cycles
 +per video frame (including video sync time).
 +
 +Chances are good you will probably want to only display about 15 frames a
 +second, which is the MPC-1 specification for PC full motion video playing
 +from a CD-ROM disc.
 +
 +With simple code, you can get about a 7.7Khz sample rate for the audio, by
 +playing one sample byte every other raster line, and maintain a smooth 60
 +FPS video transfer rate, should you want to go this high. 
 +
 +All you have to worry about is making sure you start an animation frame
 +transfer at the top of the intended video refresh, raster line 0.  You do
 +this with a simple wait loop:
 +
 +loop BIT $D012
 +     BMI loop
 +
 +As soon as bit 7 of $D012 goes low, the BMI will fail, signalling raster
 +line 0 on a new frame.
 +
 +The VIC chip steals 43 cycles from the CPU (and any REU transfer in
 +progress) on the first of every 8 raster lines.  The line where this
 +occurs now only has about 21 cycles free instead of the usual 64, this is
 +called a "bad" line in demospeak.
 +
 +You want your audio routines to use the odd lines, to stay out of the way
 +of the bad lines that occur every 8 lines.  The video routines and any
 +additional overhead can be used after the audio routine has done it's job
 +on it's line. 
 +
 +An algorithm like this might do the job:
 +
 +0 bad line, start audio REU xfer from last video refresh (see below)
 +1 Play 1 sample of audio data and run animation copier routine
 +2 ::::
 +3 Play 1 sample and run animation copier
 +4 ::::
 +5 Play 1 sample and run animation copier
 +6 ::::
 +7 Play 1 sample, set REU to grab 2 more audio bytes
 +8 bad line, start the audio REU xfer (should take 8-10 cycles)
 +9 Play 1 sample and run animation copier
 +10 ::::
 +11 Play 1 sample and run animation copier
 +12 ::::
 +13 Play 1 sample and run animation copier
 +14 ::::
 +15 Play 1 sample, set REU to grab two more audio bytes
 +16 bad line, start the audio REU xfer (8-10 cycles)
 +17 Play 1 sample of audio data
 +:
 +
 +You use a 2-byte transfer buffer for the digi audio data, to cut REU
 +overhead to a minimum, and to maximize the usage of those bad lines.
 +Remember that packed RAW data, as stored in a file, takes 1 byte for 2
 +samples.  So we're really transferring 4 samples here..
 +
 +Basically on every badline you simply tell the REU to start the 2 byte
 +transfer that was set up on the previous line.  In the case of line 0 of
 +the very first frame when starting the code, simply set up everything
 +needed, including the first 2 byte audio pointer, which will be used by
 +the REU at the end of line 0 to copy those 2 bytes..
 +
 +This only takes 6 cycles to activate, plus 2 cycles for the dma copy. You
 +have 11 cycles left, which may or may not be useful.  Just use four NOPs
 +and a BIT, to waste this time out to the next line.
 +
 +Play 1 sample of audio data on every odd line, this takes only 6 cycles if
 +the data from the REU was copied to Zero Page. 
 +
 +You have the remainder of the this rasterline and all of the next to run
 +your animation copier, a total of about 120 cycles.  You should be able to
 +squeeze in about 80 or so bytes into this space (80 bytes plus about 40
 +cycles of REU overhead is about 120 cycles).
 +
 +The REU can be programmed to remember where it left off after a transfer,
 +making subsequent contiguous transfers painless. It takes about 40 cycles
 +to set up and execute the first transfer (plus the actual copy time), and
 +then only 6 cycles to repeat the transfer (plus transfer time of course),
 +by using LDA #imm:STA $DF01 , where #imm is the value that tells the REU
 +to start, I forget offhand, something like #$95 I think... 
 +
 +This means that you might only be able to copy 80 or so bytes the first
 +time after an audio data copy (the first line following a bad line), but
 +you can transfer another 80-byte block just by using only 6 cycles to
 +re-execute the copy.
 +
 +Use another 6 cycles to adjust the size of the transfer if you want more
 +to be transferred this time, LDA #imm : STA $xfer_size_reg where #imm is
 +your new size and xfer_size_reg is the REU register for the low byte of
 +the transfer length..
 +
 +In this way you use 12 cycles to start a new size of transfer, and are
 +able to copy around 108 bytes, instead of just 80.
 +
 +On every raster line that'S just before a badline, you play the last
 +sample in the buffer, and use the rest of the line to set up the REU to
 +transfer another 2 bytes of audio data into your audio buffer.  This
 +should only take about 40 cycles or so, plus whatever time is needed to
 +update your audio data pointers. 
 +
 +To keep your timing easy, you should definitely keep this line down to
 +less than 64 cycles.  You can push it into the next (bad) line, but then
 +you gotta make sure the REU has completed the 2 byte transfer before the
 +VIC starts the line following the bad line, and you only have 21 cycles on
 +that bad line in which to do it. 
 +
 +Use as much raster time as you can for the REU copier code, since the
 +audio code is so simple and requires comparatively little CPU time.
 +
 +The REU is predictable; you will always know precisely how many cycles a
 +transfer will take.  However, you may not always know how much time your
 +own code will take, so you may need a simple wait loop like this at the
 +ends of certain raster lines, to wait for the next raster line: 
 +
 +     LDA $D011
 +loop CMP $D011
 +     BEQ loop
 +
 +This takes 11 cycles, plus 7 each time it loops.
 +
 +Needless to say, you need to know a little about synchronizing all of this
 +to the video display and the raster lines. 
 +
 +Location $D011 in the VIC is the low byte of the raster counter.  Reading
 +this register will tell you what raster line the VIC is on at any given
 +moment.
 +
 +Remember that an NTSC TV has 525 lines, which consist of two 262 line
 +fields, often called "even" and "odd" fields.  In a TV displaying a normal
 +broadcast signal, One set of fields is normally positioned half a raster
 +line below the other, resulting in true 525 line interlaced display at a
 +30Hz refresh rate.
 +
 +The VIC chip gets around this by displaying the exact same data in both
 +fields, and by placing both fields on  the exact same position on screen,
 +instead of moving one down half a line.  The result is the "normal" 262
 +line screen with a 60Hz refresh rate.
 +
 +Synchronizing to a particular raster line is a simple matter of: 
 +
 +     LDA #your_raster_line
 +loop CMP $D011
 +     BNE loop
 +
 +This type of wait loop takes 9 cycles for the first run, plus 5 cycles
 +each time it loops.  
 +
 +When you start a new frame update/copy, you need to synchronize your
 +routine to start on raster line 0.  You can do this by watching the high
 +bit of the raster counter:
 +
 +loop  BIT $D012
 +      BMI loop
 +
 +This only takes 5 cycles per loop.  As soon as bit 7 of $D012 goes low
 +(0), the BMI will fail, signalling that the VIC has started an even video
 +field.  This  way you know you are at the start of the TV's video frame as
 +well as the VIC's idea of a frame.  I don7t knwo if this would really
 +matter, however. :)
 +
 +Remember that line 0 is NOT a bad line, nor are any other lines outside
 +the range 48 to 199, because there is no visible display here, only
 +border.
 +
 +On these lines outside the visible display, you have 43 cycles more on
 +every 8th line, which are normally the bad lines on the visible display.
 +They are all a full 64 cycles long like any other non-bad line elsewhere
 +on the display.
 +
 +Let's take a general routine that copies 80 bytes on every two raster
 +lines (minus the bad line and the line before that), not using the REU's
 +ability to remember where it left off.  80 bytes * 3 transfers per row is
 +240 bytes.  25 visible rows * 240 bytes yields exactly 6000 bytes.
 +
 +Well we still have those 56 rasters off screen.  That'S about 7 rows
 +tall, and we can use the same routine as we do for the on-screen rows
 +(except we have no bad lines to deal with).. 
 +
 +So 7 * 240 = 1680 bytes + 6000 from the on-screen rows = 7680 bytes.
 +
 +That'S not quiet fast enough to do 60 FPS, but you can certainly get 15
 +out of it. :)  In fact that looks to be good enough for 50 FPS.  Well we
 +can improve this! 
 +
 +Since the REU can remember where it left off, why not get it to transfer
 +80 bytes the first time on each row, and 108 bytes each of the next two
 +times (as described way up there someplace)? 
 +
 +Well, let's add it up...  80 + 108 + 108 = 296 bytes per row.  25 rows
 +times 296 bytes yields 7400 bytes on the visible screen.  We only need
 +another 600 bytes to finish our 8000 byte bitmap... 
 +
 +LeT's just use the next three rows and waste a few rasters..  296 * 3 =
 +888, add the 7400 bytes we've done on the visible screen and we get 8288
 +bytes.  Just slightly more than enough for the full screen. 
 +
 +After all this we still have another 32 rasters left, on which the audio
 +routine is still running (on every other line).  That audio routine is
 +probably only using maybe 1/20 of the total raster time. 
 +
 +Even then we could still speed this up by using some of that leftover
 +raster time, and with a little fiddling you can get 15Khz instead of
 +7.7Khz, but that'S kinda tricky and involves a lot more cycle counting. 
 +
 +Now remember, all of this audio and video data takes a LOT of ram....
 +
 +You can only get 8 animation frames into a 64K bank in the REU if you go
 +with full-size 320x200 bitmaps.  A 1750 REU only has 8 banks, that'S a
 +total of 64 animation frames.
 +
 +At 15 FPS, that'S only about 4 seconds of video..
 +
 +A 2MB REU on the other hand has 32 banks, which yields 256 frames.  At 15
 +FPS, that'S only about 17 seconds of video.
 +
 +One way to increase the video time is to use custom characters to simulate
 +an 80x100 bitmap using a text screen.  This would still be monochrome and
 +would be much lower resolution, but you would now have about 8 times
 +longer video.  That 2MB REU would now be able to handle about 140 seconds,
 +or just over two minutes.
 +
 +The advantage of that method is you would only have to copy 1K of data
 +instead of 8K, which could be done in about 5 rasterlines using the above
 +copy-and-remember method.
 +
 +And then you still have your audio track with that..  a 7.7Khz sample uses
 +7700 bytes for 2 seconds (packed 4 bit data) of sound, so a 4 second long
 +sample, will take just over 15K.   A 17 second sample would take about
 +65K.  And to match up that 140 seconds of video with 140 seconds of audio
 +would take about 537K, or about 1/4 of the 2MB REU.
 +
 +Obviously you would have to find a break-even point here, where you have
 +as much audio time as video time.  From the looks of it, video takes about
 +4 times as much data as audio, when using 1K charctermapped frames, or
 +about 32 times as much when using full 8K bitmaps.
 +
 +If you were playing the Audio data from the C64's memory, or if you had
 +one ram device to hold audio data and one to hold video, then the overhead
 +would be virtually nil.  You could probably get away with a 44 KHz sample
 +rate and 60 FPS video, depending on the code and the speed of the ram
 +device(s) in question.  Two REU's mapped at different addresses in memory
 +should in theory be enough to do it. 
 +
 +
 +
 +:::::::::::d:i:s:C=:o:v:e:r:y:::::::::::::::::i:s:s:u:e::3::::::::::::::::::::
 +/S06::$f00d:::::::::::::::::::S O F T W A R E:::::::::::::::::::::::::::::::::
 +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 +
 +
 +                          A look into 'The Fridge'
 +
 +                     by Stephen L. Judd  (sjudd@nwu.edu)
 +
 +
 +[Ed. note : The following text is from The Fridge, an archive on the World
 + Wide Web dedicated to the preservation of useful routines and algorithms.
 + The Fridge (http://stratus.esam.nwu.edu/judd/fridge) is authored and
 + maintained by our technical editor, Mr. Stephen L. Judd.  All contributions
 + to The Fridge should be sent to him at sjudd@nwu.edu]
 +
 +
 +Sample descriptions
 +-------------------
 +
 +     * ascii2bin.doc - A description of an ASCII to binary number converter.
 +
 +     * ascii32.s     - A routine to convert a 32 bit number to ASCII and print
 +                       it to the screen.
 + 
 +     * rand1.s       - A simple pseudo-random number generator from dim4.
 +                       Not that great of a random sequence, but fine for
 +                       simple sequences.
 +
 +     * bitchin.doc   - "A totally bitchin' circle algorithm"
 +
 +--
 +ascii2bin.doc
 + 
 +The idea here is pretty simple.  Numbers are read in left to right, and
 +each time a number is read in, the total is multiplied by ten and the
 +digit is added in:
 +
 +        total=0
 +        digit=0
 +:loop   total= total*10
 +        total= total + digit
 +        read digit (and convert from ASCII to integer)
 +        if not EOF then goto :loop
 +
 +There are two ways to multiply by ten.  The first way is to use a general
 +multiplication method.  The second is to realize that 10 = 8+2, thus
 +x*10 = x*8 + x*2 = x*2*(1+4), so with a few shifts, a temporary location, and
 +an addition, multiplying by ten can be done very quickly.
 +
 +Example: read in the number 1653
 +
 +        total=0
 +        digit=0
 +
 +1st read: digit=1
 +        total= total*10 => total=0
 +        total= total+digit => total=1
 +
 +2nd read: digit=6
 +        total= total*10 => total=10
 +        total= total+digit => total=16
 +
 +3rd read: digit=5
 +        total= total*10 => total=160
 +        total= total+digit => total=165
 +
 +4th read: digit=3
 +        total= total*10 => total=1650
 +        total= total+digit => total=1653
 +
 +Voila!
 +
 +SLJ 10/96
 +--
 +
 +ascii32.s
 +*-------------------------------
 +*
 +* 32 bit -> ASCII conversion
 +*
 +* Take 2 -- Divide by 10 manually; remainder is coefficient
 +* of successive powers of 10
 +*
 +* Number to convert -> faq2..faq2+3 (lo..hi)
 +*
 +* SLJ 8/28/96
 +
 +          ORG $1300
 +
 +FAQ2      EQU $6A
 +TEMP      EQU $FE
 +
 +CHROUT    EQU $FFD2
 +
 +          LDA #$FF
 +          STA FAQ2
 +          STA FAQ2+1
 +          STA FAQ2+2
 +          STA FAQ2+3
 +
 +          LDA #10
 +          STA FAQ2+4
 +
 +          LDY #10
 +:LOOP     STY TEMP
 +          JSR DIV32
 +          LDY TEMP
 +          CLC
 +          ADC #48
 +          STA $0400,    ;Stick it on the screen
 +          DEY
 +          BNE :LOOP
 +          RTS
 +
 +
 +*
 +* Routine to divide a 32-bit number (in faq2..faq2+3) by
 +* the 8-bit number in faq2+4.  Result -> faq2..faq2+3, remainder
 +* in A.  Numbers all go lo..hi
 +*
 +
 +DIV32     LDA #00
 +          LDY #$20
 +:LOOP     ASL FAQ2
 +          ROL FAQ2+1
 +          ROL FAQ2+2
 +          ROL FAQ2+3
 +          ROL
 +          CMP FAQ2+4
 +          BCC :DIV2
 +          SBC FAQ2+4
 +          INC FAQ2
 +:DIV2     DEY
 +          BNE :LOOP
 +          RTS
 +--
 +
 +rand1.s
 +*-------------------------------
 +*
 +* GETRAND
 +*
 +* Generate a somewhat random repeating sequence.  I use
 +* a typical linear congruential algorithm
 +*      I(n+1) = (I(n)*a + c) mod m
 +* with m=65536, a=5, and c=13841 ($3611).  c was chosen
 +* to be a prime number near (1/2 - 1/6 sqrt(3))*m.
 +*
 +* Note that in general the higher bits are "more random"
 +* than the lower bits, so for instance in this program
 +* since only small integers (0..15, 0..39, etc.) are desired,
 +* they should be taken from the high byte RANDOM+1, which
 +* is returned in A.
 +*
 +GETRAND
 +         LDA RANDOM+1
 +         STA TEMP1
 +         LDA RANDOM
 +         ASL
 +         ROL TEMP1
 +         ASL
 +         ROL TEMP1
 +* ASL
 +* ROL TEMP1
 +* ASL
 +* ROL TEMP1
 +         CLC
 +         ADC RANDOM
 +         PHA
 +         LDA TEMP1
 +         ADC RANDOM+1
 +         STA RANDOM+1
 +         PLA
 +         ADC #$11
 +         STA RANDOM
 +         LDA RANDOM+1
 +         ADC #$36
 +         STA RANDOM+1
 +         RTS
 +--
 +
 +bitchin.doc
 +
 +                    A totally bitchin' circle algorithm
 +
 +Last revised: 2/20/97 SLJ
 +
 +With a revision!  The old algorithm ignored one small detail -- the plot8
 +8-fold plotter, which can be a real pain!  One thing to do is to make the
 +algorithm draw a quarter of a circle instead of an eighth, and the
 +way to do that is to attempt to reverse the procedure that drew the
 +first eighth of the circle.
 +
 +BLARG does exactly this; in the process, I also experimented with how the
 +order of statements below makes a difference in the way the circles
 +look.  So the algorithm below is now the best version I know of, i.e.
 +makes the most beautiful circles at all radii.
 +
 +This is the entire algorithm:
 +
 +        Y = Radius
 +        X = 0
 +        A = Radius/2
 +:loop
 +        Plot4(x,y)      ;Could just use Plot8
 +        X = X + 1
 +        A = A - X
 +        if A<0 then A=A+Y : Y=Y-1
 +        if X < Y then :loop
 +
 +; Now more or less reverse the above to get the other eighth
 +
 +        A = -R/2 - 1
 +:loop2
 +        Plot4(x,y)
 +        A = A + Y
 +        Y = Y - 1
 +        if A<0 then X=X+1:A=A-X
 +        if Y>=0 then :loop2
 +
 +Neat!
 +
 +The other possibility is to use the first half of this algorithm with
 +an 8-fold symmetric plot, and be sure to plot the last point X=Y.
 +
 +See C=Hacking Issue #9 for more details, but note that A=R/2 above, which
 +will make the circle correct for small R (it just rounds numbers).
 +
 +--
 +These and other useful bits of information can be obtained through Mr. Judd's
 +web page, - The Fridge -, at http://stratus.esam.nwu.edu/judd/fridge
 +
 +
 +
 +:::::::::::d:i:s:C=:o:v:e:r:y:::::::::::::::::i:s:s:u:e::3::::::::::::::::::::
 +/S07::0100h:::::::::::::::::::S O F T W A R E:::::::::::::::::::::::::::::::::
 +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 +
 +  
 +               C-128 CP/M, trailblazer in a jungle of formats.
 + 
 +                                    By
 + 
 +                               Mike Gordillo
 + 
 + 
 +The microcomputer world was once awash in an estimated 100 different major
 +operating systems with over 2000 proprietary disk format-types.  The numbers
 +are much less intimidating today, but with the resurgence of older systems
 +amongst the public (IMHO), the need to extract information from an obscure
 +disk format may become very real to the hobbyist.  Your C-128 and its
 +drive peripherals are extremely flexible when coupled to the right software.
 +When running CP/M, your C-128 is at its best in its role as an inter-platform
 +intermediary.  This article will attempt to deliniate what your C-128, under
 +CP/M, can do for you in this regard.
 +--
 + 
 +The original C-128 CP/M BIOS directly supports six 5.25" CP/M MFM (Modified
 +Frequency Modulation) and two 5.25" CBM GCR (Group Coded Recording)
 +format-types.  They are as follows:
 + 
 +      Epson QX10   (MFM) - CP/M Z80 DS/DD
 +      Epson Euro   (MFM) - CP/M Z80 DS/DD
 +      IBM-86       (MFM) - CP/M 8086 DS/DD
 +      Kaypro II    (MFM) - CP/M Z80 SS/DD
 +      Kaypro IV    (MFM) - CP/M Z80 DS/DD
 +      Osborne      (MFM) - CP/M Z80 SS/DD
 +      C-128 DS/DD  (GCR) - The "Default" C-128 CP/M format-type.
 +      C-64  SS/DD  (GCR) - C-64 CP/M (Z80 Cartridge) SS/DD
 + 
 +   Note: The 1581 is "officially" supported in the 28 MAY 87 version of
 +         C-128 CP/M 3.0+.  The official 1581 format-type is MFM DS/DD.
 +         (SS = Single Sided, DS = Double Sided, DD = Double Density)
 + 
 +MFM disks usually have the same number of sectors on each track while GCR
 +disks have a variable number of sectors for different ranges of tracks.
 +Commodore-DOS-style GCR is the "default" format-type for C-128 CP/M
 +because this allows "Joe User" to easily boot up CP/M from a 1571 or even
 +a 1541 (slow!) drive.  (Fortunately, when Commodore finalized the 28 May 87
 +version of C-128 CP/M, they not only provided a format-type for use with the
 +1581 but added a FORMAT.COM that could create a 1581 3.5" C-128 CP/M bootable
 +system disk.)
 + 
 +What can you do with these format-types?
 + 
 +Taking advantage of what CP/M provides is as simple as inserting a diskette.
 +For example, let's say I have some files on my Kaypro which I need to use on
 +C-128 CP/M.  All I have to do is put the Kaypro disk in my trusty 1571 and
 +voila, I can use it and the files within as I please with no hassles.  This
 +is no small point of trivia.  The message here is that you can use data on
 +these "alien" format-types as if the data were sitting on the "default"
 +C-128 CP/M disk.
 + 
 +What about copying them over to C-128 CP/M disks?
 + 
 +No problem!  The transfer process is as easy as using an off-the-shelf file
 +copier because as far as CP/M is concerned, the "alien" and "default" (native)
 +format-types are one in the same.  This degree of transparency is due largely
 +to the internal disk format table which exists within the computer's memory
 +as part of the CP/M BIOS (Basic Input/Output System).  This arrangement
 +constitutes better support and flexibility over the rigid Commodore DOS system
 +when it comes to juggling different format-types.
 + 
 +What happens if I run across a format-type that is not directly supported by
 +C-128 CP/M?
 + 
 +Flexibility to the rescue!  The "built-in" drive table is modifiable (both in
 +memory or on the system disk).  If you need to access other CP/M format-types,
 +the solution may be as easy as installing the parameters that match the disks
 +in question.  A good example of a utility that does this is the UNIDRIVE
 +utility by Frank Prindle.  It reconfigures the drive table, allowing up
 +to ten different 5.25 MFM format-types at any one time from an overall
 +selection of twenty-four.  Because of the drive table, UNIDRIVE is a simple
 +elegant program that can make these changes without sacrificing any TPA
 +(Transient Program Area) memory.  The undisputed king of format "jugglers" and
 +nowhere near as simple is the JUGGLER utility by Miklos Garamszeghy.  This
 +program can read and write and format over ONE HUNDRED THIRTY different
 +format-types, mostly 5.25" MFM (with 1571) but also 3.5" MFM (with 1581) based
 +disks.  This includes the popular space extending, speedy alternative formats
 +for C-128 CP/M, namely Maxi 1571/1581 and MG 1581.  A demo version of the
 +JUGGLER utility is publically available.  It does not have as many features
 +as the full version, you can only access twenty-two format-types and modifying
 +the "built-in" drive table is out of the question.  This would be inconvenient
 +if the full version were hard to find as it once was.  This has changed as
 +its author as put up the full version of Juggler on the World Wide Web at
 +http://www.herne.com/cpm.htm
 + 
 +What about MSDOS MFM disks, can I use them as well?
 + 
 +Yes you can!  I know of at least three separate utilities that will allow
 +communication between C-128 CP/M and MSDOS diskettes.  First on the list
 +is the RDMS 2.33 utility.  This is an old program designed to read MSDOS
 +diskettes, and that's all it does.  It will read from MSDOS into CP/M but
 +will not write back to MSDOS.  Frank Prindle ported over this program
 +(for the 1571 drive) and he would have probably added a "write MSDOS" option
 +if someone else hadn't beaten him to the punchline.  The TRANSFER 128 v1.2c
 +utility (ported over by Gilly Cabral from David Koski's original TRANSFER
 +util.) came soon after Prindle's rendition of RDMS 2.33.  In fact, the routines
 +used to communicate with the 1571 are based on Prindle's work.  TRANSFER 128,
 +however, goes way beyond RDMS 2.33.  Not only does it read and write to MSDOS
 +disks but it also provides a suprisingly high level of sophisticated access to
 +the internal workings of MSDOS disks.  For example, it can display the MSDOS
 +FAT (File Allocation Table) and reconstruct it, if needed, using a backup FAT
 +as a template.  TRANSFER 128 supports single and double sided 5.25" format
 +types with eight or nine sectors per track.  It places no limits on the size
 +of the data it can transfer.  The only limitation is the free space left
 +on the destination diskette.  This is a huge advantage over the first "native"
 +mode MSDOS to CBM DOS programs which use internal memory buffering.  For many
 +years, TRANSFER 128 was my only standby for large files.  When better utilities
 +came out for the "native" modes, I still found TRANSFER 128 to be my choice.
 +Why?  Because of the excellent Ram Expansion support under the CP/M BIOS.  CP/M
 +thinks the Ram Expansion Unit is truly a real drive.  TRANSFER 128 (and other
 +CP/M programs) does not have to worry about steering clear of "interface pages"
 +and silly stuff like that when dealing with the additional Ram.  Eventually,
 +people wrote transfer utilities that did work with CBM RAMDOS, for example.
 +Too late, my heart was set on TRANSFER 128.  It's been a good companion and
 +since it comes bundled with its Turbo Pascal source, I can always modify it
 +in case of trouble.  In fact, I had to do just that when I set up several
 +BIOS/BDOS/CCP enhancements on my system.  (But that's another story :)))
 +The one tiny snag with TRANSFER 128, however, is that it will format the
 +various MSDOS format-types perfectly as far as MSDOS itself is concerned,
 +but "native" mode transfer programs do not recognize the disks which TRANSFER
 +128 has formatted.  I am at a loss to explain this, so I won't ;), but its safe
 +to say i'll give TRANSFER 128 the benefit of the doubt anytime!
 + 
 +What about 3.5" MSDOS format-types using my 1581?
 + 
 +Ah, yes, I've neglected to mention what may be the best "transfer" utility
 +available for the C-128.  It may be too sophisticated for young viewers so
 +this section of this article will be rated PG-13 :).
 + 
 +Well Well Well !??!?  Don't keep us in suspense!
 + 
 +Not to worry!  The utility i'm harping about is called MSDOSEM (by Nichita
 +Sandru).  It doesn't just give you a temporary transfer "window of
 +opportunity", it makes CP/M think of MSDOS disks as native CP/M disks and
 +it provides (get this) *full* subdirectory support!!!
 + 
 +This is similar to the transparent "juggling" of CP/M format-types, yes?
 + 
 +Yes, except that CP/M disks carry the same directory structure no matter how
 +their format-type is arranged.  In order to support the MSDOS directory
 +structure, MSDOSEM creates a separate buffer area for internal conversions
 +between CP/M and MSDOS logical constructs.  The actual physical nature of the
 +MSDOS format-types, however, is handled (once again) with a modified CP/M drive
 +table.  MSDOSEM has no problem with 5.25" (1571) or 3.5" (1581) double density
 +MSDOS format-types.  Again, as described earlier in this article, transparency
 +means that you can play with the "alien" disk as if it were a "default" one.
 +Any copy utility you have sitting around can now access MSDOS diskettes with
 +MSDOSEM as the go-between.  This is the ultimate in MSDOS to C-128 transferring
 +because you (essentially) do not have to transfer anything anymore! The "stuff"
 +on your MSDOS disks is no longer anathema to CP/M, even though it may be to
 +you :).
 + 
 +What about support for regular Commodore DOS (GCR) disks?
 + 
 +In reality, the original "default" C-128 CP/M format-type is as Commodore
 +DOSian GCRish as anything Commodore has done for the "native" modes.  I take
 +advantage of this when backing up my CP/M disks, either with FastHack'em
 +(or any GCR copier) in C-128 mode or IMAGE.COM under CP/M itself.  These 
 +programs allow us to manipulate Commodore GCR on a gross level.  For a more
 +refined manipulation of files "stuck" in regular CBM GCR disks, I generally
 +use the RDCBM 2.1 utility by Rob Tillotson and Turbo Penguin Software.  This
 +program can read files from 1541 or 1571 "native" Commodore GCR disks and spit
 +them out as straight binaries (eg., no translation) or it can convert files from
 + 
 +PETSCII to ASCII.  Like RDMS 2.33, RDCBM 2.1 does not write back to the disks
 +it so aptly read and it does not read anything on the 1581.  These quirks are
 +*highly irritating* considering its a pretty good program otherwise.  Good
 +enough to provide limited support for files under the GEOS file structure.
 +Fortunately, I surmise that I have not run into a more recent version of
 +RDCBM to evaluate.  I say this because the source listing of this program
 +contains "Hooks and Crannies" pointing to the author's efforts to implement
 +a "write-back" option and 1581 support.
 + 
 +You mean I cannot transfer material from my CP/M disks to my regular 15xx
 +disks???
 + 
 +No I don't.  There exist several "native" C-64 and C-128 utilities which will
 +do this.  The C-128 "native" mode version of the Big Blue Reader program has
 +this ability.  Utilities like Supersweep and Crosslink can also port your
 +files to CBM DOS 15xx disks, albeit these two programs set limitations on
 +the size of the files in question.
 + 
 +That's nice, but i'm a C-128 CP/M'er through and through!
 + 
 +Ok, you beat it out of me.  There *is* a way to "save" files to a regular
 +CBM DOS diskette from within C-128 CP/M.  You first use the C128LOAD utility
 +by David Bratton to load a file into Bank 1 of the CP/M memory map.  Next, you
 +hit CTRL-ENTER (on the numeric keypad, do not press RETURN) and this will put
 +you in C-128 "native" mode.  Finally, you use the built in C-128 ML monitor
 +to save to disk the memory block (Bank 1) where the program was loaded.
 +Please note the following example;
 + 
 + 
 +     A> C128LOAD DIEHARD.C64
 + 
 +        Program loaded - from 2000 to 8192  <-- Last byte-address
 + 
 +     --When the A> prompt reappears, press the CONTROL and ENTER keys
 +       simultaneously.  (The ENTER key is on the NUMERIC KEYPAD.)
 + 
 +       <The C-128 will now boot Basic 7.0 -- C-128 "Native" mode>             
 + 
 +     READY.
 +     MONITOR (activate the C-128 ML monitor & insert CBM DOS disk into drive 8)
 + 
 +     S "DIEHARD.C64",8,2000,8193  <-- Always add +1 to the last byte-address.
 +                            ----
 + 
 +In effect, we have just moved the file DIEHARD.C64 from C-128 CP/M to a CBM
 +DOS disk (remember to use the bank address of 1 when saving).  While this
 +method places an absolute restriction on the file size of what you can "save",
 +it means that files can be "saved" to any drive supported by the C-128.  It
 +is possible to save only one file per iteration of this cycle.  In order to
 +save many files, you will have to reboot CP/M and go through these steps
 +for each file involved.  This is a roundabout way to "write-back" to CBM DOS
 +and it certainly isn't as contained within CP/M as most of us would like.
 + 
 +How do the exciting CMD FD-2000 and FD-4000 drives factor into all this?
 + 
 +They are "covered" insofar the programs that support the 1581 also support
 +them, namely the JUGGLER, MSDOSEM, and C128LOAD utilities, and also the 28 MAY
 +87 Version of CP/M 3.0+ on the C-128.  The FD series drives do a pretty good
 +job at emulating the 1581 and should present no problems under C-128 CP/M.  The
 +1581 is limited to around 800 kilobytes and this may not be adequate for you.
 +As far as accessing the high capacity disks within the scope of the FD-drives,
 +the key issue is software (again).  For example, there is nothing in terms of
 +hardware that says we cannot use these drives to play with MSDOS 2.88 megabyte
 +formats (ala FD-4000) or create 2.88+ megabyte CP/M formats of our own design.
 +I do not know if FD-based software exists to allow this under C-128 CP/M.
 + 
 +How do I use the strengths of some programs to get around the limitations
 +of other programs?
 + 
 +I take it you are asking this because of the software gap in linking CP/M
 +to CBM DOS (at least from the CP/M side of the equation)?  Well, we have
 +a trump card in our sleeves in the form of the MSDOS format-types.  These
 +tend to be the lowest common denominator for information inter-change in
 +the entire microcomputer world.  For example, if the JUGGLER utility lacks
 +the ability to communicate with a particular brand of CP/M format-type (a
 +rare event indeed), chances are the system (with the funny format-type) has
 +some means to get information from its disks onto MSDOS disks.  Obviously,
 +I can simply use the MSDOS format-types as a bridge "over troubled sectors" :)
 +and not worry anymore.  The same holds true for CP/M to CBM DOS.  If it becomes
 +too inconvenient to save with C128LOAD and the built in C-128 mode monitor,
 +I simply pop up TRANSFER 128 or MSDOSEM and let them put things into MSDOS
 +disks for later retrieval by CBM DOS-able "native" mode programs such as Big
 +Blue Reader or Little Red Reader/Writer 128.  Mind you, this has its own
 +share of inconveniences, but it does present an attractive alternative to
 +some people.
 + 
 +What if I don't have a C-128 but I need to put files on a C-128 CP/M disk
 +or some other type of CP/M disk?
 + 
 +Hmmm...that's a tad outside the scope of this article but I can see a situation
 +arising from this where a C-128 CP/M user might miss out on some software.  If
 +you have a machine that runs MSDOS, you can avoid that situation.  There is a
 +MSDOS to CP/M utility called 22DISK140 which supports 140 different CP/M MFM
 +formats in its demo version and over 400 (!) in the full version.  The key
 +thing here is that it supports the Commodore 1581 CP/M MFM format.  Any files
 +you put in there are going to be useful to a C-128 CP/M user as long as he/she
 +has a 1581 and the 28 MAY 87 Version of CP/M 3.0+ on the C-128 (or a suitable
 +patch which supports the Commodore 1581 CP/M MFM format).
 + 
 +You've shown me the software, but where do I get it?
 + 
 +All the C-128 CP/M utilities I mentioned are available on Internet FTP sites
 +such as  ccnga.uwaterloo.ca  in directory  /pub/cbm/os/cpm.  I have also seen
 +some of them in the GEnie and Delphi information networks.  The 22DISK140
 +utility is available on the Internet FTP site  oak.oakland.edu  in directory
 +/pub/msdos/diskutil
 + 
 +Final thoughts...
 + 
 +Software Software Software... This article is by no means the final word
 +on what you can or can't "port" out of C-128 CP/M.  For example, Apple CP/M
 +GCR disks are completely isolated from C-128 CP/M, 22DISK140 or anything out
 +there besides an Apple drive!  However, some clever magician among you may
 +set to master the Apple GCR format using a Commodore GCR drive.  If you do it,
 +drop me a line, good CP/M software is usually a thing of beauty.  As I hinted
 +the last time we met, CP/M's strength lies in its software, (: and in its users
 +does its software lie. :)
 + 
 +-------
 +Mike Gordillo is an expert in CP/M and Z80 programming as well as
 +a devout Commodore fanatic.  He may be reached on the Internet as
 +s0621126@dominic.barry.edu for general comments or questions.
 +
 +
 +
 +:::::::::::d:i:s:C=:o:v:e:r:y:::::::::::::::::i:s:s:u:e::3::::::::::::::::::::
 +\H01::::::::::::::::::::::::::H:A:R:D:W:A:R:E:::::::::::::::::::::::::::::::::
 +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 +
 +
 +                     The X10 PowerHouse, What is it?
 +
 +                     by Dan Barber (xy3951@epix.net)
 +
 +
 +Well to put simply, it is a system that allows you to control up to 256 lights
 +and or appliances in your house automatically, or from a distance.
 +
 +The most basic part of the system is the modules.  They are small boxes that
 +plug into a plain 2 or 3 pin electrical outlet (depending on the module you
 +have purchased) and the device you wish to control is plugged into the module.
 +Then you can get numerous remote controls that send signals to a receiver
 +that then sends the signals over your wiring to the individual modules,
 +which then turn on, off, or dim (if you are using a lamp module).
 +
 +As I have said, you can get remote controls to control the appliances,
 +but why not just control them with the normal switch and save yourself some
 +money?  Because a computer interface can also be purchased for the system,
 +and this interface can be programmed with a Commodore 64/128!  Or if you are
 +one of the unfortunate that don't own a Commodore, then you can use a MS-DOS,
 +Apple Macintosh, or Apple IIe/IIc.
 +
 +The CP290 Home Control Interface is 5 inches wide by 7 long, and 1 1/2 deep.
 +The top face is covered by rocker keys which allow you to control 8 modules
 +from one HOUSECODE which is adjustable.  The modules have two dials on them,
 +the first is the letters A-O.  This is called the the HOUSECODE.  The second
 +dial on the modules is the number 1-15, this is the UNITCODE.  So, your
 +first module would probably be name d A1 and the second A2 and so on, for
 +a total of 256 modules.  
 +
 +The interface can handle control of all 256 modules but if you are using
 +the Commodore 64/128, you can only program 95 using the included point-and
 +-click GUI (Graphic User Interface) program.   If you have more than 95
 +modules you will have to use the included BASIC extension program that is
 +included on the disk.  Then you can create your own simple program to control
 +all of the modules if need be.  But I can't personally imagine anyone using
 +over 95 modules, unless you have a mansion.  :)
 +
 +The program that sets up the interface is very simple to use.  With the
 +power off you connect the cable to the userport and the interface turn it
 +on and load the program.  You set the time and the HOUSECODE you want the
 +rocker keys to respond to and then the screen shows the different rooms
 +you can "install" modules in.  There are 9 "virtual" rooms you can place and
 +program modules, though it does not make any difference what room you have
 +the module in as long as the dials on it are set properly.  Programs for use
 +with other computer systems have differences, some you type in the name of
 +the room instead of using the "virtual" rooms.  And some can control all 256
 +modules with the supplied software, where as other systems must write there
 +own software if they need to control all 256 modules.
 +
 +Once you pick a room (by using the cursor keys or the joystick to move a
 +pointer and clicking) you are presented with 11 "tabs" where you can "place"
 +modules.  When you select one you are presented with choices of icons
 +(graphics) that look like appliances and lamps.  When you chose one it is
 +stored in the interface as well as the HOUSECODE and UNITCODE.  Note, it does
 +not make any difference what icon you select to go along with a module, it
 +is just to remind you of what the device is.  So you could have a toaster
 +icon (graphic) actually controlling a coffee pot, the only thing that really 
 +matters is the dials on the modules and the interface codes are the same.
 +
 +Once you have the rooms set up with icons you like, you go to the operate
 +mode.  This is where you program the interface to come on or off at specific
 +times of days.  You can set it to go on NOW, which turns it on immediately.
 +OFF immediately, ON TODAY, OFF TODAY, ON/OFF SPECIFIC DAYS, ON/OFF EVERYDAY.
 +And this is the beauty of the system, you can have your house have a "lived-in"
 +look even though it isn't.  With SPECIFIC DAYS and EVERYDAY modes, you can set
 +a security mode.  This means that if you set something to come on at 5:00pm,
 +it would come on between 5:00pm and 5:30pm.  It just picks a random time and
 +ON (or OFF) it goes.  The interface is very versatile and you can enter
 +numerous ON and OFF times, so for instance, if you have kids that forget to
 +turn off the lights you can have them go off-only at designated times, the
 +same goes for ON.  Now this is why this system shines over others, when you
 +aredone programming you unplug the interface from the computer!  It does
 +not tie the computer up.  You only use the computer to program the interface.
 +Afterwards it runs completely on its own.
 +
 +The interface will handle up to 128 timed events, which means if you were
 +controlling a Christmas light setup, and you were changing the lights every
 +minute (the closest span that you can program a timed event) you could have
 +over 2 hours of automatic control.  I should mention that it does not make
 +any difference how many modules have been setup to go on or off for one
 +particular time (up to 16 modules).  It would still be considered one time
 +event (ex. modules A1, A4, A7, and A15 programmed to go on at 70% brightness
 +on Mondays, Wednesdays, and Fridays at 7:30 p.m. is just one event).  Also, 
 +you can only set brightness for a lamp module with the interface hooked up
 +to the computer to send the commands manually, or as a pre-programmed event.
 +So, if you just hit one of the rocker keys or turn the lamp on, off, and
 +back on (the module will sense this and turn on), the lamp will just come
 +on full.
 +
 +
 +AFTER PROGRAMMING IS COMPLETE
 +And after you get the interface all programmed just the way you want it-the
 +power fails and you loose your entire program.  Well, if you have a 9 volt
 +battery installed the program would have been safe.  The battery can hold the
 +memory of the interface for 10 hours (or so).  And it is a good precaution,
 +the only problem might be to forget it is in there and after a few years,
 +the battery leaks.  But that applies to any battery-powered device.  There
 +is also the option to save the entire contents of the interface to disk.  
 +This is available as a separate program on the disk, and it saves the interface
 +data as a file to the disk.  Three saves can be on the disk at one time, and if
 +you need more just copy the disk, it is not protected.  One of the greatest
 +benefits of this feature is the ability to swap setups in and out so you can
 +have one for different times of the year.  For instance you could save your
 +Christmas light setup to disk and next year get out the same setup and save 
 +yourself a lot of time in programming.
 +
 +If you have a elaborate house setup that takes 20 minutes or more to program.
 +It is great to be able to load the settings back in a minute or so!  Another
 +good reason for having a backup is because the interface can "lock-up" and
 +you must remove the battery and unplug it to reset it.  This of course causes
 +the program to be lost so having a backup is necessary in this case, otherwise
 +you have to reprogram it.  I have had it happen once, but I was moving the
 +interface.  I think that the battery lost contact momentarily while I was
 +moving it to another room and caused a "lock-up" to occur.  But I had just
 +done a backup so nothing was lost.
 +
 +Power failures have different effects on the modules as well.  The appliance
 +module will stay in the same position (they have a latching mechanical relay
 +type switches) as it was before the outage.  Where as, the lamp modules will
 +be off after a power failure (they have a triac for dimming), no matter what
 +state the module was in before the failure.
 +
 +
 +HARDWARE
 +There are a lot of clones on the market, and they all appear to be compatible.  
 +X-10 was the first, but other places such as Radio Shack has both the interface,
 +modules, and other addons for the system.  But in the case of Radio Shack's
 +interface, it is missing a very important feature (at least in my opinion):
 +no manual rocker keys!  Other than that, I don't know of any differences
 +between the systems.
 +
 +** Just as this issue of disC=overy was going to press, I found out that
 +   X-10 manufactures all the clones themselves!  The differences are minor
 +   and limited to cosmetic changes as the example listed above.
 +
 +The equipment is long lasting (people have had the system in place for over
 +20 years).  But of course if you have a lightning strike I would not expect
 +them to survive, and don't try to put a surge suppressor on them either.  Most
 +filter the lines and will block any signals going out or coming in to the
 +attached equipment.  And a plug-in intercom system or baby monitor will
 +interfere with the signals if they happen to be sent at the same time as
 +the intercom is on.
 +
 +In short this system is MUCH easier than running cabling all over your house,
 +and much cheaper.  You can get the interface and 4 modules for around $100.
 +And if you want to control a chandler or other such lighting fixture, just
 +replace the switch with an X-10 controllable switch, and the same applies
 +for outlets.  And replacing them is very easy, and can be done in an afternoon
 +(unless you are doing an entire mansion).  Just make sure to turn off the
 +power at the breaker!!!!  Other addons for X-10 include entire alarm systems,
 +motion sensing flood lights, emergency dialer (dial for assistance when you
 +push the remote control), telephone responder (remote control your home
 +while you are away), and many other interesting products.
 +
 +There have been some interesting uses I have heard of for the X-10 system.
 +Like, magicians using it in there act, remote control lighting for underground
 +cavetours, and lighting control for chicken farms to fool the chickens into
 +laying more eggs.  And many others, this proves that is no limit to what the
 +system can do if you put your mind to it.
 +
 +
 +TECHNICAL SEPCIFICATIONS
 +The processor is in the interface is a 80C48.  And I mentioned before a maximum 
 +of 256 modules with a maximum of 128 timed events.
 +
 +The transmissions are complex and are sent twice for verification and basically
 +the signals involve short RF burst which represent digital information.  The
 +transmissions are synchronized to the zero crossing point of the AC power line.
 +The goal is to transmit as close to zero crossing point as possible, but
 +certainly within 200 microseconds of the crossing point.  A Binary 1 is
 +represented by a 1 millisecond burst of 120 kHz at the zero crossing point,
 +and Binary 0 by the absence of 120 khz.  And the instructions to the module is
 +sent with those two signals (as is all computer information).
 +  
 +The complete code transmission involves eleven cycles of the power line.  The
 +different cycles represent different commands to the module.  Such as the first
 +two cycles represent start, next four represent the House Code and the last
 +five represent either a Number Code (1 thru 16) or a Function code (ON, OFF,
 +etc).  The programming manual is reproduced below with permission and for the
 +edification of the reader.
 +--
 +
 +[Ed. Note : Portions of the technical information below require some basic
 + understanding of signal theory and electronics.]
 +
 +
 +INTRODUCTION
 +Software is required to use your computer to program the X-10 Home control
 +Interface.  The interface is packaged with software and connecting cable for
 +either IBM PC, Apple Macintosh, Apple IIe/IIc or Commodore 64/128.
 +THAT'S ALL YOU NEED.
 +
 +A utility program of Basic statements is included with the Home Control
 +Software for IBM, Apple IIe/IIc and Commodore Computers.  These Utility
 +programs let you write your own programs in Basic.
 +
 +For more advanced programming you may also need to refer to this programing
 +guide.
 +
 +This programing Guide is for advanced programmers who wish to write their
 +own software using Machine code and need information than is supplied in the
 +owner's manual which comes with the X-10 Home Control Software.
 +
 +If you do NOT intend to write your own software, don't be intimidated by
 +this programming guide- you don't need it.
 +
 +The Interface must be connected to your computer for programming but once
 +programmed it can be disconnected and will continue to send commands to the
 +X-10 Modules under time control.
 +
 +The Main functions of the Interface are summarized as follows.
 +
 +*Maintains a real time clock
 +*Stores the timed events relating to control of lights and appliances in the
 +home.
 +*Stores the graphics data required by the computer to display the details of
 +lamps and appliances installed into the house by the user.
 +*Transmits X-10 Control Signals onto existing house wiring to control lights
 +and appliances connected to the X-10 Modules.
 +
 +A 9volt Alkaline battery will provide approximately 100 hours back up for the
 +Interface clock and stored data.  When the Interface is running on battery
 +power, the L.E.D. pulses approximately once every 5 seconds.
 +
 +Up to 128 timed events + 256 ICONS (Graphical pictures of lights and
 +appliances) can be stored in the Interface.  A timer event is any number of
 +unit codes on the same Housecode programmed to go on or off at a particular
 +time at a specified brightness level on any day or days of the week.
 +(E.G. Modules A1, A4, A7 and A15 programmed to go on at 70% brightness on
 + Mondays,Wednesdays and Fridays at 7:30 P.M. is just one event and 128
 + events can be stored.)
 +
 +The Interface has 8 rocker keys to give manual control of unit codes 1 thru 8
 +onthe Base Housecode.  Base Housecode is set to "A" on power up but can be
 +changed by the software.
 +
 +PROGRAMMING
 +
 +The Interface is programmed to recognize 8 different types of instruction
 +for the computer and each instruction has an ID number between 0 and 7.  Each
 +instruction from the computer has a leading SYNC pattern of 16 x FF bytes. The
 +ID number tells the Interface what type of data to expect and a check sum is
 +maintained which is compared with the last byte of data in the instruction.
 +If the check sums agree, the Interface will acknowledge back to the computer
 +and obey the instruction.  It is suggested that if no response to an
 +instruction is received within 10 seconds, the computer should advise the
 +user of potential problem with the connections to the Interface. 
 +(E. G. the program could display a message such as "Error check Interface
 + connections.  Press Enter to continue".)
 +
 +The Interface is programmed via the 5 pin DIN socket on the back of the
 +Interface.  The pin connections are shown below.
 +
 +                      Looking at Back of Interface
 +             1
 +           2
 +          3
 +Pin  Description
 +1    -
 +2    Receive (Input)
 +3    Ground
 +4    Transmit (Output)
 +
 +The input signals from the computer (receive data input) are connected between
 +pins 3 and 2.
 +
 +The output signals to the computer (transmit data output) are connected
 +between pins 3 and 4.
 +
 +A data cable is available for IBM, Macintosh, Apple IIe, and Commodore 64/128
 +and is included with the Interface and software for these computers.
 +<Note-The Commodore cable and software must be purchased separately, it is no
 +longer sold with the interface.  To get the cable-software package you must
 +order one from X-10..>
 +
 +Voltage levels meet RS-232 specifications and the data format is RS-232 with
 +the following characteristics.
 +
 +Baud rate:  600.
 +Data bits:   8.
 +Parity:      None.
 +Stop bits:   1.
 +
 +
 +BYTE FORMAT
 +           Start                                Stop
 +            Bit  D0  D1  D2  D3  D4  D5  D6  D7   Bit
 +     V+    ---     ---            ---     ---
 +           ! 0 ! 1  ! 0       1 ! 0 ! 1 ! 0 !  1
 +     V- ---     ---    -----------     ---    ---
 +
 +1011     D0 to D3
 +1010     D4 to D7
 +
 +Dec = 93
 +Hex = 5D
 +0 = Mark
 +1 = Space
 +
 +A gap of 1 Millisecond should be left between each byte of data sent.
 +
 +A start bit signifies that a string of 8 data bits will follow.  A start
 +bit is always a SPACE bit, i.e. "0" A stop bit signifies that the data is
 +finished and separates one byte from another.  A stop bit is always a MARK
 +bit, "1".
 +
 +
 +DOWNLOAD BASE HOUSECODE
 +
 +When the Interface is first powered up, the Base Housecode is set to "A".
 +To change this you must first send a leading SYNC pattern of 16 x FF bytes
 +to the interface, followed by the identifier "0" for "download base Housecode"
 +and then of data, the upper nibble of which contains the Housecode information.
 +See below.
 +
 +
 +BYTE    D7    D6    D5    D4    D3    D2    D1    D0
 +1-16    1      1                          Sync, 16 X FF
 + 17          0                          ID 0, download Base 
 +                                                      Housecode
 + 18    ---HOUSECODE------------- 0              See table 1.
 +
 +
 +
 +TABLE 1
 +
 +House   Byte 18     House   Byte 18     House   Byte 18
 +  A       60               E0          C       20
 +  D       A0               10          F       90
 +  G       50               D0          I       70
 +  J       F0               30          L       B0
 +  M       00               80          O       40
 +  P       C0 
 +
 +Base Housecode is used by the rocker keys on the Interface.  Changing the
 +Base Housecode will reset all timer events and graphics data stored in the
 +Interface, therefore before downloading a new Base Housecode to the Interface,
 +the program should warn the user of this.  (E.G. the program could display
 +"Warning changing Base Housecode will erase all program information.  Continue
 +with change yes/no".)
 +
 +After a successful download, the Interface will acknowledge by sending the
 +"ACK" message to the computer.
 +
 +
 +ACK MESSAGE
 +
 +Byte    D7    D6    D5    D3   D2   D1   D0
 +1-6      1                1    1    1  FF X 6
 +                      0    0    S  Status
 +
 +The STATUS bit is reset to "0" during power up of the Interface and is set
 +to "1" by a download of data from the computer (any data with byte 17 equal
 +to ID 0, 1, 2, or 3).  The STATUS bit is used to warn the computer that the
 +Interface has been powered down.  E.G. a STATUS bit equal to "0" could tell
 +the program to display a message such as "The Interface has been powered
 +down and contains no data.  Press Enter to continue".
 +
 +
 +DIRECT COMMAND (instant ON or OFF)
 +
 +To turn something ON or OFF or adjust the brightness level of a light
 +instantly,m it is first necessary to send a leading SYNC pattern of 16 x FF
 +bytes of data to the interface.  This is then followed by the identifier "1"
 +for "direct command" and then 4 bytes of data followed by a check sum.  The
 +check sum is the sum of bytes 18 through 21.  See below.
 +
 +
 +BYTE     D7  D6  D5  D4  D3  D2  D1  D0
 +1-16      1                 SYNC FF x 16.
 + 17                       ID1, Direct command.
 + 18           LEVEL          FUNCTION       See notes 1 and 2.
 + 19         HOUSECODE               See table 1.
 + 20        10  11  12  13  14  15  16   Bit mapped unit codes.
 + 21                       X-10 Modules.
 + 22                   CHECK SUM           Sum of bytes 18-21.
 +
 +
 +NOTE 1
 +"LEVEL" is dimmer settings for lamps.  This applies only to X-10 Lamp Modules
 +and Wall Switch Modules.  Level F Hex is full DIM and level 0 Hex if full
 +BRIGHT.  The lamps specified by bytes 20 and 21 will switch on, adjust to full
 +brightness and then DIM to level specified by the upper nibble of byte 18.
 +All codes between 0 Hex and F Hex are acceptable thus providing 16 discrete
 +light levels.
 +
 +NOTE 2
 +D3  D2  D1  D0  Function    Explanation
 +0    0        ON        Modules with house codes as specified   
 +                            by upper nibble byte 19 and unit codes as 
 +                            specified by bytes 20 and 21 will turn on.
 +
 +0    0        OFF      As above, except turn OFF.
 +
 +0    1        DIM      Lamp Modules and Wall Switch Modules addressed as 
 +                           above will turn on, adjust to full intensity and 
 +                           then DIM to the level specified by upper nibble of 
 +                           byte 18.  Appliance Modules do not respond to 
 +                           bright and dim codes.
 +
 +
 +NOTE 3
 +If the check sum is accepted, the Interface will send the ACK response to the
 +computer and will then transmit the X-10 codes onto the house wiring.  When
 +the power line transmission is complete the command is uploaded to the computer
 +(see command upload).  Also, if X-10 codes are transmitted by pressing the keys
 +on the Interface, at the end of each transmission the codes are uploaded to
 +the computer.  This allows the computer to keep track of the ON/OFF status
 +of the Modules while it is connected to the Interface.
 +
 +
 +DIRECT COMMAND EXAMPLES
 +Example 1:  Turn ON modules A1 and A4
 +Bytes:   1-16  17  18  19  20  21  22
 +Data:     FF   01  02  60  00  90  F2
 +
 +Example 2:  Turn OFF modules A1 and A4
 +Data      FF  01  03   60  00  90  F3
 +
 +Example 3:  Turn on lamp module B9 and DIM to 50%
 +Data      FF  01  75   E0  80  00  D5
 +
 +Example 4:  Turn OFF all modules with housecode A
 +Data      FF  01  03   60  FF  FF  61
 +
 +
 +COMMAND UPLOAD (Interface to Computer)
 +This follows every transmission of X-10 onto the power line either from
 +pressing the rocker keys, or from direct commands, or from timed events.
 +This enables the computer to keep track of the ON/OFF status of lights and
 +appliances.
 +
 +Byte   D7  D6  D5  D4  D3  D2  D1  D0
 +1-6                     FF X 6.
 +7                       Status.
 +8          HOUSECODE       FUNCTION     See note 4 below.
 +9        10  11  12  13  14  15  16   Bit mapped unit codes of
 +10      1                 X-10 Modules.
 +11      BASE HOUSECODE  0         Same as table 1.
 +12                 CHECK SUM            Sum of bytes 8-11.
 +
 +NOTE 4 -House code same as table 1.  Function same as note 2, except that
 +the code for DIM is UPLOADED to the computer as 0100 (4hex).
 +
 +
 +SET CLOCK (Computer To Interface)
 +To set the clock in the Interface it is first necessary to send a leading
 +SYNC pattern of 16 X FF bytes of data.  This is followed by the identifier "2"
 +for set clock and then 3 bytes of data followed by a check sum.  This check
 +sum is the sum of bytes 18 thru 20.  See below.
 +
 +Byte   D7   D6   D5   D4   D3   D2   D1   D0
 +1-16    1    1    1    1    1      1    1     SYNC 16 X FF.
 +17      0    0    0    0    0      1    0     ID2, set for clock.
 +18      0    0             MINUTES              HEX 00 to 3B (0 TO 59).
 +19      0    0    0         HOURS               HEX 00 to 17 (0 TO 23).
 +20      0   Sun  Sat  Fri  Thu Wed  Tue  Mon    Bit mapped Days.
 +21                    CHECK SUM                 Sum of bytes 18 to 20.
 +
 +SET CLOCK EXAMPLES
 +
 +EXAMPLE 1  To set clock to 9:30 a.m. on Monday.
 +BYTE  1-16   17   18   19   20   21
 +DATA   FF    02   1E   09   01   28
 +
 +EXAMPLE 2  To set clock to 7:45 p.m. on Friday.
 +BYTE  1-16   17   18   19   20   21
 +DATA   FF    02   2D   13   10   50
 +
 +
 +
 +TIMER EVENT OR GRAPHICS DATA DOWNLOAD
 +(Computer to Interface)
 +
 +To download either a timed event or graphics data you must frist send a
 +leading sync pattern of 16 X FF bytes.  The ID. (Byte 17) is 3 HEX for both
 +timer events and graphics data but D2 in Byte 19 is a "0" for timer events
 +and a "1" for graphics data.
 +
 +Timer events are stored in bytes 0 to 1023 of the 2k X 8 RAM in the interface.
 +Only bytes 20 to 27 of the downloadable message are stored.  Each event (group
 +of 8 bytes) is assigned a Start Address in the RAM in the Interface.  This
 +Star Address is specified by A0-A4 in Byte 18 and A5-A6 in Byte 19.  D0, D1,
 +and D2 in byte 18 must ALWAYS be 0, so that the Start Addresses increase in
 +multiples of 8 (0, 8, 16, .... 1016).  The computer should keep track of the
 +event Start Addresses and load new events into vacant address locations in RAM.
 +Byte 20 designates the type of timer event as shown in table 4.  Bytes 21
 +through 23 set the time and day of the event.  Bytes 24 and 25 specify which
 +Modules will be controlled and byte 26 specifies the Housecode of these
 +Modules.  Byte 27 specifies whether the Module(s) will turn ON, OFF, or
 +DIM and to what brightness level.  Byte 28 is the sum of bytes 20 to 27.
 +
 +
 +TIMER EVENT DOWNLOAD
 +BYTE   D7   D6   D5   D4   D3   D2   D1   D0
 +1-16    1    1    1    1    1    1    1    1    SYNC 16 X FF
 +17      0    0    0    0    0    0    1    1    ID3, event/graphics download.
 +18     A4   A3   A2   A1   A0    0    0    0    A0 to A6 binary coding of
 +19      x    x    x    x    x    0   A6   A5    event number.
 +20      0    0    0    0         MODE           See table 4.
 +21      0   Sun  Sat  Fri  Thu  Wed  Tue  Mon   Bit map of days.
 +22      0    0              HOUR                HEX 00 to 17 (0 to 23).
 +23      0    0    0        MINUTE               HEX 00 to 3B (0 to 59).
 +24      1    2    3    4    5    6    7    8    Bit map of unit codes.
 +25      9   10   11   12   13   14   15   16    Bit map of unit codes.
 +26         HOUSECODE        0    0    0    0    Same as table 1.
 +27          LEVEL               FUNCTION        Same as Notes 1 and 2.
 +28                   CHECKSUM                   Sum of bytes 20 to 27.
 +
 +X=DON'T CARE
 +
 +
 +
 +TABLE 4 - TIMER MODE SELECTION
 +
 +BYTE 20 lower nibble
 +D3    D2    D1    D0    MODE      EXPLANATION
 +                NORMAL       Occurs on a weekly cycle at 
 +                                     the same time each day, on 
 +                                     day or days specified by byte 
 +                                     21 and at the time specified 
 +                                     by bytes 22 and 23.  The 
 +                                     function and codes for event 
 +                                     are specified by bytes 24 to 27.
 +
 +      0            SECURITY    Same as NORMAL mode 
 +                                     except that the event time 
 +                                     will be different each day 
 +                                     and will be within one hour 
 +                                     after the time specified by 
 +                                     byte 22.  (varies in a 
 +                                     pseudo random pattern). 
 +                                     SECURITY is only available in 
 +                                     EVERYDAY and SPECIFIC DAYS  
 +                                     modes, see note 5.
 +
 +
 +
 +TABLE 4 - TIMER MODE SELECTION
 +BYTE 20 lower nibble
 +D3    D2    D1    D0    MODE      DESCRIPTION
 +                TODAY     EVENT occurs only TODAY at 
 +                                  the time specified by bytes 22 
 +                                  and 23. and will be cleared from 
 +                                  memory at midnight TODAY.
 +
 +                TOMORROW   EVENT occurs only TOMORROW 
 +                                   at the time specified by bytes
 +                                   22 and 23. and will be cleared 
 +                                   from memory at midnight 
 +                                   TOMORROW.
 +
 +                 CLEAR      Clears from memory, the 
 +                                    event specified by the event 
 +                                    number stored in bytes 18 
 +                                    and 19.
 +
 +
 +NOTE 5
 +In addition to TODAY and TOMORROW, it is suggested that the program offer the
 +user the choice of EVERYDAY and SPECIFIC DAYS.  If EVERYDAY is chosen, byte
 +21 should be sent as 7F HEX (all days selected).  If SPECIFIC DAYS is chosen,
 +byte 21 should indicate which days were chosen.
 +
 +
 +GRAPHICS DATA DOWNLOAD
 +Graphics data is stored in bytes 1024 to 1535 of the 2K  x 8 RAM in the
 +interface.  Only bytes 20 and 21 of the downloaded message are stored.  Each
 +pair of bytes is assigned a number between 0 and 511 as specified by A0 to A6
 +in byte 18 and A7 in byte 19.  D0 in byte 18 is ALWAYS '0' so these address
 +numbers increase in steps of 2 (for graphics type and X-10 code of 256
 +objects).  Note also that byte 19 D1 is ALWAYS "0" and D2 is ALWAYS "1".
 +The computer should keep track of the message numbers and load new messages
 +into vacant address locations.  The contents of bytes 20 and 21 depends on
 +the graphics approach used by the programmer (see note 6), the interface
 +merely stores this data and will upload it to the computer upon request (see
 +graphics upload).  Byte 22 is the sum of bytes 20 and 21.
 +
 +
 +GRAPHICS DATA DOWNLOAD
 +BYTE   D7   D6   D5   D4   D3   D2   D1   D0
 +1-16    1    1    1    1    1    1    1    1   Sync 16 X FF
 +17      0    0    0    0    0    0    1    1   ID3, event/graphics download.
 +18     A6   A5   A4   A3   A2   A1   A0    0   A0 to A7, binary number for
 +19      X    X    X    X    X    1    0   A7   graphics object- 256 objects.
 +20                 GRAPHICS DATA               User RAM to define type and
 +21                 GRAPHICS DATA               X-10 code of graphics object.
 +22                   CHECK SUM                 Sum of bytes 20 and 21.
 +
 +X= DON'T CARE 
 +
 +
 +Note 6
 +A suggested allocation for byte 20 is shown below.
 +BYTE 20   D7   D6   D5   D4   D3   D2   D1   D0
 +          1=ON          ICON TYPE
 +          0=OFF
 +
 +FOR EXAMPLE
 +ICON of a lamp shown in the ON state.
 +              0    0    0    0    0    0    1
 +ICON of a T.V. shown in the ON state.
 +              0    0    0    0    0    1    0
 +ICON of a coffee pot shown in the ON state.
 +              0    0    0    0    0    1    1
 +ICON of a fan shown in the OFF state.
 +              0    0    0    0    1    0    0
 +
 +Byte 20 = 0 indicates a vacant ICON storage location.  To clear an ICON from
 +the Interface you need to send a graphics download with byte 20 = 0.  Note,
 +after doing this, you should also send a DOWNLOAD TIMER EVENT message with
 +byte 20 = 0 (to clear any timed events for the removed ICON).
 +
 +A suggested allocation for byte 21 is shown below.
 +
 +BYTE 21    D7   D6   D5   D4  !  D3   D2   D1   D0
 +              HOUSECODE OF    !  UNIT CODE OF 
 +              STORED ICON      STORED ICON
 +
 +
 +
 +REQUEST CLOCK AND BASE HOUSECODE
 +(Interface to Computer)
 +
 +To upload the time and Base Housecode from the Interface it is first necessary
 +to send a leading SYNC pattern of 16 X FF bytes, followed by an ID4 for the
 +request clock and Base Housecode.  See below.
 +
 +BYTE    D7   D6   D5   D4   D3   D2   D1   D0
 +1-16        1    1    1    1    1    1    1    SYNC FF X 16
 +17          0    0    0    0    1    0    0    BASE Housecode.
 +
 +If the Interface receives the request correctly it will respond by uploading
 +the clock and Base Housecode to the computer, as shown.  If the request is
 +not received correctly, no response is given.
 +
 +
 +
 +CLOCK AND BASE HOUSECODE UPLOAD
 +Byte   D7   D6   D5   D4   D3   D2   D1   D0
 +1-6        1    1    1    1    1    1    1   SYNC 6 X FF
 +7          0    0    0    0    0    0    S   status bit. *
 +8          0             MINUTES             HEX 00 to 3B (0 to 59)
 +9          0    0         HOURS              HEX 00 to 17 (0 to 23).
 +10      0   Sun  Sat  Fri  Thu  Wed  Tue  Mon  Bit mapped days.
 +11      BASE HOUSECODE      0    0    0    0   Same as table 1.
 +12                  CHECK SUM                 Sum of bytes 8 to 11.
 +
 +* The STATUS bit is reset to "0" during power up of the Interface and is set
 +to "1" by a DOWNLOAD of data from the computer (any data with byte 17 equal to
 +ID 0
 +, 1, 2, or 3).  The STATUS bit is used to warn the computer that the Interface
 +has been powered down.  E.G. a STATUS bit equal to "0" could tell the program
 +to display a message such as "The Interface has been powered down and contains
 +no data.  Press Enter to continue".
 +
 +
 +
 +REQUEST TIMER EVENTS (Interface to Computer)
 +To upload the timer events from the Interface it is first necessary to send a
 +leading SYNC pattern of 16 X FF bytes, followed by an ID5, for request timer
 +events.  See below.
 +
 +BYTE   D7   D6   D5   D4   D3   D2   D1   D0
 +1-16    1    1    1    1    1    1    1    1    SYNC FF X 16
 +17      0    0    0    0    0    1    0    1    ID5, request timer events.
 +
 +The Interface will respond by uploading to the computer, all of the 128 events
 +starting with number 1 as shown below.  A vacant event is represented by a
 +single FF byte, this shortens the time for the upload.  The check sum does
 +not include these FF bytes.
 +
 +
 +
 +TIMER EVENTS UPLOAD
 +EXAMPLE WHERE ONLY FIRST TWO EVENTS ARE PROGRAMMED
 +
 +BYTE   D7   D6   D5   D4   D3   D2   D1   D0
 +16      1    1    1    1    1    1    1    1     SYNC FF X 6.
 +7          0    0    0    0    0    0    0     Status.
 +8-15   EVENT NUMBER 1 AS DOWNLOADED, 8 BYTES.
 +24-149  1    1    1    1    1    1    1    1     FF X 126 to indicate 126 
 +                                                 vacant event spaces.  
 +150                   CHECK SUM                  Sum of bytes 8 to 23 (FF 
 +                                                 bytes ignored).
 +
 +
 +REQUEST GRAPHICS DATA (Interface to Computer)
 +
 +To upload graphics data from the Interface it is first necessary to send a
 +leading SYNC pattern of 16 X FF bytes followed by and ID6, for request
 +graphics data.  See below.
 +
 +BYTE    D7   D6   D5   D3   D2   D1   D0
 +1-16        1    1    1    1    1    1    SYNC FF X 16
 +17          0    0    0    1    1    0    ID6, request graphics data.
 +
 +The Interface will respond by uploading to the computer, all of the 256
 +ICONS starting with number 1, as shown on page 33.  A vacant ICON space is
 +represented by a single FF byte, this shortens the time for the upload.  The
 +check sum does not include these FF bytes.
 +
 +
 +
 +GRAPHICS DATA UPLOAD
 +EXAMPLE WHERE ONLY 5 ICONS ARE PROGRAMMED
 +
 +BYTE    D7   D6   D5   D4   D3   D2   D1   D0
 +1-6      1    1    1    1    1    1    1    1    SYNC FF X 6.
 +7        0    0    0    0    0    0    0    0    Status.
 +8-9                   ICON NUMBER 1              2 bytes.
 +10-11                 ICON NUMBER 2              2 bytes.
 +12-13                 ICON NUMBER 3              2 bytes.
 +14-15                 ICON NUMBER 4              2 bytes.
 +16-17                 ICON NUMBER 5              2 bytes.
 +18-268      1    1    1    1    1    1    1    FF X 251 to indicate 251 
 +                                                 vacant ICON spaces.
 +269                    CHECK SUM                 Sum of bytes 8 to 17 (FF 
 +                                                 bytes ignored).
 +
 +
 +DIAGNOSTIC
 +
 +The Interface has a self test diagnostic routine which is initiated by sending
 +a leading SYNC pattern of 16 X FF bytes followed by a ID7.  Upon receiving
 +this instruction, the Interface will run a self check on it's own hardware and
 +software (firmware).  The output of the Interface (pins 3 and 4) will go low
 +for 10 seconds as part of this test.  If the check is o.k. the Interface
 +will respond by sending the ACK with status "0" If a fault is diagnosed,
 +the interface will Send ACK with status "1" or will not respond.
 +
 +BYTE    D7   D6   D5   D4   D2   D1   D0
 +1-16        1    1    1    1    1    1    SYNC FF X 16
 +17          0    0    0    1    1    1    ID7, initiate self test.
 +
 +
 +
 +The above programming guide is included when you purchase the interface.  I
 +checked and it is freely distributable.  And remember, if you don't want to
 +control more than 95 modules, you don't need to create your own program (as
 +stated previously.
 +
 +If you want to read further on the X-10 system, then go to there web page at
 +http://www.x10.com.  They have information on all the products they carry,
 +as well as ones still in the works.  Also on the web page is a FAQ (Frequently
 +Asked Questions) file that has a wealth of information on the X-10 system
 +and compatible products.  Unfortunately, the interface is no longer sold
 +packaged with the Commodore cable and software.  So, you must purchase the
 +interface packaged with some other software and call X-10 and order the
 +Commodore connection package separately for $25.  Of course you can create
 +a cable and copy the software (it is also freely distributable) if you
 +wanted to.  To get the interface and any modules or compatible products,
 +Home Controls has a great selection, and there catalogue is filled with
 +home automation equipment.  X-10's and Home Controls addresses and phone
 +numbers are as follows:
 +
 +
 +X-10 (USA) INC.
 +91 Ruckman Rd.
 +Closter, NJ  07624
 +Phone: 201-784-9700
 +
 +Home Controls INC.
 +7626 Miramar Road, Suite 3300
 +San Diego, CA  92126-4446
 +Phone: 800-266-8765  or  619-693-8887
 +
 +
 +
 +:::::::::::d:i:s:C=:o:v:e:r:y:::::::::::::::::i:s:s:u:e::3::::::::::::::::::::
 +\H02::::::::::::::::::::::::::H:A:R:D:W:A:R:E:::::::::::::::::::::::::::::::::
 +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 +
 +
 + !......The Metal Shop......!
 +                                                     // - The Metal Shop - //
 +
 +                      ^...!..The Metal Shop..!...^
 +
 +
 +  Contributors : XmikeX  (xmikex@eyrie.stanford.edu)
 +                 Co-Sysop of DiamondBack BBS (305)258-5039
 +
 +                 David Wood (jbevren@willowtree.com)
 +
 +                 Marc-Jano Knopp and Daniel Krug
 +                 http://www.student.informatik.th-darmstadt.de/%7Emjk/c64.html
 +
 +
 +
 +Dear Metal Shop,
 +
 +    I recently found a 16 KB Commodore expander for my trusty VIC-20.  My
 +glee turned to disgust after realizing that I needed the proper DIP scheme
 +required to bank the memory into the VIC.  I barely know the old '20, much
 +less this expander.  Please tell me this will be easy.... :)
 +
 +RE
 +--
 +
 +RE,
 +
 +You are in luck RE because as the Good Lord would have it, I have also run
 +into a VIC-20 expander!  Ok...I didn't just "run" into it...  I actively
 +sought one out to view the new Veni Vedi Vic (Vedi Veni Vic?) demo by Marko
 +Makela (with umlauts over the a's).  :)  And oh Yes, this will be easy!
 +
 +Without much further ado, I decoded the DIP scheme for my 16 KB VIC-20
 +expansion cartridge, as follows :
 +
 + 
 +CBM VIC-1111 16 KiloByte RAM expansion cartridge with eight DIP scheme
 +----------------------------------------------------------------------
 + 
 +Expansion RAM bank 1                            Expansion RAM bank 2
 +(8 KB)                                          (8 KB)
 +                          8 KB Mapped to :
 +1                                                     8
 +on    off   off   off   -> $A000-RAM/ROM4 <-    on    off   off  off
 +off   on    off   off   -> $6000-RAM/ROM3 <-    off   on    off  off
 +off   off   on    off   -> $4000-RAM/ROM2 <-    off   off   on   off
 +off   off   off   on    -> $2000-RAM/ROM1 <-    off   off   off  on
 +
 + 
 +As is evident above, the DIP settings for each bank yield identical results 
 +so I suspect that the settings for the 8 KB CBM ram expander follow the same
 +scheme.  8 KB chunks do keep things simple, and we can either give the VIC-20
 +just 8 KB of expansion memory at $2000, $4000, etc., or we can activate both
 +banks and map them to these RAM/ROM expansion blocks within the VIC's memory
 +map for 16 KB total.  For example, whereas 8 KB ROM images are usually quite
 +happy with 8 KB of memory at RAM/ROM4, most 16 KB rom images tend to require
 +that RAM/ROM blocks 3 and 4 be active.  We can accomplish this by mapping
 +expansion bank 1 into $6000 and bank 2 into $a000 (or vice versa!).  In this
 +case, our DIP settings could be :
 + 
 +        1                             8
 +        off   on    off   off   on    off   off   off
 + 
 +                             OR
 + 
 +        on    off   off   off   off   on    off   off
 + 
 + 
 +Please note that with the CBM 16k expander, we cannot map any of its memory
 +to the 3 KB expansion area sitting at $0400-0fff (1024-4095).  - XmikeX
 +--
 +
 +[Ed. Note : The following is a response to the 1541 <-> Apple disk ][
 + discussion that appeared in this column, issue 2.  It has been reprinted
 + in its entirety with permission from the author.]
 +
 +
 +From    :  jbevren@willowtree.com
 +Date    :  19-JAN-1997 08:58:43.19
 +Subject :  info on 1541/disk ][ transfers
 +
 +First: Thank you disC=overy magazine.  I've read a few zines, and only yours
 +and C= Hacking make the bet for me.
 +
 +Keep up the _good_ work!
 +
 +
 +Dear Metal Shop,
 +
 +I was reading the article in the disC=overy magazine, issue two.  In there
 +was a section from a user who has an Apple ][ computer who wished to
 +transfer files from the computer's disk drive to the Commodore 1541 (or was
 +it vice-versa?).
 +
 +I am commenting on the hardware aspect of the disk ][ drives on the Apple
 +computer.  When I was in college, my 1541 failed completely due to
 +lightning.  The main board was fine, but the read/write head was blown
 +"open" as I discovered in the school's electronics lab.  Remembering my
 +days on the ol' ][ in high school, I thought of hooking a disk ][ assembly
 +to the 1541 board.
 +
 +I acquired a junk drive assembly from a friend, unhooked all the
 +electronics, and re-wired the assembly to the 1541 drive's CPU board. 
 +Voila!  The system ran fine, until I could come up with a low-density
 +single-sided assembly from a PC to fit "inside" the 1541's case.  It even
 +ran fastloaders and GEOS.
 +
 +Point at hand?  The disk ]['s mechanical assembly is functionally identical
 +to the 1541's drive assembly.  In fact, the Alps assembly was used in some
 +Apple compatible drives (am I right?).  Reading Apple disks on the 1541 will
 +be one hell of a challenge, because of the drive's limited RAM.  
 +
 +However, reading Commodore's GCR format should be fairly easy if you have a
 +little advanced knowledge of the disk ][ interface.  All you have to do is
 +get a modified CBM DOS binary into the Apple ][, and have it read the
 +Commodore disk.  Not a trivial task mind you.  When the DOS is in the Apple,
 +the rest is easy.  simply change the locations the program uses to
 +read/write the disk, and you have it.
 +
 +Hope I was helpful!
 +
 +-David Wood
 +
 +ps:  All the disk ][ is (with the interface included), is a 1541 with no
 +brains. :)
 +--
 +
 +[Ed. Note : The text below to the end of the article is a sample of the C=
 + hardware repair and enhancement projects put out by Marc-Jano Knopp & Daniel
 + Krug on the WWW http://www.student.informatik.th-darmstadt.de/%7Emjk/c64.html
 + Reprinted with permission.]
 +
 + 
 +                                   SAFER SID!
 +                                       
 +
 +Project: Protection circuit for SID
 +Target : C64 (all models)
 +Time   : 20 min
 +Cost   : ~1 US$
 +Use    : Protect the SID from overvoltage.
 +
 +
 +Cause
 +  
 + The SID cannot stand more than 3Vss or 1Veff, respectively.
 + Therefore, if you use the SID audio input, the input voltage
 + should be limited. The circuit below limits the input signal
 + to about 1.4Vss. This is done by two antiparallel silicon diodes
 + which cut off the signal at +/- 0.7V. The resistor limits the
 + current coming out of the audio source.
 +
 +Ingredients
 +
 +  - 1 resistor 470 ohm
 +  - 2 diodes 1N4148 (or 1N914)
 +
 +Instructions
 +
 +  1. Build the following circuit:
 +
 +  SID protection circuit
 +  ----------------------
 +
 +
 +  (5)  O---------o----------o-------XXXXX-----O  Audio in
 +                          |
 +                          |                    __
 +              +-----+     -----                 /  \
 + <-- to SID    \   /       / \          <--   -+----+----+-
 +                \ /       /                        \__/
 +               -----     +-----+
 +                          |
 +  (2)  O---------o----------o-----------------O  GND
 +
 +
 +  XXXXX  = resistor 470ohm
 +  diodes = 1N4148 or 1N914
 +
 +
 + 2. ... and stuff it in a DIN plug for the AV jack.
 +
 +
 +
 +                         SPONTANEOUSLY RESETTING C-64?
 +                                       
 +
 +Symptom: C-64 resets at random.
 +Target : C64 (all models) and VC20
 +Time   : 10 min.
 +Cost   : <1 US$
 +
 +
 +Cause
 +
 +  Voltage level floats near to forbidden zone (unstable voltage
 +  below ~4 volts).
 +
 +Fix
 +
 +  Pull-up resistor between pin 3 (/RESET) and pin 2 (+5V) of
 +  user port. Value should be in the range of 4.7k to 10k,
 +  starting with 10k.
 +
 +Note
 +
 +  C-64s which are used industrially, should be equipped with an
 +  additional 100nF capacitor connected between pin 3 (/RESET) and
 +  GND (pin 1), which provides excellent noise immunity.
 +  The same applies to users encountering reset problems due to
 +  a long reset switch cable.
 +
 +Ingredients
 +
 +  - resistor of 10k (or less)
 +
 +Instructions
 +
 +  1. Open case, disconnect power plug!
 +
 +  2. Solder one end of resistor to pin 2 the other end to pin 3
 +     of the user port connector. DO NOT solder the leads directly
 +     onto the contact area, instead try soldering them to the
 +     nearest visible bare point connected to the above pins.
 +
 +  3. Connect power plug and keep your C-64 running for several
 +     hours. See if it resets spontaneously as before; if not,
 +     close the case again.
 +
 +Possible failures
 +
 +  - Resistor's value is too high, try 5.6k or 4.7k otherwise.
 +
 +
 +
 +                               'FIX' RESTORE KEY!
 +                                       
 +
 +Project: Make RESTORE key behave like all the other keys
 +Target : C64 (old)
 +Time   : 15 min.
 +Cost   : <1 US$
 +Use    : Never hear the RESTORE key singing
 +         'Killing me softly ...' again.
 +
 +
 +  Extract
 +
 +   Replace 'NMI-capacitor' C38 by a 4.7nF one.
 +  
 +  Cause
 +
 +   The value of the built in capacitor responsible for triggering
 +   the NMI via the timer 556 is too small in old C-64's (big PCB).
 +   On account of the pressure dependant resistance of the keys,
 +   pressing the RESTORE key just as softly as the other keys is not
 +   sufficient for producing a trigger signal at the timer's TRIG
 +   input. Therefore, we will replace it with a 4.7nF capacitor.
 +  
 +   The problem described above was fixed in the new (small) PCB's
 +   and in the SX-64.
 +  
 +Ingredients
 +
 +  - 1 capacitor 4.7nF
 +
 +Instructions
 +
 +  1. Open case, disconnect power plug!
 +
 +  2. Search for capacitor C38 (51pF) below the leftmost CIA. In
 +     most boards it is built into a resistor case with green base
 +     color! Its color code is: green-brown-black
 +
 +  3. Unsolder it and replace it with the 4.7nF one.
 +
 +  4. Connect power plug.
 +
 +  5. Switch your C-64 on. After the startup screen appeared press
 +     [STOP]-[RESTORE] just as softly as you would usually hit the
 +     other keys. Repeat that procedure a few times and if the
 +     RESTORE key seems to behave like the other keys, close the
 +     case again.
 +
 +Possible failures
 +
 + - Replaced the wrong capacitor. Often the capacitor is built into
 +   a resistor case.
 +
 +
 +
 +                                 BLACK SCREEN
 +                                       
 +
 +Symptom: Screen remains black.
 +Target : C-64
 +
 +
 +  Possible sources of failure
 +    - Power supply's fuse is blown -> no power :)
 +    - continuous reset -> no startup
 +    - Fuse -> no 12V for VIC (old C-64)
 +    - Voltage regulator -> no 12V, no fun (old C-64)
 +    - CPU -> blocks phi2 or bus
 +    - VIC -> blocks bus
 +    - SID -> blocks bus
 +    - PLA -> well.... :)
 +    - 8701 -> no clock cycles
 +  
 +  
 +Analysis - Power supply ok?
 +
 +  If the power LED is not lit, check the power supply's fuse and
 +  replace it, if necessary. Next, measure the voltage directly on
 +  the power plug. If you cannot find 5VDC and 9VAC anywhere, kick
 +  the power supply and get a new one.
 +
 +  If you have an old C-64, check its internal fuse now.
 +
 +  Then check the 5V at the power jack (before the switch!) with
 +  the power supply plugged in and the C-64 switched on. It should
 +  be between 4.9 and 5.1V. If not, a defective IC might demand a
 +  current so high that the 5V level gets pulled below 4.8V. You
 +  should be able to locate the very IC by simply touching all the
 +  chips and checking for especially hot ones. Replace it.
 +
 +  Next, measure the 5V supply voltage between pin 7 (GND) and pin
 +  14 (Vcc) of a 74xx chip. If the 5V show to be ok, then continue
 +  with 'Voltage regulator ok?'.
 + 
 +  Otherwise, it is very likely that the cause for the low vol-
 +  tage level is - believe it or not, it DID happen to a lot of
 +  people - the power switch(!), so that it could be a good idea to
 +  either rock the switch several dozen times, open and clean it or
 +  to replace it completely.
 +
 +Reset line HIGH?
 +
 +  Since it is possible that the black screen is caused by a con-
 +  tinuous reset, you should check the voltage between pin 1 (GND)
 +  and pin 3 (/RESET) of the user port. If it is below 1V, then
 +  check the reset switch, if you got one. Otherwise, check wether
 +  the output levels of the 7406 and 74LS14 (new board) match their
 +  input levels. Next, you should check the timer 556 (old board)
 +  when I managed to offer you a description for that chip :) Until
 +  then, simply replace it, it is not socketed, but cheap.
 +
 +  If that does not help, some other chips load the reset line so
 +  that the level is below 2.4V which causes the CPU to reset. Try
 +  a pull-up resistor (4.7k) between pin 2 (+5V) and pin 3 (/RESET)
 +  of the user port. If that does not make the blank screen vanish,
 +  check for other defective chips (which probably become very hot,
 +  see later in this document).
 +
 +Voltage regulator ok?
 +
 +  In case you have an old C-64, check the 12V voltage regulator
 +  VR1 (7812). At the output (right pin, 2) you should measure
 +  around 12V (11.8 to 12.3V). If not, measure the input voltage
 +  (left pin, 1), the voltmeter should show about 15 to 20V. If the
 +  latter is the case, replace the VR. If the input voltage is out
 +  of range, check the 9VAC on the power plug (with the C-64 still
 +  switched on). If they prove to be ok, then the two diodes before
 +  the voltage regulator could be damaged; replace them. If you cannot
 +  find the 9VAC, make sure you have checked for the C-64's internal
 +  fuse and otherwise get another power supply.
 +
 +CPU running?
 +
 +  Try accessing the floppy drive by typing blindly (you do not
 +  need to close your eyes)
 +
 +    LOAD"$",  (assuming your device id is '8')
 +
 +  If the floppy drive's motor starts spinning, you are lucky. The
 +  processor, the CIA's and the address manager seem to work.
 +  If the floppy does not react in any way, you probably have a
 +  serious problem and should continue reading...
 +
 +Other chips alive?
 +
 +  Test VIC, SID, PLA and, where applicable, the clock circuit 8701
 +  near the VIC (not in very old PCB revisions), whether they get
 +  extraordinaryly hot. If any of the chips gets hot, it is very
 +  likely that they are defective and, e.g. block the bus. These
 +  should be replaced. In C-64s with the new board, you will find
 +  a 64-pin multifunction chip, the MMU. If the other chips are ok,
 +  it is probably the MMU which is damaged. Alas, this MMU is prac-
 +  tically impossible to replace, there are neither suitable
 +  sockets nor spare chips.
 +
 +  Of course, every chip connected to the bus in any way could be
 +  damaged and blocking the bus, therefore you should also check
 +  if the CIAs, the ROMs, the RAMs, the RIMs or the RUMs (oops) are
 +  getting extremly hot.  Especially in the old C-64 board, the
 +  various 74xx/74LSxx might be responsible for the failure.
 +
 +If all else fails...
 +
 +  ... you should consider the very low price of a used C-64 on
 +  the free market or, if you live in a strange country with prices
 +  over US$ 30 for a C-64 (including power supply), check for
 +  hair cracks and dry joints.
 +
 +
 +
 +:::::::::::d:i:s:C=:o:v:e:r:y:::::::::::::::::i:s:s:u:e::3::::::::::::::::::::
 +\L01:::::::::::::::::::::::::::::L:E:G:A:L::::::::::::::::::::::::::::::::::::
 +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 +
 +
 +                A R T I C L E S    O F    O P E R A T I O N
 +
 +
 +Article 1 : Mission Statement
 + 
 +Our intent is to present useful information in order to enhance and preserve
 +the knowledge base of the Commodore 8-bit domain, including, but not limited
 +to, the Commodore 64 and Commodore 128 home computers.  To this end, we shall
 +require that every article contain what in our discretion should be a viable
 +Commodore 8-bit hardware and/or software point of relevance.  Likewise, each 
 +issue should include material that can both potentially enlighten the most
 +saavy of users as well as the layman.  We intend to complement and assist all
 +others engaged in similar endeavours.  We believe it is of paramount concern
 +to stave off entropy as long as possible.
 + 
 + 
 +Article 2 : disC=overy Staff
 + 
 +The current staff of disC=overy, the Journal of the Commodore Enthusiast,
 +is as follows:
 + 
 +      Editor-in-Chief       : Mike Gordillo  (s0621126@dominic.barry.edu)
 +      Associate/Tech Editor : Steven Judd    (sjudd@nwu.edu)
 +      Associate/Tech Editor : George Taylor  (aa601@chebucto.ns.ca)
 +      Webmaster             : Ernest Stokes  (drray@eskimo.com)
 +
 +      disC=overy, issue 3 logo by 'WaD'
 + 
 +We invite any and all interested parties to join us as authors, panelists,
 +and staff members.
 + 
 + 
 +Article 3 : General Procedures
 +
 +- Submission Outline -
 +
 +a. Articles may range in size from 1 kilobyte and up.  Approximately 15
 +   kilobytes of text is the preferred length, including any software present.
 +
 +b. Sufficient technical content about Commodore 8-bit home computers,
 +   concerning software and/or hardware relevant to these systems, is a 
 +   requirement.  What constitutes a sufficient amount of 'technical
 +   content' is left to the discretion of the Editor-in-Chief and/or the
 +   review panel (see below).
 +
 +
 +- Staff Priorities -
 +
 +The Editor-in-Chief shall supervise the organization of each issue in regards
 +to grammatical and syntactical errors, flow of content, and overall layout of
 +presentation.  The Editor-in-Chief and Associate Editor shall form a review
 +panel whose function it shall be to referee literary work which the Editor
 +in-Chief has deemed to be of advanced technical merit.  The Editor-in-Chief
 +iand disC=overy, the Journal of the Commodore Enthusiast, shall retain
 +copyright solely on the unique and particular presentation of its included body
 +of literary work in its entirety.  Authors shall retain all copyrights and
 +responsibilities with regards to the content of their particular literary
 +work.  Authors shall be required to submit their works to the Editor-in-Chief
 +approximately two weeks prior to publication.
 +
 +
 +Article 4 : Peer Review
 + 
 +To the best of our knowledge, disC=overy shall be the first Commodore 8-bit
 +journal with a review panel dedicated to uphold the technical integrity and
 +legitimacy of its content.  The Editor-in-Chief and the Associate Editor
 +shall be responsible for the formation of the panel.  The appointed
 +panelists shall have the option of anonymity if desired.  The panel shall
 +review works primarily for technical merit if the Editor-in-Chief and
 +the Associate Editor deem it necessary.  Authors may be asked to modify
 +their works in accordance with the panel's recommendations.  The Editor-in-
 +Chief shall have final discretion regarding all such "refereed" articles.
 +
 +
 +Article 5 : Distribution
 +
 +Although we welcome open distribution by non-commercial organizations, there
 +are currently four "official" distribution channels available to interested
 +parties.  This journal may be obtained by directly mailing the Editor-in-Chief
 +or via the World Wide Web at http://www.eskimo.com/~drray/discovery.html and
 +at FTP site : ftp.eskimo.com - directory /u/t/tpinfo/C64/Magazines/discovery
 +A "snail" mail disk copy of any issue of this journal may also be obtained
 +from Arkanix Labs at the following physical address :
 +
 +   disC=overy, c/o Jon Mines
 +   Arkanix Labs
 +   17730 15th Ave NE  Suite #229
 +   Shoreline, WA  98155
 +
 +This source should follow the distribution guidelines as listed in Article 6
 +below.  However, specific questions concerning billing, etc., should be
 +directed at them.
 +
 +Several versions of this journal may be available for your convenience, please
 +check with the aforementioned sources.
 +
 +
 +Article 6 : Disclaimers
 + 
 +The Editor-in-Chief and disC=overy, the Journal of the Commodore Enthusiast,
 +retain all copyrights regarding the presentation of its articles.  Authors
 +retain all copyrights on their specific articles in and of themselves,
 +regarding the full legal responsibility concerning the originality of their
 +works and its contents.
 +
 +The Editor-in-Chief and disC=overy, the Journal of the Commodore Enthusiast,
 +grants the reader an exclusive license to redistribute each issue in its
 +entirety without modification or omission under the following additional
 +stipulations:
 + 
 +      - If distribution involves physical media and is part of a commercial,
 +        not-for-profit, or PD distribution, the maximum allowable monetary
 +        charge shall not exceed $4 1996 United States Dollars per issue
 +        unless more than one issue is distributed on a single media item
 +        (i.e., two or more issues on one disk), in which case maximum
 +        allowable charge shall not exceed $4 1996 United States Dollars per
 +        media item.  All dollar values given assume shipping costs are
 +        -included- as part of the maximum allowable charge.
 + 
 +      - If distribution involves non-physical media and is part of a
 +        commercial, not-for-profit, or PD distribution, the maximum
 +        allowable charge shall be limited to the actual cost of the
 +        distribution, whether said cost be in the form of telephony or
 +        other electronic means.
 +
 +      - Software included within articles (as text) may be subject to separate
 +        distribution requirements as binary executables.  Please check directly
 +        with authors regarding distribution of software in binary form.
 +
 +      - disC=overy should be distributed on per-issue basis, and any potential
 +        subscription arrangements are strictly between distributor and reader.
 +        We do not guarantee subscriptions nor do we take responsibility for
 +        distribution outside of the disC=overy home page on the World Wide
 +        Web (http://www.eskimo.com/~drray/discovery.html)
 +
 +It is understood that distribution denotes acceptance of the terms listed and
 +that under no condition shall any particular party claim copyright or public
 +domain status to disC=overy, the Journal of the Commodore Enthusiast, in its
 +entirety.
 + 
 +The Editor-in-Chief and disC=overy, the Journal of the Commodore Enthusiast,
 +reserve the right to modify any and all portions of the Preamble and the
 +Articles of Operation.
 +
 +:::::::::::d:i:s:C=:o:v:e:r:y:::::::::::::::::i:s:s:u:e::3::::::::::::::::::::
 +\END:::::::::::::::::::::::::::March 26, 1997:::::::::::::::::::::::::::::::::
 +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 +</code>
magazines/discovery3.txt · Last modified: 2015-04-17 04:35 by 127.0.0.1