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: | ||
+ | < | ||
+ | __ __ | ||
+ | | ||
+ | | ||
+ | / __ / || || |__|__|| | ||
+ | | ||
+ | | ||
+ | | ||
+ | _ | ||
+ | | ||
+ | |||
+ | |||
+ | | ||
+ | |||
+ | |||
+ | 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. | ||
+ | Commodore 8-bit machines in high regard and respect. | ||
+ | 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. | ||
+ | |||
+ | |||
+ | |||
+ | ::::::::::: | ||
+ | :::::::::::::::::::::: | ||
+ | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||
+ | |||
+ | |||
+ | -Software Section- | ||
+ | |||
+ | /S01 - " | ||
+ | $a480 by Stephen L. Judd | ||
+ | |||
+ | /S02 - "A Closer Look at the VIC II's Output" | ||
+ | $d000 by Adrian Gonzalez and George Taylor | ||
+ | |||
+ | /S03 - " | ||
+ | $d000 Interpretation Technique" | ||
+ | by Roland Toegel, 'Count Zero', and George Taylor | ||
+ | |||
+ | /S04 - " | ||
+ | $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 ' | ||
+ | |||
+ | |||
+ | -Legal Section- | ||
+ | |||
+ | /L01 - Articles of Operation, Distribution, | ||
+ | |||
+ | |||
+ | |||
+ | ::::::::::: | ||
+ | / | ||
+ | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||
+ | |||
+ | |||
+ | Rommaging around : $A480-$A856 | ||
+ | ---------------- | ||
+ | Stephen L. Judd (sjudd@nwu.edu) | ||
+ | | ||
+ | " | ||
+ | |||
+ | 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. | ||
+ | version, on the other hand, is written in a more 'human readable' | ||
+ | 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, | ||
+ | |||
+ | BLARG is a program which adds several hires graphics commands to BASIC, | ||
+ | and was the main motivation to finally get started on this project. | ||
+ | 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. | ||
+ | part gives a brief overview of BLARG. | ||
+ | and BLARG binaires are all included. | ||
+ | |||
+ | http:// | ||
+ | |||
+ | About the ROM listings: I did them up in Merlinesque format of | ||
+ | course. | ||
+ | and local lables. | ||
+ | definition is only valid between two global lables. | ||
+ | may be redefined. | ||
+ | |||
+ | PROC1 BNE :CONT | ||
+ | INC TEMP1 | ||
+ | :CONT RTS | ||
+ | |||
+ | PROC2 BNE :CONT | ||
+ | INY | ||
+ | :CONT DEC TEMP1 | ||
+ | RTS | ||
+ | |||
+ | contains two global labels (PROC1 and PROC2). | ||
+ | instruction and PROC2 will branch to the DEC TEMP1 instruction, | ||
+ | :CONT label is redefined once the global label PROC2 appears. | ||
+ | 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. | ||
+ | is entered into a text buffer located at $0200. | ||
+ | is then tokenized by the BASIC interpreter. | ||
+ | command (doesn' | ||
+ | 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] | ||
+ | | | | ||
+ | | | | ||
+ | | | | ||
+ | | | | ||
+ | | | | ||
+ | | | | ||
+ | | | | | ||
+ | | | 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 line in the program. | ||
+ | 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 " | ||
+ | |||
+ | 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 ; | ||
+ | 2054 32 ;space | ||
+ | 2055 34 " | ||
+ | 2056 72 H ; | ||
+ | 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. | ||
+ | the address of the routines in question. | ||
+ | table is located at $0300-$030B: | ||
+ | |||
+ | IERROR | ||
+ | IMAIN | ||
+ | ICRNCH | ||
+ | IQPLOP | ||
+ | IGONE | ||
+ | IEVAL | ||
+ | | ||
+ | |||
+ | Calls to these routines are vectored through these addresses via an | ||
+ | indirect JMP -- they are called using JMP (IMAIN) for instance. | ||
+ | vectors may then be redirected to new routines, and so they provide | ||
+ | a smooth way of adding new keywords to BASIC. | ||
+ | tokenize lines of text when they are entered. | ||
+ | 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. | ||
+ | up, and are located at $0073: | ||
+ | |||
+ | $73 | ||
+ | $75 BNE CHRGOT | ||
+ | $77 INC TXTPTR+1 | ||
+ | $79 | ||
+ | $7A | ||
+ | ;Generally points at BASIC or points | ||
+ | ;at input buffer at $0200 when in | ||
+ | ;immediate mode. | ||
+ | $7C | ||
+ | $7E BCS EXIT ;Exit if not a numeral | ||
+ | $80 CMP #$20 ;Check for ASCII space | ||
+ | $82 BEQ CHRGET | ||
+ | $84 SEC | ||
+ | $85 SBC #$30 ;Digits 0-9 are ASCII $30-$39 | ||
+ | $87 SEC | ||
+ | $88 SBC #$D0 ;Carry set if < ASCII 0 ($30) | ||
+ | $8A | ||
+ | |||
+ | 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 | ||
+ | $81 | ||
+ | $82 | ||
+ | $83 | ||
+ | $84 | ||
+ | $85 | ||
+ | $86 | ||
+ | $87 | ||
+ | $88 | ||
+ | $89 | ||
+ | $8A | ||
+ | $8B | ||
+ | $8C | ||
+ | $8D | ||
+ | $8E | ||
+ | $8F | ||
+ | $90 | ||
+ | $91 | ||
+ | $92 | ||
+ | $93 | ||
+ | $94 | ||
+ | $95 | ||
+ | $96 | ||
+ | $97 | ||
+ | $98 | ||
+ | $99 | ||
+ | $9A | ||
+ | $9B | ||
+ | $9C | ||
+ | $9D | ||
+ | $9E | ||
+ | $9F | ||
+ | $A0 | ||
+ | $A1 | ||
+ | $A2 | ||
+ | |||
+ | $A3 | ||
+ | $A4 TO | ||
+ | $A5 FN | ||
+ | $A6 SPC( | ||
+ | $A7 THEN | ||
+ | $A8 NOT | ||
+ | $A9 STEP | ||
+ | |||
+ | $AA | ||
+ | $AB | ||
+ | $AC | ||
+ | $AD / | ||
+ | $AE | ||
+ | $AF | ||
+ | $B0 | ||
+ | $B1 > | ||
+ | $B2 | ||
+ | $B3 < | ||
+ | |||
+ | $B4 | ||
+ | $B5 | ||
+ | $B6 | ||
+ | $B7 | ||
+ | $B8 | ||
+ | $B9 | ||
+ | $BA | ||
+ | $BB | ||
+ | $BC | ||
+ | $BD | ||
+ | $BE | ||
+ | $BF | ||
+ | $C0 | ||
+ | $C1 | ||
+ | $C2 | ||
+ | $C3 | ||
+ | $C4 | ||
+ | $C5 | ||
+ | $C6 | ||
+ | $C7 | ||
+ | $C8 | ||
+ | $C9 | ||
+ | $CA | ||
+ | |||
+ | $CB | ||
+ | |||
+ | BASIC ROM | ||
+ | --------- | ||
+ | | ||
+ | The BASIC ROM begins at $A000: | ||
+ | |||
+ | $A000-$A001 | ||
+ | $A002-$A003 | ||
+ | $A004-$A00B | ||
+ | |||
+ | $A00C-$A051 | ||
+ | |||
+ | 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. | ||
+ | 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. | ||
+ | with token $80 (END) and ending with token $A2 (NEW): | ||
+ | |||
+ | $A052-$A07F | ||
+ | |||
+ | 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). | ||
+ | with token $B4 (SGN) and ending with token $CA (MID$). | ||
+ | |||
+ | $A080-$A09D | ||
+ | |||
+ | This table is for math operators, beginning with token $AA (+) | ||
+ | and ending with token $B3 (<). | ||
+ | |||
+ | $A09E-$A19D | ||
+ | |||
+ | This is a table of all the reserved BASIC keywords. | ||
+ | high bit of the last character set, so it is easy to detect the end | ||
+ | of a keyword. | ||
+ | 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. | ||
+ | input buffer at $0200, character codes 192-223 are used for shifted | ||
+ | characters. | ||
+ | for instance typing pO instead of poke. It should also be clear why poK will | ||
+ | also work, but pokE will not work. | ||
+ | |||
+ | $A19E-$A327 | ||
+ | $A328-$A364 | ||
+ | $A365-$A389 | ||
+ | |||
+ | $A38A-$A47F | ||
+ | |||
+ | $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. | ||
+ | routine is vectored through IMAIN at $0302. | ||
+ | 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. | ||
+ | |||
+ | Other important vectored routines are: | ||
+ | |||
+ | $A579 | ||
+ | |||
+ | This routine goes through the BASIC text buffer at $0200 and | ||
+ | tokenizes any keywords which aren't in quotes. | ||
+ | to scan the input buffer it discards any characters which have their | ||
+ | high bit set, such as shifted characters. | ||
+ | initial search for keywords -- shifted characters within quotes or | ||
+ | as part of a keyword are taken care of by another routine). | ||
+ | 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). | ||
+ | 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. | ||
+ | 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. | ||
+ | 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: | ||
+ | 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. | ||
+ | commands to BASIC. | ||
+ | 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. | ||
+ | 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 " | ||
+ | some good documentation, | ||
+ | often at http:// | ||
+ | there, including a complete html cross-referenced ROM listing. | ||
+ | |||
+ | |||
+ | |||
+ | * | ||
+ | * A480-A856 | ||
+ | * 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 | ||
+ | ;Vectored through IMAIN, so it | ||
+ | ;may be redirected. | ||
+ | MAIN JSR INLIN ;Input a line from keyboard | ||
+ | STX TXTPTR | ||
+ | STY TXTPTR+1 | ||
+ | JSR CHRGET | ||
+ | | ||
+ | BEQ JMPMAIN | ||
+ | LDX #$FF ; | ||
+ | STX CURLIN+1 | ||
+ | BCC MAIN1 ;CHRGET clears C when digit is read | ||
+ | JSR CRUNCH | ||
+ | JMP JMPGONE | ||
+ | |||
+ | * | ||
+ | * 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 | ||
+ | JSR CRUNCH | ||
+ | STY COUNT ;Y=length of line | ||
+ | JSR FINDLINE | ||
+ | BCC :NEWLINE | ||
+ | LDY #$01 ; | ||
+ | LDA (TEMP2), | ||
+ | STA TEMP1+1 | ||
+ | LDA VARTAB | ||
+ | STA TEMP1 ;(TEMP1) = basic end, high next | ||
+ | LDA TEMP2+1 | ||
+ | STA INDEX1+1 | ||
+ | LDA TEMP2 ;Compute -length of current line | ||
+ | | ||
+ | SBC (TEMP2), | ||
+ | | ||
+ | ADC VARTAB | ||
+ | STA VARTAB | ||
+ | STA INDEX1 | ||
+ | LDA VARTAB+1 | ||
+ | ADC #$FF | ||
+ | STA VARTAB+1 | ||
+ | SBC TEMP2+1 | ||
+ | | ||
+ | SEC | ||
+ | LDA TEMP2 ;Pretty confusing, eh? | ||
+ | SBC VARTAB | ||
+ | | ||
+ | BCS : | ||
+ | | ||
+ | DEC INDEX1+1 | ||
+ | : | ||
+ | ADC TEMP1 ;old basic end - number of bytes to move | ||
+ | BCC : | ||
+ | DEC TEMP1+1 | ||
+ | | ||
+ | : | ||
+ | STA (INDEX1), | ||
+ | | ||
+ | BNE : | ||
+ | INC TEMP1+1 | ||
+ | INC INDEX1+1 | ||
+ | | ||
+ | BNE : | ||
+ | |||
+ | :NEWLINE JSR RESCLR | ||
+ | JSR LINKPRG | ||
+ | LDA BUF | ||
+ | BEQ JMPMAIN | ||
+ | | ||
+ | LDA VARTAB | ||
+ | STA $5A | ||
+ | ADC COUNT | ||
+ | STA $58 ;Start of vars after line is added | ||
+ | LDY VARTAB+1 | ||
+ | STY $5B | ||
+ | BCC : | ||
+ | | ||
+ | : | ||
+ | JSR MALLOC | ||
+ | LDA LINNUM | ||
+ | LDY LINNUM+1 | ||
+ | STA H01FE ;Rock bottom on the stack. | ||
+ | STY H01FF | ||
+ | LDA STREND | ||
+ | LDY STREND+1 | ||
+ | STA VARTAB | ||
+ | STY VARTAB+1 | ||
+ | LDY COUNT ;Number of chars in BUF | ||
+ | | ||
+ | :LOOP LDA BUF-4, | ||
+ | STA (TEMP2), | ||
+ | | ||
+ | BPL :LOOP | ||
+ | JSR RESCLR | ||
+ | JSR LINKPRG | ||
+ | JMP JMPMAIN | ||
+ | |||
+ | * | ||
+ | * LINKPRG -- Relink lines of program text | ||
+ | * | ||
+ | * $A533 | ||
+ | LINKPRG | ||
+ | LDY TXTTAB+1 | ||
+ | STA TEMP1 | ||
+ | STY TEMP1+1 | ||
+ | | ||
+ | : | ||
+ | LDA (TEMP1), | ||
+ | BEQ :RTS ;0 means end of program | ||
+ | LDY #$04 ;Skip link, line number, and 1st char | ||
+ | : | ||
+ | LDA (TEMP1), | ||
+ | BNE : | ||
+ | | ||
+ | | ||
+ | ADC TEMP1 ;Add offset to pointer to get address | ||
+ | | ||
+ | LDY #$00 | ||
+ | STA (TEMP1), | ||
+ | LDA TEMP1+1 | ||
+ | ADC #$00 | ||
+ | | ||
+ | STA (TEMP1), | ||
+ | STX TEMP1 ;Move to next line | ||
+ | STA TEMP1+1 | ||
+ | BCC : | ||
+ | :RTS | ||
+ | |||
+ | * | ||
+ | * INLIN -- Input a line from keyboard to buffer | ||
+ | * | ||
+ | * $A560 | ||
+ | INLIN LDX #$00 | ||
+ | :LOOP JSR HE112 ; | ||
+ | CMP #$0D | ||
+ | BEQ :DONE | ||
+ | STA BUF,X | ||
+ | | ||
+ | CPX #$59 ; | ||
+ | BCC :LOOP | ||
+ | LDX #$17 ; | ||
+ | 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. | ||
+ | * | ||
+ | * | ||
+ | * 04 otherwise. | ||
+ | * | ||
+ | * 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 | ||
+ | JMP (ICRNCH) | ||
+ | LDX TXTPTR | ||
+ | LDY #$04 | ||
+ | STY GARBFL | ||
+ | | ||
+ | MAINLOOP LDA BUF,X ;Search input buffer for text | ||
+ | BPL : | ||
+ | CMP #$FF | ||
+ | BEQ STALOOP | ||
+ | | ||
+ | BNE MAINLOOP | ||
+ | | ||
+ | :GOTCHAR CMP #$20 ;Is it a space? | ||
+ | BEQ STALOOP | ||
+ | STA ENDCHR | ||
+ | CMP #$22 ;Is it a quote? | ||
+ | BEQ QUOTE2 | ||
+ | BIT GARBFL | ||
+ | ;colon was hit, $49 if a DATA | ||
+ | ;statement was found, and #04 | ||
+ | ; | ||
+ | ;text within DATA statements. | ||
+ | BVS STALOOP | ||
+ | CMP #'?' | ||
+ | BNE : | ||
+ | LDA #$99 ; | ||
+ | BNE STALOOP | ||
+ | | ||
+ | : | ||
+ | BCC : | ||
+ | CMP #'<' | ||
+ | BCC STALOOP | ||
+ | | ||
+ | : | ||
+ | LDY #$00 | ||
+ | STY COUNT | ||
+ | | ||
+ | STX TXTPTR | ||
+ | | ||
+ | | ||
+ | FINDWORD INY ;Find keyword | ||
+ | | ||
+ | CMPWORD | ||
+ | | ||
+ | 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 | ||
+ | STALOOP | ||
+ | | ||
+ | STA BUF-5, | ||
+ | LDA BUF-5, | ||
+ | BEQ ALLDONE | ||
+ | | ||
+ | SBC #$3A ;Is it a colon? | ||
+ | BEQ : | ||
+ | CMP #$49 ;Was it $83, a DATA statement? | ||
+ | BNE :SKIP | ||
+ | : | ||
+ | :SKIP SEC | ||
+ | SBC #$55 ;Was it $8F, a REM statement? | ||
+ | BNE MAINLOOP | ||
+ | STA ENDCHR | ||
+ | | ||
+ | QUOTE LDA BUF,X ;Look for matching quote char | ||
+ | BEQ STALOOP | ||
+ | CMP ENDCHR | ||
+ | BEQ STALOOP | ||
+ | QUOTE2 | ||
+ | STA BUF-5, | ||
+ | | ||
+ | BNE QUOTE | ||
+ | | ||
+ | NEXTWORD LDX TXTPTR | ||
+ | INC COUNT ;Next token | ||
+ | :LOOP INY | ||
+ | LDA RESLST-1, | ||
+ | BPL :LOOP | ||
+ | LDA RESLST, | ||
+ | BNE CMPWORD | ||
+ | LDA BUF,X | ||
+ | BPL STABUF | ||
+ | | ||
+ | ALLDONE | ||
+ | DEC TXTPTR+1 | ||
+ | LDA #$FF | ||
+ | STA TXTPTR | ||
+ | | ||
+ | |||
+ | * | ||
+ | * FINDLINE | ||
+ | * | ||
+ | * to link address and set carry. | ||
+ | * not found. | ||
+ | * | ||
+ | |||
+ | * $A613 | ||
+ | FINDLINE LDA TXTTAB | ||
+ | LDX TXTTAB+1 | ||
+ | :LOOP LDY #$01 | ||
+ | STA TEMP2 | ||
+ | STX TEMP2+1 | ||
+ | LDA (TEMP2), | ||
+ | BEQ :EXIT ;Exit if at end of program | ||
+ | | ||
+ | | ||
+ | LDA LINNUM+1 | ||
+ | CMP (TEMP2), | ||
+ | BCC :RTS ;Less than -> line doesn' | ||
+ | BEQ : | ||
+ | | ||
+ | BNE : | ||
+ | : | ||
+ | | ||
+ | CMP (TEMP2), | ||
+ | BCC :RTS ;Punt when past line number | ||
+ | BEQ :RTS ; | ||
+ | : | ||
+ | LDA (TEMP2),Y | ||
+ | | ||
+ | | ||
+ | LDA (TEMP2), | ||
+ | BCS :LOOP | ||
+ | :EXIT CLC | ||
+ | :RTS RTS | ||
+ | | ||
+ | * Perform NEW | ||
+ | * $A642 | ||
+ | NEW BNE *-2 ;RTS above | ||
+ | LDA #$00 | ||
+ | TAY | ||
+ | STA (TXTTAB), | ||
+ | | ||
+ | STA (TXTTAB), | ||
+ | LDA TXTTAB | ||
+ | | ||
+ | ADC #$02 | ||
+ | STA VARTAB | ||
+ | LDA TXTTAB+1 | ||
+ | ADC #$00 | ||
+ | STA VARTAB+1 | ||
+ | RESCLR | ||
+ | LDA #$00 | ||
+ | |||
+ | * Perform CLR (Calcium Lime and Rust remover!) | ||
+ | * $A65E | ||
+ | CLEAR BNE CLEAREND | ||
+ | JSR CLALL ;Close files | ||
+ | LDA MEMSIZ | ||
+ | LDY MEMSIZ+1 | ||
+ | STA FRETOP | ||
+ | STY FRETOP+1 | ||
+ | LDA VARTAB | ||
+ | LDY VARTAB+1 | ||
+ | STA ARYTAB | ||
+ | STY ARYTAB+1 | ||
+ | STA STREND | ||
+ | STY STREND+1 | ||
+ | JSR RESTORE | ||
+ | LDX #$19 | ||
+ | STX TEMPPT | ||
+ | | ||
+ | | ||
+ | | ||
+ | LDX #$FA ; | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | LDA #$00 | ||
+ | STA OLDTXT+1 | ||
+ | STA SUBFLG | ||
+ | CLEAREND RTS | ||
+ | |||
+ | * | ||
+ | * RUNC -- reset current text character pointer to the | ||
+ | * beginning of program text. | ||
+ | * | ||
+ | * $A68E | ||
+ | RUNC | ||
+ | LDA TXTTAB | ||
+ | ADC #$FF | ||
+ | STA TXTPTR | ||
+ | LDA TXTTAB+1 | ||
+ | ADC #$FF | ||
+ | STA TXTPTR+1 | ||
+ | | ||
+ | |||
+ | * | ||
+ | * LIST -- perform LIST | ||
+ | * entered via return from CHRGET | ||
+ | * | ||
+ | * $A69C | ||
+ | LIST BCC :SKIP ;Is next char an ASCII digit | ||
+ | BEQ :SKIP ;Is next char ':' | ||
+ | CMP #$AB ;Is next char ' | ||
+ | BNE CLEAREND | ||
+ | :SKIP JSR LINGET | ||
+ | JSR FINDLINE | ||
+ | JSR CHRGOT | ||
+ | BEQ :CONT ;statement terminator | ||
+ | CMP #$AB | ||
+ | BNE NEW-1 ;RTS | ||
+ | JSR CHRGET | ||
+ | JSR LINGET | ||
+ | BNE NEW-1 ;RTS | ||
+ | :CONT PLA | ||
+ | | ||
+ | LDA LINNUM | ||
+ | ORA LINNUM+1 | ||
+ | BNE LISTLOOP | ||
+ | LDA #$FF ; | ||
+ | STA LINNUM | ||
+ | STA LINNUM+1 | ||
+ | LISTLOOP LDY #$01 | ||
+ | STY GARBFL | ||
+ | LDA (TEMP2), | ||
+ | BEQ ENDLIST | ||
+ | JSR TESTSTOP | ||
+ | JSR HAAD7 ;part of PRINT routine | ||
+ | | ||
+ | LDA (TEMP2), | ||
+ | | ||
+ | | ||
+ | LDA (TEMP2), | ||
+ | CMP LINNUM+1 | ||
+ | BNE : | ||
+ | CPX LINNUM | ||
+ | BEQ : | ||
+ | : | ||
+ | : | ||
+ | JSR LINPRT | ||
+ | LDA #$20 ; | ||
+ | LISTENT1 LDY FORPNT | ||
+ | AND #$7F ; | ||
+ | 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 | ||
+ | LDA (TEMP2), | ||
+ | BNE JMPPLOP | ||
+ | | ||
+ | LDA (TEMP2), | ||
+ | | ||
+ | | ||
+ | LDA (TEMP2), | ||
+ | STX TEMP2 | ||
+ | STA TEMP2+1 | ||
+ | BNE LISTLOOP | ||
+ | ENDLIST | ||
+ | |||
+ | * | ||
+ | * QPLOP -- print BASIC tokens as ASCII characters. | ||
+ | * | ||
+ | * $A717 | ||
+ | JMPPLOP | ||
+ | QPLOP BPL LISTENT2 | ||
+ | CMP #$FF | ||
+ | BEQ LISTENT2 | ||
+ | BIT GARBFL | ||
+ | BMI LISTENT2 | ||
+ | | ||
+ | SBC #$7F ; | ||
+ | | ||
+ | STY FORPNT | ||
+ | LDY #$FF | ||
+ | : | ||
+ | BEQ : | ||
+ | : | ||
+ | LDA RESLST, | ||
+ | BPL : | ||
+ | BMI : | ||
+ | : | ||
+ | LDA RESLST, | ||
+ | BMI LISTENT1 | ||
+ | JSR HAB47 ;Print char, AND #$FF | ||
+ | BNE : | ||
+ | |||
+ | * | ||
+ | * Perform FOR | ||
+ | * | ||
+ | * $A742 | ||
+ | FOR LDA #$80 | ||
+ | STA SUBFLG | ||
+ | JSR LET | ||
+ | JSR FINDFOR | ||
+ | BNE :CONT | ||
+ | | ||
+ | ADC #$0F | ||
+ | | ||
+ | | ||
+ | :CONT PLA | ||
+ | | ||
+ | LDA #$09 | ||
+ | JSR CHKSTACK | ||
+ | JSR ENDSTAT | ||
+ | | ||
+ | | ||
+ | ADC TXTPTR | ||
+ | | ||
+ | LDA TXTPTR+1 | ||
+ | ADC #$00 | ||
+ | | ||
+ | LDA CURLIN+1 | ||
+ | | ||
+ | LDA CURLIN | ||
+ | | ||
+ | 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 | ||
+ | | ||
+ | LDA FORPNT | ||
+ | | ||
+ | LDA #$81 | ||
+ | | ||
+ | | ||
+ | * | ||
+ | * NEWSTT -- Set up next statement for execution. | ||
+ | * | ||
+ | * $A7AE | ||
+ | NEWSTT | ||
+ | LDA TXTPTR | ||
+ | LDY TXTPTR+1 | ||
+ | CPY #$02 ;Text buffer? | ||
+ | | ||
+ | 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), | ||
+ | | ||
+ | BNE : | ||
+ | JMP HA84B ;exit through END | ||
+ | |||
+ | : | ||
+ | LDA (TXTPTR), | ||
+ | STA CURLIN | ||
+ | | ||
+ | LDA (TXTPTR), | ||
+ | STA CURLIN+1 | ||
+ | | ||
+ | ADC TXTPTR | ||
+ | STA TXTPTR | ||
+ | BCC JMPGONE | ||
+ | INC TXTPTR+1 | ||
+ | |||
+ | * | ||
+ | * GONE -- Read and execute next statment | ||
+ | * | ||
+ | * $A7E1 | ||
+ | JMPGONE | ||
+ | JSR CHRGET | ||
+ | JSR GONE | ||
+ | JMP NEWSTT | ||
+ | * $A7ED | ||
+ | GONE BEQ :RTS ;Exit if statement terminator | ||
+ | SBC #$80 | ||
+ | BCC : | ||
+ | CMP #$23 ; | ||
+ | BCS CHKGOTO | ||
+ | | ||
+ | | ||
+ | LDA STATVEC+1, | ||
+ | | ||
+ | LDA STATVEC, | ||
+ | | ||
+ | JMP CHRGET | ||
+ | | ||
+ | : | ||
+ | | ||
+ | HA807 CMP #':' | ||
+ | BEQ JMPGONE | ||
+ | JMPSYN | ||
+ | | ||
+ | CHKGOTO | ||
+ | BNE JMPSYN | ||
+ | JSR CHRGET | ||
+ | LDA #$A4 ;Make sure next char is " | ||
+ | JSR CHKCOM | ||
+ | JMP GOTO | ||
+ | |||
+ | * | ||
+ | * Perform RESTORE | ||
+ | * | ||
+ | * $A81D | ||
+ | RESTORE | ||
+ | LDA TXTTAB | ||
+ | SBC #$01 | ||
+ | LDY TXTTAB+1 | ||
+ | BCS :CONT | ||
+ | | ||
+ | :CONT STA DATPTR | ||
+ | STY DATPTR+1 | ||
+ | :RTS | ||
+ | | ||
+ | TESTSTOP JSR STOP | ||
+ | BCS END+1 | ||
+ | |||
+ | * | ||
+ | * END -- perform END | ||
+ | * | ||
+ | * $A831 | ||
+ | END CLC | ||
+ | BNE $A870 ;RTS | ||
+ | LDA TXTPTR | ||
+ | LDY TXTPTR+1 | ||
+ | LDX CURLIN+1 | ||
+ | | ||
+ | BEQ : | ||
+ | STA OLDTXT | ||
+ | STY OLDTXT+1 | ||
+ | LDA CURLIN | ||
+ | LDY CURLIN+1 | ||
+ | STA OLDLIN | ||
+ | STY OLDLIN+1 | ||
+ | : | ||
+ | PLA | ||
+ | * $A84B | ||
+ | HA84B LDA #$81 ; | ||
+ | LDY #$A3 | ||
+ | BCC :CONT2 | ||
+ | JMP $A469 ;BREAK | ||
+ | : | ||
+ | |||
+ | | ||
+ | |||
+ | ENDCHR | ||
+ | COUNT = $0B | ||
+ | GARBFL | ||
+ | SUBFLG | ||
+ | LINNUM | ||
+ | TEMPPT | ||
+ | TEMP1 = $22 ;Temporary pointer/ | ||
+ | INDEX1 | ||
+ | TXTTAB | ||
+ | ARYTAB | ||
+ | STREND | ||
+ | FRETOP | ||
+ | MEMSIZ | ||
+ | CURLIN | ||
+ | OLDTXT | ||
+ | DATPTR | ||
+ | FORPNT | ||
+ | TEMP2 = $5F | ||
+ | FAC1 = $61 | ||
+ | FACSGN | ||
+ | TEMP1 = $71 | ||
+ | FBUFPT | ||
+ | CHRGET | ||
+ | CHRGOT | ||
+ | TXTPTR | ||
+ | H01FE = $01FE | ||
+ | H01FF = $01FF | ||
+ | BUF = $0200 ;Text input buffer | ||
+ | IMAIN = $0302 ;System vectors | ||
+ | ICRNCH | ||
+ | IQPLOP | ||
+ | IGONE = $0308 | ||
+ | STATVEC | ||
+ | RESLST | ||
+ | FINDFOR | ||
+ | MALLOC | ||
+ | CHKSTACK = $A3FB ;Check for space on stack | ||
+ | ERROR = $A437 ;General error handler | ||
+ | END = $A831 ;Perform END | ||
+ | GOTO = $A8A0 ;Perform GOTO | ||
+ | ENDSTAT | ||
+ | ;(00 or colon) | ||
+ | LINGET | ||
+ | LET = $A9A5 ;Perform LET | ||
+ | HAACA = $AACA | ||
+ | HAAD7 = $AAD7 | ||
+ | HAB47 = $AB47 | ||
+ | FRMNUM | ||
+ | HAD8D = $AD8D | ||
+ | HAE38 = $AE38 | ||
+ | HAE43 = $AE43 | ||
+ | CHKCOM | ||
+ | SYNERR | ||
+ | MTOFAC | ||
+ | SIGN = $BC2B ;Sign of FAC1 in A | ||
+ | LINPRT | ||
+ | HE112 = $E112 | ||
+ | HE386 = $E386 | ||
+ | STOP = $FFE1 ;Kernal | ||
+ | CLALL = $FFE7 | ||
+ | |||
+ | * | ||
+ | * Major routine entry points | ||
+ | * | ||
+ | * $A480 JMPMAIN | ||
+ | * $A483 MAIN JSR INLIN ;Input a line from keyboard | ||
+ | * $A49C MAIN1 JSR LINGET | ||
+ | * $A533 LINKPRG | ||
+ | * $A560 INLIN LDX #$00 | ||
+ | * $A579 CRUNCH | ||
+ | * $A613 FINDLINE LDA TXTTAB | ||
+ | * $A642 NEW BNE *-2 ;RTS above | ||
+ | * $A65E CLEAR BNE CLEAREND | ||
+ | * $A68E RUNC | ||
+ | * $A69C LIST BCC :SKIP ;Is next char an ASCII digit | ||
+ | * $A717 JMPPLOP | ||
+ | * $A71A QPLOP BPL LISTENT2 | ||
+ | * $A7AE NEWSTT | ||
+ | * $A7E1 JMPGONE | ||
+ | * $A7ED GONE BEQ :RTS ;Exit if statement terminator | ||
+ | * $A81D RESTORE | ||
+ | * $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. | ||
+ | modes, as well as double buffering. | ||
+ | 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. | ||
+ | |||
+ | Anyways, these are adaptations of my algorithms from C=Hacking and such. | ||
+ | They are not the most efficient implementations, | ||
+ | and fairly well beat the snot out of BASIC7.0 commands! | ||
+ | the times from moire3 (a line drawing test): | ||
+ | |||
+ | Stock 64 1200 jiffies | ||
+ | SCPU Mode 17 137 jiffies | ||
+ | SCPU Mode 16 59 jiffies | ||
+ | BASIC7.0 (1MHz) 4559 jiffies | ||
+ | |||
+ | 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. | ||
+ | talk about them :) | ||
+ | circletest1: | ||
+ | Stock 64 360 jiffies | ||
+ | SCPU Mode 17 50 jiffies | ||
+ | SCPU Mode 16 22 jiffies | ||
+ | BASIC7.0 | ||
+ | |||
+ | 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. | ||
+ | the system (after a warm reset for instance) just type SYS49152. | ||
+ | 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. | ||
+ | load ,8,1 and type SYS32768 to initialize. | ||
+ | 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, | ||
+ | break the program before it can tell VIC where the screen | ||
+ | is located). | ||
+ | whereas run/ | ||
+ | |||
+ | 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. | ||
+ | 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, | ||
+ | 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). | ||
+ | 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). | ||
+ | may be any 8-bit value. | ||
+ | simply not be plotted! | ||
+ | |||
+ | CIRCLE XC,YC,R -- Draws a circle of radius R centered at XC,YC | ||
+ | (translating as necessary). | ||
+ | handle R=0..255 correctly (as far as I know!). | ||
+ | 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. | ||
+ | |||
+ | 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-> | ||
+ | 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? | ||
+ | with BITMASK. | ||
+ | (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. | ||
+ | possible to draw in one buffer while displaying the other. | ||
+ | BUFFER n selects which buffer the PLOT, | ||
+ | commands will affect. | ||
+ | buffer. | ||
+ | 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, | ||
+ | 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 | ||
+ | IERROR | ||
+ | ICRUNCH | ||
+ | IQPLOP | ||
+ | IGONE = $0308 ;Execute next BASIC token | ||
+ | | ||
+ | CHRGET | ||
+ | CHRGOT | ||
+ | CHROUT | ||
+ | GETBYT | ||
+ | GETPAR | ||
+ | CHKCOM | ||
+ | NEW = $A642 | ||
+ | CLR = $A65E | ||
+ | | ||
+ | LINNUM | ||
+ | | ||
+ | TEMP = $FF | ||
+ | TEMP2 = $FB | ||
+ | POINT = $FD | ||
+ | Y1 = $05 | ||
+ | X1 = LINNUM | ||
+ | X2 = $02 | ||
+ | Y2 = $04 | ||
+ | DY = $26 | ||
+ | DX = $27 | ||
+ | BUF = $0200 ;Input buffer | ||
+ | | ||
+ | CHUNK1 | ||
+ | OLDCH1 | ||
+ | CHUNK2 | ||
+ | OLDCH2 | ||
+ | CX = $A3 | ||
+ | CY = $A5 | ||
+ | X = $6D | ||
+ | Y = $6E | ||
+ | RADIUS | ||
+ | LCOL = $A6 ;Left column | ||
+ | RCOL = $A7 | ||
+ | TROW = $A8 ;Top row | ||
+ | BROW = $A9 ;Bottom row | ||
+ | | ||
+ | | ||
+ | | ||
+ | DA :LINK ;link | ||
+ | DA 1997 | ||
+ | DFB $9E ;SYS | ||
+ | TXT ' | ||
+ | DFB $A2 ;NEW | ||
+ | DFB 00 ;End of line | ||
+ | :LINK DA 0 ;end of program | ||
+ | | ||
+ | INSTALL | ||
+ | STA POINT | ||
+ | LDA #> | ||
+ | STA POINT+1 | ||
+ | LDA #< | ||
+ | | ||
+ | SBC #< | ||
+ | STA TEMP2 | ||
+ | LDA #> | ||
+ | SBC #> | ||
+ | STA TEMP2+1 | ||
+ | LDA #$C0 ;Copy to $C000 | ||
+ | STA X2+1 | ||
+ | LDY #00 | ||
+ | STY X2 | ||
+ | :LOOP LDA (POINT), | ||
+ | STA (X2), | ||
+ | | ||
+ | BNE :LOOP | ||
+ | INC POINT+1 | ||
+ | INC X2+1 | ||
+ | DEC TEMP2+1 | ||
+ | BNE :LOOP | ||
+ | LDY TEMP2 | ||
+ | : | ||
+ | STA (X2), | ||
+ | | ||
+ | CPY #$FF | ||
+ | BNE : | ||
+ | LDX #5 ;Copy CURRENT vectors | ||
+ | : | ||
+ | STA OLDCRNCH, | ||
+ | | ||
+ | BPL : | ||
+ | JMP INIT | ||
+ | | ||
+ | TXT 'so, you want a secret message, eh? ' | ||
+ | TXT ' | ||
+ | TXT ' love. think. speak. be walking trees.' | ||
+ | TXT ' be talking beasts. be divine waters.' | ||
+ | TXT ' | ||
+ | | ||
+ | PBEGIN | ||
+ | ORG $C000 | ||
+ | | ||
+ | * | ||
+ | * Init routine -- modify vectors | ||
+ | * and set up values. | ||
+ | * | ||
+ | INIT | ||
+ | LDX #5 ;Copy vectors | ||
+ | :LOOP LDA : | ||
+ | STA ICRUNCH, | ||
+ | | ||
+ | BPL :LOOP | ||
+ | | ||
+ | STX ORGX | ||
+ | STX ORGY | ||
+ | |||
+ | JMP MODE17 | ||
+ | :TEMP DFB 05 | ||
+ | : | ||
+ | DA LIST | ||
+ | DA EXECUTE | ||
+ | JMPCRUN | ||
+ | OLDCRNCH DS 2 ;Old CRUNCH vector | ||
+ | OLDLIST | ||
+ | OLDEXEC | ||
+ | | ||
+ | * | ||
+ | * 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 ' | ||
+ | TXT ' | ||
+ | TXT ' | ||
+ | TXT ' | ||
+ | TXT ' | ||
+ | TXT ' | ||
+ | DFB $B0 ;OR | ||
+ | TXT ' | ||
+ | TXT ' | ||
+ | TXT ' | ||
+ | TXT ' | ||
+ | TXT ' | ||
+ | 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 | ||
+ | | ||
+ | * | ||
+ | * CRUNCH -- If this is one of our keywords, then tokenize it | ||
+ | * | ||
+ | CRUNCH | ||
+ | JSR JMPCRUN | ||
+ | LDY #05 ;Offset for KERNAL | ||
+ | ;Y will contain line length+5 | ||
+ | :LOOP STY TEMP | ||
+ | JSR ISWORD | ||
+ | BCS : | ||
+ | :NEXT | ||
+ | JSR NEXTCHAR | ||
+ | BNE :LOOP ;Null byte marks end | ||
+ | STA BUF-3, | ||
+ | LDA #$FF ;' | ||
+ | | ||
+ | * Insert token and crunch line | ||
+ | : | ||
+ | LDX TEMP ;If so, A contains opcode | ||
+ | STA BUF-5, | ||
+ | :MOVE INX | ||
+ | LDA BUF-5, | ||
+ | STA BUF-5, | ||
+ | BEQ :NEXT | ||
+ | | ||
+ | BPL :MOVE | ||
+ | | ||
+ | * | ||
+ | * ISWORD -- Checks to see if word is | ||
+ | * in table. | ||
+ | * C is set, Y is one past the last char | ||
+ | * and A contains opcode. | ||
+ | * carry is clear. | ||
+ | * | ||
+ | * On entry, TEMP must contain current | ||
+ | * character position. | ||
+ | * | ||
+ | ISWORD | ||
+ | LDX #00 | ||
+ | :LOOP LDY TEMP | ||
+ | : | ||
+ | BEQ : | ||
+ | CMP #$E0 | ||
+ | BCS :RTS ; | ||
+ | CMP BUF-5, | ||
+ | BNE :NEXT | ||
+ | | ||
+ | | ||
+ | BNE : | ||
+ | :NEXT | ||
+ | | ||
+ | LDA KEYWORDS, | ||
+ | CMP #$E0 | ||
+ | BCC :NEXT | ||
+ | | ||
+ | BNE :LOOP ;And check again | ||
+ | :NOTMINE CLC | ||
+ | :RTS | ||
+ | | ||
+ | * | ||
+ | * NEXTCHAR finds the next char | ||
+ | * in the buffer, skipping | ||
+ | * spaces and quotes. | ||
+ | * 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 | ||
+ | : | ||
+ | LDA BUF-5, | ||
+ | BEQ :DONE | ||
+ | CMP TEMP2 | ||
+ | BNE : | ||
+ | BEQ :LOOP | ||
+ | :CONT | ||
+ | CMP #$20 ; | ||
+ | BEQ :LOOP | ||
+ | CMP #$22 ; | ||
+ | BEQ :SKIP | ||
+ | :DONE RTS | ||
+ | | ||
+ | * | ||
+ | * LIST -- patches the LIST routine | ||
+ | * to list my tokens correctly. | ||
+ | * | ||
+ | LIST | ||
+ | CMP #$E0 | ||
+ | BCC : | ||
+ | CMP # | ||
+ | BCS : | ||
+ | BIT $0F ;Check for quote mode | ||
+ | BMI : | ||
+ | | ||
+ | SBC #$DF ;Find the corresponding text | ||
+ | | ||
+ | STY $49 | ||
+ | LDY #00 | ||
+ | :LOOP DEX | ||
+ | BEQ :DONE | ||
+ | : | ||
+ | LDA KEYWORDS, | ||
+ | CMP #$E0 | ||
+ | BCC : | ||
+ | | ||
+ | BNE :LOOP | ||
+ | :DONE LDA KEYWORDS, | ||
+ | BMI :OUT | ||
+ | JSR $FFD2 | ||
+ | | ||
+ | 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) | ||
+ | :CONT LDY $49 | ||
+ | JMP $A700 ;Normal exit | ||
+ | :OR LDA #' | ||
+ | JSR CHROUT | ||
+ | LDA #' | ||
+ | JSR CHROUT | ||
+ | | ||
+ | BNE :DONE | ||
+ | | ||
+ | * | ||
+ | * EXECUTE -- if this is one of my | ||
+ | * tokens, then execute it. | ||
+ | * | ||
+ | EXECUTE | ||
+ | JSR CHRGET | ||
+ | | ||
+ | CMP #$E0 | ||
+ | BCC : | ||
+ | CMP # | ||
+ | BCS : | ||
+ | | ||
+ | JSR :DISP | ||
+ | JMP $A7AE ;Exit through NEWSTT | ||
+ | :DISP | ||
+ | EOR #$E0 | ||
+ | | ||
+ | | ||
+ | LDA TOKENLOC+1, | ||
+ | | ||
+ | LDA TOKENLOC, | ||
+ | | ||
+ | JMP CHRGET | ||
+ | :NOTMINE PLP | ||
+ | JMP $A7E7 ;Normal routine | ||
+ | | ||
+ | * | ||
+ | * PLOT -- plot a point! | ||
+ | * | ||
+ | ORGX DFB 00 ; | ||
+ | ORGY DFB 00 | ||
+ | DONTPLOT DFB 01 ; | ||
+ | ; | ||
+ | | ||
+ | PLOT | ||
+ | JSR GETPAR | ||
+ | LDA LINNUM | ||
+ | | ||
+ | SBC ORGX | ||
+ | STA LINNUM | ||
+ | BCS : | ||
+ | DEC LINNUM+1 | ||
+ | BMI : | ||
+ | | ||
+ | : | ||
+ | SBC ORGY | ||
+ | BCC : | ||
+ | | ||
+ | CPX #200 ; | ||
+ | BCS : | ||
+ | LDA LINNUM | ||
+ | CMP #< | ||
+ | LDA LINNUM+1 | ||
+ | SBC #> | ||
+ | BCC SETPOINT | ||
+ | : | ||
+ | *:ERROR LDX #14 | ||
+ | * JMP (IERROR) | ||
+ | SETPOINT | ||
+ | ;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. | ||
+ | | ||
+ | AND #248 | ||
+ | STA POINT | ||
+ | | ||
+ | | ||
+ | | ||
+ | ADC BASE ;Base of bitmap | ||
+ | STA POINT+1 | ||
+ | LDA #00 | ||
+ | ASL POINT | ||
+ | | ||
+ | ASL POINT | ||
+ | | ||
+ | ASL POINT | ||
+ | | ||
+ | ADC LINNUM+1 | ||
+ | ADC POINT+1 | ||
+ | STA POINT+1 | ||
+ | | ||
+ | AND #7 | ||
+ | | ||
+ | LDA LINNUM | ||
+ | AND #248 | ||
+ | | ||
+ | ADC POINT | ||
+ | STA POINT | ||
+ | BCC SETPIXEL | ||
+ | INC POINT+1 | ||
+ | SETPIXEL | ||
+ | LDA LINNUM | ||
+ | AND #$07 | ||
+ | | ||
+ | LDA DONTPLOT | ||
+ | BEQ :RTS | ||
+ | LDA POINT+1 | ||
+ | | ||
+ | SBC BASE ; | ||
+ | CMP #$20 | ||
+ | BCS :RTS | ||
+ | | ||
+ | LDA #$34 | ||
+ | STA $01 | ||
+ | | ||
+ | LDA (POINT), | ||
+ | EOR BITMASK | ||
+ | AND BITTAB, | ||
+ | EOR (POINT), | ||
+ | STA (POINT), | ||
+ | | ||
+ | LDA #$37 | ||
+ | STA $01 | ||
+ | | ||
+ | * LDX TEMP2 | ||
+ | * LDY TEMP2+1 | ||
+ | ;On exit, X,Y are AND #$07 | ||
+ | ;i.e. are set up correctly. | ||
+ | ;for more plotting | ||
+ | :RTS | ||
+ | | ||
+ | BITMASK | ||
+ | BITTAB | ||
+ | | ||
+ | *------------------------------- | ||
+ | * Drawin' | ||
+ | * | ||
+ | * To deal with off-screen coordinates, | ||
+ | * 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 | ||
+ | | ||
+ | : | ||
+ | | ||
+ | SBC X1 | ||
+ | | ||
+ | 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 : | ||
+ | | ||
+ | :CONT STA DX+1 | ||
+ | STX DX | ||
+ | | ||
+ | LDX #$C8 ;INY | ||
+ | LDA Y2 ; | ||
+ | | ||
+ | SBC Y1 | ||
+ | BCS : | ||
+ | EOR #$FF ; | ||
+ | ADC #$01 | ||
+ | LDX #$88 ;DEY | ||
+ | | ||
+ | : | ||
+ | STX YINCDEC | ||
+ | STX XINCDEC | ||
+ | | ||
+ | LDA X1 ;Sub origin from 1st point | ||
+ | | ||
+ | SBC ORGX | ||
+ | STA X1 | ||
+ | LDA X1+1 | ||
+ | SBC #00 | ||
+ | STA X1+1 | ||
+ | | ||
+ | STA TEMP ;Next compute column | ||
+ | LDA X1 | ||
+ | LSR TEMP | ||
+ | | ||
+ | LSR TEMP | ||
+ | | ||
+ | LSR TEMP | ||
+ | | ||
+ | STA CX ; | ||
+ | | ||
+ | BCC :NEGX ;If negative, then fix up | ||
+ | CMP #40 ;If past column 40, then punt! | ||
+ | BCC : | ||
+ | | ||
+ | :NEGX LDA X1 ; | ||
+ | AND #$07 | ||
+ | STA X1 | ||
+ | LDA #00 | ||
+ | STA X1+1 | ||
+ | LDA CX | ||
+ | | ||
+ | : | ||
+ | | ||
+ | SBC ORGY | ||
+ | STA Y1 | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | STA CY ; | ||
+ | | ||
+ | BCC :NEGY ;If negative, then fix stuff up! | ||
+ | SBC #25 ;Check if we are past bottom of | ||
+ | BCC : | ||
+ | ORA #$80 ; | ||
+ | STA CY ;(for plot range checking) | ||
+ | | ||
+ | AND #$07 | ||
+ | ORA #8*24 ;Start in last row | ||
+ | | ||
+ | BMI : | ||
+ | :NEGY ORA #$E0 ;Set high bits of column | ||
+ | STA CY | ||
+ | | ||
+ | AND #$07 | ||
+ | | ||
+ | : | ||
+ | | ||
+ | LDA #00 | ||
+ | STA DONTPLOT | ||
+ | JSR SETPOINT | ||
+ | INC DONTPLOT | ||
+ | LDA BITCHUNK, | ||
+ | STA OLDCHUNK | ||
+ | STA CHUNK | ||
+ | | ||
+ | | ||
+ | LDA #$34 | ||
+ | STA $01 | ||
+ | | ||
+ | LDX DY | ||
+ | CPX DX ; | ||
+ | BCC STEPINX | ||
+ | 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 | ||
+ | LDA CHUNK | ||
+ | | ||
+ | | ||
+ | EOR CHUNK | ||
+ | STA CHUNK | ||
+ | | ||
+ | BNE :CONT ;If dy=0 it's just a point | ||
+ | | ||
+ | :CONT LSR ;Init counter to dy/2 | ||
+ | * | ||
+ | * Main loop | ||
+ | * | ||
+ | YLOOP STA TEMP | ||
+ | * JSR LINEPLOT | ||
+ | | ||
+ | LDA CX ; | ||
+ | ORA CY | ||
+ | BMI :SKIP | ||
+ | | ||
+ | LDA (POINT), | ||
+ | EOR BITMASK | ||
+ | AND CHUNK | ||
+ | EOR (POINT), | ||
+ | STA (POINT), | ||
+ | :SKIP | ||
+ | YINCDEC | ||
+ | CPY #8 | ||
+ | BCC :CONT ;No prob if Y=0..7 | ||
+ | JSR FIXY | ||
+ | :CONT LDA TEMP ; | ||
+ | | ||
+ | SBC DX | ||
+ | BCC YFIXX | ||
+ | YCONT DEX ;X is counter | ||
+ | BNE YLOOP | ||
+ | YCONT2 | ||
+ | EOR BITMASK | ||
+ | AND CHUNK | ||
+ | EOR (POINT), | ||
+ | STA (POINT), | ||
+ | YDONE | ||
+ | LDA #$37 | ||
+ | STA $01 | ||
+ | | ||
+ | | ||
+ | | ||
+ | YFIXX ; | ||
+ | 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 ; | ||
+ | LDA TEMP2 | ||
+ | | ||
+ | BNE YLOOP | ||
+ | BEQ YCONT2 | ||
+ | | ||
+ | * | ||
+ | * Big steps in X direction | ||
+ | * | ||
+ | * On entry, X=DY=number of loop iterations, and Y= | ||
+ | * Y1 AND #$07 | ||
+ | | ||
+ | COUNTHI | ||
+ | ;only used once | ||
+ | STEPINX | ||
+ | LDX DX | ||
+ | LDA DX+1 | ||
+ | STA COUNTHI | ||
+ | | ||
+ | STA Y1 ;High byte of counter | ||
+ | | ||
+ | BNE :CONT ;Could be $100 | ||
+ | DEC COUNTHI | ||
+ | :CONT ROR | ||
+ | * | ||
+ | * Main loop | ||
+ | * | ||
+ | XLOOP | ||
+ | LSR CHUNK | ||
+ | BEQ XFIXC ;If we pass a column boundary... | ||
+ | XCONT1 | ||
+ | BCC XFIXY ;Time to step in Y? | ||
+ | XCONT2 | ||
+ | BNE XLOOP | ||
+ | DEC COUNTHI | ||
+ | BPL XLOOP | ||
+ | XDONE | ||
+ | LSR CHUNK ;Advance to last point | ||
+ | JSR LINEPLOT | ||
+ | EXIT LDA #$37 | ||
+ | STA $01 | ||
+ | | ||
+ | | ||
+ | * | ||
+ | * 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 ; | ||
+ | BPL XCONT2 | ||
+ | ADC DX | ||
+ | STA TEMP | ||
+ | LDA DX+1 | ||
+ | ADC #$FF ;Hi byte | ||
+ | STA Y1 | ||
+ | | ||
+ | JSR LINEPLOT | ||
+ | LDA CHUNK | ||
+ | STA OLDCHUNK | ||
+ | | ||
+ | LDA TEMP | ||
+ | XINCDEC | ||
+ | CPY #8 ;0..7 is ok | ||
+ | BCC XCONT2 | ||
+ | STA TEMP | ||
+ | JSR FIXY | ||
+ | LDA TEMP | ||
+ | JMP XCONT2 | ||
+ | | ||
+ | * | ||
+ | * Subroutine to plot chunks/ | ||
+ | * room, gray hair, etc.) | ||
+ | * | ||
+ | LINEPLOT | ||
+ | | ||
+ | LDA CX | ||
+ | ORA CY | ||
+ | BMI :SKIP | ||
+ | | ||
+ | LDA (POINT), | ||
+ | EOR BITMASK | ||
+ | ORA CHUNK | ||
+ | AND OLDCHUNK | ||
+ | EOR CHUNK | ||
+ | EOR (POINT), | ||
+ | STA (POINT), | ||
+ | :SKIP | ||
+ | | ||
+ | | ||
+ | * | ||
+ | * Subroutine to fix up pointer when Y decreases through | ||
+ | * zero or increases through 7. | ||
+ | * | ||
+ | FIXY CPY #255 ; | ||
+ | BEQ : | ||
+ | : | ||
+ | LDY #0 ;Y increased through 7 | ||
+ | LDA CY | ||
+ | BMI : | ||
+ | CMP #24 | ||
+ | BCS : | ||
+ | LDA POINT | ||
+ | ADC #< | ||
+ | STA POINT | ||
+ | LDA POINT+1 | ||
+ | ADC #> | ||
+ | STA POINT+1 | ||
+ | : | ||
+ | | ||
+ | : | ||
+ | LDY #7 ;Y decreased through 0 | ||
+ | LDA CY | ||
+ | BEQ : | ||
+ | BMI : | ||
+ | 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 | ||
+ | | ||
+ | SBC #< | ||
+ | STA POINT | ||
+ | LDA POINT+1 | ||
+ | SBC #> | ||
+ | STA POINT+1 | ||
+ | : | ||
+ | | ||
+ | : | ||
+ | | ||
+ | JMP EXIT ; | ||
+ | | ||
+ | * | ||
+ | * CIRCLE draws a circle of course, using my | ||
+ | * super-sneaky algorithm. | ||
+ | * | ||
+ | * | ||
+ | | ||
+ | CIRCLE | ||
+ | JSR GETPAR | ||
+ | STX CY ; | ||
+ | | ||
+ | LDA X1 | ||
+ | | ||
+ | SBC ORGX | ||
+ | STA CX | ||
+ | STA X1 | ||
+ | LDA X1+1 | ||
+ | SBC #00 | ||
+ | STA CX+1 | ||
+ | STA X1+1 | ||
+ | | ||
+ | | ||
+ | LDA CX ;in | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | BCS :CONT ;Underflow means negative column | ||
+ | | ||
+ | LDA X1 ;Set X to first column | ||
+ | AND #$07 | ||
+ | STA X1 | ||
+ | LDA #00 | ||
+ | STA X1+1 | ||
+ | | ||
+ | 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 | ||
+ | STX Y | ||
+ | STX RADIUS | ||
+ | | ||
+ | BNE :C ;Skip R=0 | ||
+ | LDX CY | ||
+ | JMP SETPOINT | ||
+ | :C | ||
+ | ADC CY | ||
+ | BCS :BLAH | ||
+ | | ||
+ | SBC ORGY | ||
+ | BCS :C4 ; | ||
+ | :RTS | ||
+ | | ||
+ | :BLAH SBC ORGY ; | ||
+ | BCS :C3 ;Handle overflow sneaky | ||
+ | :C4 TAX | ||
+ | CMP #200 ;If Y>200 then set pointer to | ||
+ | BCC :C2 ;last row, but set TROW | ||
+ | | ||
+ | :C3 TAY | ||
+ | AND #$07 | ||
+ | ORA #$C0 ;Last row, set Y1 correctly | ||
+ | | ||
+ | | ||
+ | :C2 ROR | ||
+ | | ||
+ | | ||
+ | STA TROW ;Top row | ||
+ | | ||
+ | LDA #00 | ||
+ | STA DONTPLOT | ||
+ | JSR SETPOINT | ||
+ | STY Y2 ;Y AND 07 | ||
+ | LDA BITCHUNK, | ||
+ | STA CHUNK1 | ||
+ | STA OLDCH1 | ||
+ | | ||
+ | EOR #$FF | ||
+ | STA CHUNK2 | ||
+ | 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 | ||
+ | | ||
+ | SBC ORGY | ||
+ | BCS :CSET | ||
+ | | ||
+ | SBC Y | ||
+ | | ||
+ | BCC :BNEG | ||
+ | :CSET SBC Y ;Compute CY-Y-ORGY | ||
+ | :BNEG PHP | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | STA BROW | ||
+ | | ||
+ | BCS :CONT | ||
+ | ORA #$E0 ;Make row negative | ||
+ | STA BROW | ||
+ | | ||
+ | AND #07 ;Handle underflow special! | ||
+ | | ||
+ | :CONT JSR SETPOINT | ||
+ | STY Y1 | ||
+ | LDA POINT | ||
+ | STA X1 ;X1 will be the backwards | ||
+ | LDA POINT+1 | ||
+ | STA X1+1 ; | ||
+ | | ||
+ | | ||
+ | LDA #$34 | ||
+ | STA $01 | ||
+ | | ||
+ | LDA Y | ||
+ | | ||
+ | LDX #00 | ||
+ | STX X ;y=0 | ||
+ | | ||
+ | * Main loop | ||
+ | | ||
+ | :LOOP | ||
+ | INC X ;x=x+1 | ||
+ | | ||
+ | LSR CHUNK1 | ||
+ | BNE : | ||
+ | JSR UPCHUNK1 | ||
+ | : | ||
+ | BNE : | ||
+ | JSR UPCHUNK2 | ||
+ | : | ||
+ | | ||
+ | SBC X ;a=a-x | ||
+ | BCS :LOOP | ||
+ | | ||
+ | ADC Y ;if a<0 then a=a+y; y=y-1 | ||
+ | | ||
+ | JSR PCHUNK1 | ||
+ | JSR PCHUNK2 | ||
+ | LDA CHUNK1 | ||
+ | STA OLDCH1 | ||
+ | LDA CHUNK2 | ||
+ | STA OLDCH2 | ||
+ | | ||
+ | | ||
+ | DEC Y ;(y=y-1) | ||
+ | | ||
+ | DEC Y2 ; | ||
+ | BPL : | ||
+ | JSR DECYOFF | ||
+ | : | ||
+ | | ||
+ | STY Y1 | ||
+ | CPY #8 | ||
+ | BCC : | ||
+ | JSR INCYOFF | ||
+ | : | ||
+ | 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 | ||
+ | ASL OLDCH2 | ||
+ | LDA RADIUS | ||
+ | | ||
+ | EOR #$FF | ||
+ | :LOOP | ||
+ | | ||
+ | JSR PCHUNK1 | ||
+ | JSR PCHUNK2 | ||
+ | | ||
+ | DEC Y2 ; | ||
+ | BPL : | ||
+ | JSR DECYOFF | ||
+ | : | ||
+ | LDY Y1 | ||
+ | CPY #8 | ||
+ | BCC : | ||
+ | JSR INCYOFF | ||
+ | : | ||
+ | LDX Y | ||
+ | BEQ :DONE | ||
+ | | ||
+ | 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 : | ||
+ | | ||
+ | JSR UPCH1 ;Upchunk, but no plot | ||
+ | : | ||
+ | ASL CHUNK2 | ||
+ | BNE : | ||
+ | | ||
+ | JSR UPCH2 | ||
+ | : | ||
+ | BCS :LOOP | ||
+ | :DONE | ||
+ | CIRCEXIT | ||
+ | LDA #$37 | ||
+ | STA $01 | ||
+ | | ||
+ | LDA #1 ; | ||
+ | STA DONTPLOT | ||
+ | | ||
+ | * | ||
+ | * Decrement upper pointers | ||
+ | * | ||
+ | DECYOFF | ||
+ | | ||
+ | LDA #7 | ||
+ | STA Y2 | ||
+ | LDA TROW ; | ||
+ | BEQ EXIT2 | ||
+ | CMP #25 ;range (rows 0-24) | ||
+ | BCS :SKIP | ||
+ | LDA X2 ;If we pass through zero, then | ||
+ | | ||
+ | SBC #< | ||
+ | STA X2 | ||
+ | LDA X2+1 | ||
+ | SBC #> | ||
+ | STA X2+1 | ||
+ | LDA TEMP2 | ||
+ | | ||
+ | SBC #< | ||
+ | STA TEMP2 | ||
+ | LDA TEMP2+1 | ||
+ | SBC #> | ||
+ | STA TEMP2+1 | ||
+ | :SKIP TYA | ||
+ | DEC TROW | ||
+ | | ||
+ | EXIT2 PLA ;Grab return address | ||
+ | | ||
+ | JMP CIRCEXIT | ||
+ | | ||
+ | * Increment lower pointers | ||
+ | INCYOFF | ||
+ | | ||
+ | LDA #00 | ||
+ | STA Y1 | ||
+ | LDA BROW | ||
+ | BMI : | ||
+ | CMP #24 ;If we hit bottom of screen then | ||
+ | BEQ EXIT2 ;just quit | ||
+ | LDA X1 | ||
+ | | ||
+ | ADC #< | ||
+ | STA X1 | ||
+ | LDA X1+1 | ||
+ | ADC #> | ||
+ | STA X1+1 | ||
+ | LDA POINT | ||
+ | | ||
+ | ADC #< | ||
+ | STA POINT | ||
+ | LDA POINT+1 | ||
+ | ADC #> | ||
+ | STA POINT+1 | ||
+ | : | ||
+ | INC BROW | ||
+ | | ||
+ | | ||
+ | * | ||
+ | * UPCHUNK1 -- Update right-moving chunk pointers | ||
+ | * Due to passing through a column | ||
+ | * | ||
+ | UPCHUNK1 | ||
+ | | ||
+ | JSR PCHUNK1 | ||
+ | UPCH1 LDA #$FF ; | ||
+ | STA CHUNK1 | ||
+ | STA OLDCH1 | ||
+ | LDA RCOL | ||
+ | BMI :DONE ;Can start negative | ||
+ | LDA TEMP2 | ||
+ | | ||
+ | ADC #8 | ||
+ | STA TEMP2 | ||
+ | BCC :CONT | ||
+ | INC TEMP2+1 | ||
+ | | ||
+ | :CONT LDA POINT | ||
+ | ADC #8 | ||
+ | STA POINT | ||
+ | BCC :DONE | ||
+ | INC POINT+1 | ||
+ | :DONE TXA | ||
+ | INC RCOL | ||
+ | | ||
+ | | ||
+ | * | ||
+ | * UPCHUNK2 -- Update left-moving chunk pointers | ||
+ | * | ||
+ | UPCHUNK2 | ||
+ | | ||
+ | JSR PCHUNK2 | ||
+ | UPCH2 LDA #$FF | ||
+ | STA CHUNK2 | ||
+ | STA OLDCH2 | ||
+ | LDA LCOL | ||
+ | CMP #40 | ||
+ | BCS :DONE | ||
+ | LDA X2 | ||
+ | | ||
+ | SBC #8 | ||
+ | STA X2 | ||
+ | BCS :CONT | ||
+ | DEC X2+1 | ||
+ | | ||
+ | :CONT LDA X1 | ||
+ | SBC #8 | ||
+ | STA X1 | ||
+ | BCS :DONE | ||
+ | DEC X1+1 | ||
+ | :DONE TXA | ||
+ | DEC LCOL | ||
+ | | ||
+ | * | ||
+ | * Plot right-moving chunk pairs for circle routine | ||
+ | * | ||
+ | PCHUNK1 | ||
+ | | ||
+ | LDA RCOL ;Make sure we're in range | ||
+ | CMP #40 | ||
+ | BCS : | ||
+ | LDA CHUNK1 | ||
+ | EOR OLDCH1 | ||
+ | STA TEMP | ||
+ | LDA BROW ; | ||
+ | BMI :SKIP | ||
+ | LDY Y1 | ||
+ | LDA (POINT), | ||
+ | EOR BITMASK | ||
+ | AND TEMP | ||
+ | EOR (POINT), | ||
+ | STA (POINT), | ||
+ | | ||
+ | :SKIP LDA TROW ;If CY+Y >= 200... | ||
+ | CMP #25 | ||
+ | BCS : | ||
+ | LDY Y2 | ||
+ | LDA (TEMP2), | ||
+ | EOR BITMASK | ||
+ | AND TEMP | ||
+ | EOR (TEMP2), | ||
+ | STA (TEMP2), | ||
+ | : | ||
+ | | ||
+ | | ||
+ | * | ||
+ | * Plot left-moving chunk pairs for circle routine | ||
+ | * | ||
+ | PCHUNK2 | ||
+ | | ||
+ | LDA LCOL ; | ||
+ | CMP #40 | ||
+ | BCS : | ||
+ | LDA CHUNK2 | ||
+ | EOR OLDCH2 | ||
+ | STA TEMP | ||
+ | LDA BROW ; | ||
+ | BMI :SKIP | ||
+ | LDY Y1 | ||
+ | LDA (X1), | ||
+ | EOR BITMASK | ||
+ | AND TEMP | ||
+ | EOR (X1), | ||
+ | STA (X1), | ||
+ | | ||
+ | :SKIP LDA TROW ;If CY+Y >= 200... | ||
+ | CMP #25 | ||
+ | BCS : | ||
+ | LDY Y2 | ||
+ | LDA (X2), | ||
+ | EOR BITMASK | ||
+ | AND TEMP | ||
+ | EOR (X2), | ||
+ | STA (X2), | ||
+ | : | ||
+ | | ||
+ | | ||
+ | * | ||
+ | * 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 | ||
+ | OLDD018 | ||
+ | | ||
+ | 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 | ||
+ | | ||
+ | AND #$03 | ||
+ | STA OLDBANK | ||
+ | | ||
+ | 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 | ||
+ | BEQ GRONDONE | ||
+ | JSR GETBYT | ||
+ | CLEARCOL LDA #00 ;Low byte of base address | ||
+ | STA POINT | ||
+ | LDA BASE ; | ||
+ | | ||
+ | SBC #$14 | ||
+ | STA POINT+1 | ||
+ | | ||
+ | LDY #00 | ||
+ | LDX #4 | ||
+ | :LOOP STA (POINT), | ||
+ | | ||
+ | BNE :LOOP | ||
+ | INC POINT+1 | ||
+ | | ||
+ | BNE :LOOP | ||
+ | LDA BASE ;Now clear bitmap | ||
+ | STA POINT+1 | ||
+ | LDX #32 | ||
+ | | ||
+ | : | ||
+ | | ||
+ | BNE : | ||
+ | INC POINT+1 | ||
+ | | ||
+ | BNE : | ||
+ | | ||
+ | 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 # | ||
+ | STA $D011 | ||
+ | GDONE RTS | ||
+ | | ||
+ | * | ||
+ | * COLOR -- Set drawing color | ||
+ | * | ||
+ | COLOR | ||
+ | JSR GETBYT | ||
+ | COLENT | ||
+ | BEQ :C2 | ||
+ | :C1 CPX #01 | ||
+ | BNE :RTS | ||
+ | LDX #$FF | ||
+ | :C2 STX BITMASK | ||
+ | :RTS | ||
+ | | ||
+ | * | ||
+ | * MODE -- catch-all command. | ||
+ | * | ||
+ | * | ||
+ | * | ||
+ | * | ||
+ | * | ||
+ | * | ||
+ | * Anything else -> BITMASK | ||
+ | * | ||
+ | MODENUM | ||
+ | MODE | ||
+ | JSR GETBYT | ||
+ | CPX #2 | ||
+ | BCC COLENT | ||
+ | :C16 CPX #16 | ||
+ | BNE :C18 | ||
+ | STX MODENUM | ||
+ | : | ||
+ | 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 ; | ||
+ | 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 | ||
+ | | ||
+ | :C18 CPX #18 ; | ||
+ | BNE :C17 | ||
+ | STX MODENUM | ||
+ | JSR : | ||
+ | STA $D07E | ||
+ | STA $D077 ;Turn off optimization | ||
+ | STA $D07F | ||
+ | | ||
+ | :C17 CPX #17 | ||
+ | BNE MODEDONE | ||
+ | MODE17 | ||
+ | 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 ; | ||
+ | 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 | ||
+ | | ||
+ | MODEDONE STX BITMASK | ||
+ | | ||
+ | | ||
+ | | ||
+ | * | ||
+ | * BUFFER -- Sets the current drawing buffer to 1 or 2, | ||
+ | * | ||
+ | * | ||
+ | * | ||
+ | * Now, buffer=0 swaps draw buffers, even/odd otherwise. | ||
+ | * | ||
+ | BUFFER | ||
+ | JSR GETBYT | ||
+ | LDA MODENUM | ||
+ | CMP #18 | ||
+ | BNE :PUNT | ||
+ | LDY #$A0 | ||
+ | | ||
+ | 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. | ||
+ | * be enabled first. | ||
+ | * | ||
+ | SWAP | ||
+ | LDA MODENUM | ||
+ | CMP #18 | ||
+ | BNE :PUNT | ||
+ | LDA $DD00 ; | ||
+ | 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 | ||
+ | | ||
+ | | ||
+ | | ||
+ | PEND ;To get that label right :) | ||
+ | |||
+ | -- | ||
+ | The BLARG distribution binary is available from 'The Fridge', | ||
+ | archival web page on the internet at http:// | ||
+ | |||
+ | |||
+ | |||
+ | ::::::::::: | ||
+ | / | ||
+ | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||
+ | |||
+ | |||
+ | A CLOSER LOOK AT THE VIC II'S OUTPUT | ||
+ | by Adrian Gonzalez (DW/Style) & George Taylor (Repose/ | ||
+ | ------------------------------------------------------------------------------ | ||
+ | | ||
+ | 123456789012345678901234567890123456789012345678901234567890123456789012345678 | ||
+ | |||
+ | |||
+ | Contents | ||
+ | -------- | ||
+ | |||
+ | 0. Preface | ||
+ | |||
+ | 1. Introduction | ||
+ | | ||
+ | | ||
+ | |||
+ | 2. The NTSC Y/C video signal | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | 3. Wrapup | ||
+ | |||
+ | Bibliography | ||
+ | |||
+ | |||
+ | 0. Preface | ||
+ | ----------- | ||
+ | |||
+ | This text was originally formatted to 78 columns for ease of use. This | ||
+ | ensures compatibility with MSDOS " | ||
+ | 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. | ||
+ | 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. | ||
+ | and matching the colors "by eye", however, this turned out to be more | ||
+ | difficult than I expected. | ||
+ | logical step was to analyze the c64's output and determine the RGB values | ||
+ | from there. | ||
+ | to what the VIC-II' | ||
+ | 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, | ||
+ | measurements. | ||
+ | something new from it (!). | ||
+ | |||
+ | Repose: | ||
+ | |||
+ | Coincidently, | ||
+ | project. | ||
+ | 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. | ||
+ | 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. | ||
+ | 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' | ||
+ | get a color picture. | ||
+ | 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. | ||
+ | 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. | ||
+ | semi standard in a way because video production is always done in PAL format, | ||
+ | and only converted to SECAM for final transmission. | ||
+ | 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. | ||
+ | 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. | ||
+ | later. | ||
+ | |||
+ | Odd field Even field | ||
+ | |||
+ | | ||
+ | Scanline | ||
+ | | ||
+ | Scanline | ||
+ | | ||
+ | Scanline | ||
+ | . . | ||
+ | . | ||
+ | | ||
+ | Scanline 2*n ---------------------- | ||
+ | | ||
+ | |||
+ | 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 " | ||
+ | vision" | ||
+ | |||
+ | Scanline | ||
+ | Scanline | ||
+ | Scanline | ||
+ | Scanline | ||
+ | Scanline | ||
+ | . | ||
+ | . | ||
+ | |||
+ | The second consideration the engineers had was how to represent a 2d image as | ||
+ | a 1d voltage. | ||
+ | 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 | ||
+ | | | ||
+ | | | ||
+ | | ___________________________________ | ||
+ | | | ||
+ | | | ||
+ | | | ||
+ | | | ||
+ | | | ||
+ | |___ ____| 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. | ||
+ | scanline starts. | ||
+ | |||
+ | The brightness at a particular point of the scanline is defined by the | ||
+ | voltage of the waveform | ||
+ | to create a display with a simple white vertical line at the middle of the | ||
+ | screen, the waveform would look like this: | ||
+ | |||
+ | ^ Voltage | ||
+ | | | ||
+ | | | ||
+ | | __ __ | ||
+ | | White level | | | ||
+ | | | ||
+ | | | ||
+ | | | ||
+ | | Black level | | | ||
+ | |___ __________________| | ||
+ | | | | | ||
+ | | |__| <- Horizontal sync pulses ------------> | ||
+ | | | ||
+ | -------------------------------------------------------------------------> | ||
+ | Time | ||
+ | |||
+ | |||
+ | Let us now turn our attention to the visible display area on your TV: | ||
+ | |||
+ | ___ ___ | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | Field XXXXXXXX | ||
+ | | period XXXXXXXX | ||
+ | | (60hz) XXXXXXXX | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | _v_ | ||
+ | |< | ||
+ | 17% of 83% of line | ||
+ | | ||
+ | | ||
+ | blank | ||
+ | |< | ||
+ | Line period: 63.5 microseconds | ||
+ | |||
+ | The X's in the graph represent areas in which the in which your screen is | ||
+ | not visible. | ||
+ | left we have the horizontal blanking interval. | ||
+ | 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 | ||
+ | sync pulse 6 equalizing pulses | ||
+ | |||
+ | Please note that the time scale has been compressed to be able to cover most | ||
+ | of the vblank interval. | ||
+ | equalizing pulses, one serrated vertical sync pulse, and 6 more equalizing | ||
+ | pulses. | ||
+ | are spaced half a scanline apart. | ||
+ | away the equalizing pulses and serrations: | ||
+ | |||
+ | ^ Voltage | ||
+ | | | ||
+ | | last time | ||
+ | | scanline | ||
+ | | _________________________________ | ||
+ | | | ||
+ | | | ||
+ | |||
+ | | ||
+ | |||
+ | 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. | ||
+ | the field frequency is 60 Hz, and the frame frequency is 30hz (PAL has a 50Hz | ||
+ | field rate and 25Hz frame rate). | ||
+ | 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). | ||
+ | to an old book on TV theory, " | ||
+ | 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. | ||
+ | there are visible spaces between the scanlines. | ||
+ | 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' | ||
+ | VIC-II really outputs two signals (NTSC version only): | ||
+ | signal and the Chrominance (C) signal. | ||
+ | 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. | ||
+ | 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. | ||
+ | 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. | ||
+ | use an encoding called YUV. Y is the brightness information, | ||
+ | the C or color information. | ||
+ | picture this vector as originating from the centre of a circle. | ||
+ | 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. | ||
+ | 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. | ||
+ | (NTSC) (4.43Mhz PAL) with a varying phase and amplitude. | ||
+ | will be seen as a fine wavey detail in the luminance. | ||
+ | filter to separate the high frequencies as the color signal, and pass on the | ||
+ | lower frequencies as the normal B/W signal. | ||
+ | and can cause several strange effects on the picture, known as " | ||
+ | dots", " | ||
+ | appear in PAL). That is why, coincidently, | ||
+ | physically separate the color signal from the luma signal. | ||
+ | that may have occurred to you, is how do you measure phase without a | ||
+ | reference point? | ||
+ | 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. | ||
+ | |||
+ | *** | ||
+ | * | ||
+ | | ||
+ | | ||
+ | *-------*-------*----> | ||
+ | | ||
+ | | ||
+ | * * | ||
+ | | ||
+ | ColorBurst Reference Signal | ||
+ | |||
+ | *** | ||
+ | * * | ||
+ | | ||
+ | | ||
+ | --*-------*-------*--> | ||
+ | | ||
+ | | ||
+ | * | ||
+ | | ||
+ | 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. | ||
+ | important point which will be explained is how gamma affects RGB color | ||
+ | measurements, | ||
+ | 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. | ||
+ | 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:// | ||
+ | for up to date information. | ||
+ | |||
+ | |||
+ | Bibliography | ||
+ | ------------ | ||
+ | |||
+ | Introduction to Digital Video, Charles Poynton. | ||
+ | comp.graphics FAQ. | ||
+ | Television Theory and Servicing, second edition. | ||
+ | |||
+ | |||
+ | |||
+ | ::::::::::: | ||
+ | / | ||
+ | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||
+ | |||
+ | |||
+ | : Innovation in the 90s : | ||
+ | |||
+ | Revisiting The Super Hi-Res Interlace Flexible Line Interpretation Technique | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | Prelude from George Taylor, technical editor | ||
+ | ----------------+--+--+--------------------- | ||
+ | Once you have FLI, why not just overlay some sprites on it to make better | ||
+ | graphics? | ||
+ | implementing the concept was very difficult. | ||
+ | to making it work. The following article is a brilliant piece of work on | ||
+ | the subject. | ||
+ | raised a great deal of discussion. | ||
+ | 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. | ||
+ | inventor of the technique, Roland Toegel (Crossbow of Crest), was helpful | ||
+ | in providing the original SHIFLI documentation, | ||
+ | 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 : | ||
+ | |||
+ | ' | ||
+ | |||
+ | Please note that the technique is described primarily for Commodore computers | ||
+ | based on the European/ | ||
+ | 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. | ||
+ | reader to be already familiar to a high degree with VIC-II programming on the | ||
+ | C64. I would suggest books such as ' | ||
+ | found at ftp.funet.fi/ | ||
+ | some terms used in this document (e.g., mix-color) are meant to be uniquely | ||
+ | descriptive and hence, will not be found in any ' | ||
+ | The terminology is a result of the strain that occurs when new methodology | ||
+ | meets old semantics. | ||
+ | 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 ' | ||
+ | the use of the FLI technique with a multicolor mode as the basis. | ||
+ | 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, | ||
+ | 12 Characters or 4 Sprites next to each other. | ||
+ | area is centered though using Char-Position 15 to 26 inclusive on the | ||
+ | screen. | ||
+ | 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. | ||
+ | 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. | ||
+ | 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! | ||
+ | |||
+ | 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 | ||
+ | |||
+ | 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. | ||
+ | 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. | ||
+ | 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. | ||
+ | |||
+ | > 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 | ||
+ | |||
+ | So what does a sprite do over FLI? Pretty simple, as it just eats up some | ||
+ | cycles. | ||
+ | we code our FLI routine without loops, we just need 2 x (LDA, STA) commands | ||
+ | (for $D018 and $D011), using 12 cycles per rasterline. | ||
+ | 8 used sprites that makes 31 cycles. | ||
+ | char-positions 9,10 and 11 and from char 12+, the FLI effect comes up. This | ||
+ | doesn' | ||
+ | We therefore get 3 cycles per rasterline for other commands. | ||
+ | |||
+ | [The explanation of when the FLI effect starts in 2.1 was unclear. | ||
+ | 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. | ||
+ | pattern, and 9+3=12 is the start of the FLI effect. | ||
+ | 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. | ||
+ | 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, | ||
+ | Thats far too much for a single rasterline and adding the FLI routine will | ||
+ | bust the limits. | ||
+ | |||
+ | |||
+ | 3.1 | ||
+ | |||
+ | The trick is not to change anything at all! On the other hand we don't want | ||
+ | the patterns to look the same everywhere. | ||
+ | (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. | ||
+ | located becomes a little bit confusing, but it doesn' | ||
+ | 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. | ||
+ | are spread throughout memory in essentially random locations to make | ||
+ | them fit around the other graphics areas. | ||
+ | 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 | ||
+ | |||
+ | 1 | ||
+ | 2 | ||
+ | 3 | ||
+ | 4 | ||
+ | 5 | ||
+ | 6 | ||
+ | 7 | ||
+ | 8 | ||
+ | |||
+ | 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 | ||
+ | |||
+ | 2 | ||
+ | 3 | ||
+ | |||
+ | 4 | ||
+ | . | ||
+ | . | ||
+ | . | ||
+ | 20 1 41 | ||
+ | 21 2 42 | ||
+ | -------------------------------- | ||
+ | 1 | ||
+ | 2 | ||
+ | 3 | ||
+ | . | ||
+ | . | ||
+ | . | ||
+ | |||
+ | |||
+ | 3.1.2 | ||
+ | |||
+ | Small example for Sprite 0 under the following conditions: | ||
+ | |||
+ | Used 8 Video-Rams | ||
+ | content of the sprite-pointer: | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | Thus the Sprite-Patterns are in memory from $6000-$61FF. | ||
+ | |||
+ | Therefore the pattern-handling looks like this: | ||
+ | |||
+ | Screenline | ||
+ | |||
+ | 1 | ||
+ | 2 | ||
+ | 3 | ||
+ | 4 | ||
+ | 5 | ||
+ | 6 | ||
+ | 7 | ||
+ | 8 | ||
+ | 9 | ||
+ | 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 | ||
+ | |||
+ | As the changing of the video-ram on the editor-routine happens inside of the | ||
+ | textscreen (but the spritepointers are read inside the sideborder), | ||
+ | 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. | ||
+ | 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 | ||
+ | |||
+ | 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' | ||
+ | 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 # | ||
+ | anything else with the last free cycle. | ||
+ | |||
+ | LDX #$VALUE | ||
+ | LDA #$08 | ||
+ | STA $D018 | ||
+ | LDA #$38 | ||
+ | STA $D011 | ||
+ | |||
+ | |||
+ | 3.2.2 | ||
+ | |||
+ | 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. | ||
+ | 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. | ||
+ | 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. | ||
+ | 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' | ||
+ | |||
+ | |||
+ | 3.2.4 | ||
+ | |||
+ | 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. | ||
+ | for graphics due to the overlay of the Char-rom we choose the back from | ||
+ | $4000 - $7FFF for now. | ||
+ | |||
+ | |||
+ | 4.1 | ||
+ | |||
+ | The 8 video-rams need $2000 Bytes. | ||
+ | |||
+ | |||
+ | 4.2 | ||
+ | |||
+ | The bitmap needs $1F40 Bytes. | ||
+ | |||
+ | |||
+ | 4.3 | ||
+ | |||
+ | 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. | ||
+ | sprites. | ||
+ | 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. | ||
+ | rams. | ||
+ | |||
+ | A textline of a bitmap covers $140 bytes. | ||
+ | $60 bytes though and is centered. | ||
+ | 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. | ||
+ | textline for sprites, resulting in 5 sprites per line. Continuing this until | ||
+ | textline 24 inclusive, we have space for 15 additional sprites. | ||
+ | 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), | ||
+ | efficient as we have some space left in the video-rams. | ||
+ | |||
+ | The Textline of a video-ram contains $28 bytes. | ||
+ | needs the middle $0C bytes. | ||
+ | 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. | ||
+ | displayed 25 times per second (PAL). | ||
+ | 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, | ||
+ | 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: | ||
+ | [ | ||
+ | V | ||
+ | FLI2 : | ||
+ | |||
+ | |||
+ | 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, | ||
+ | $5, $A : Green, | ||
+ | $C, $E : Grey, | ||
+ | $4, $8 : Lilac (Purple), Orange | ||
+ | $2, $B : Red , | ||
+ | $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. | ||
+ | the same brightness, then green, grey, and purple, then red and blue. White | ||
+ | and black form the last 2 values of brightness. | ||
+ | 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. | ||
+ | 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/ | ||
+ | |||
+ | |||
+ | |||
+ | ::::::::::: | ||
+ | / | ||
+ | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||
+ | |||
+ | |||
+ | | ||
+ | |||
+ | - a beginners guide to software archiving | ||
+ | |||
+ | By Jan Lund Thomsen (aka QED/ | ||
+ | |||
+ | |||
+ | | ||
+ | 1 article (/S08: Software analysis and reconstructive therapy, a historical | ||
+ | view on " | ||
+ | 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 | ||
+ | " | ||
+ | required to make the most of this article the casual C64 enthusiast should also | ||
+ | be able benefit from it. | ||
+ | |||
+ | |||
+ | Disclaimer | ||
+ | ---------- | ||
+ | | ||
+ | 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' | ||
+ | using the backup copy and storing the original in a safe place. Copies can be | ||
+ | stored on floppy disks or hard drives for easier/ | ||
+ | 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. | ||
+ | |||
+ | | ||
+ | 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 | ||
+ | | ||
+ | |||
+ | - 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 | ||
+ | | ||
+ | |||
+ | |||
+ | 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 " | ||
+ | settle for less? For some crackers " | ||
+ | fixed, cheat modes installed, and excess data was surgically removed to | ||
+ | produce shorter, cleaner cracks. | ||
+ | Real cracking is about technical achievement, | ||
+ | dedication to quality. Needless to say, no cracker worth his salt will want | ||
+ | to freeze/ | ||
+ | Action Replay - not even for the purpose of producing copies for my eyes only. | ||
+ | |||
+ | | ||
+ | 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 | ||
+ | " | ||
+ | using additional I/O (highscore savers, intermission screens, levels, etc.) | ||
+ | are known as " | ||
+ | next? | ||
+ | |||
+ | | ||
+ | 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 " | ||
+ | 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. | ||
+ | |||
+ | | ||
+ | form is to load the " | ||
+ | themselves come to our rescue with the following ROM routines: | ||
+ | |||
+ | Decimal | ||
+ | ----------------------------------------------- | ||
+ | # | ||
+ | # | ||
+ | |||
+ | 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: | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | 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 " | ||
+ | program. The next four bytes contain the start and end address (Low/High byte) | ||
+ | of the program. This header above denotes " | ||
+ | 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 " | ||
+ | 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' | ||
+ | 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), | ||
+ | INC $F9 ; increase pointers | ||
+ | BNE l2 | ||
+ | INC $FA | ||
+ | l2 | ||
+ | | ||
+ | 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' | ||
+ | would put it, " | ||
+ | |||
+ | | ||
+ | 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 " | ||
+ | |||
+ | |||
+ | 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. | ||
+ | | ||
+ | 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, | ||
+ | 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), | ||
+ | $F9/$FA will give us the end address of the file. For the start-address we can | ||
+ | either make an educated guess using the ' | ||
+ | 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. | ||
+ | ----------------------- | ||
+ | | ||
+ | is by far the easiest step. Link the relevant files, then use a Char/RLE | ||
+ | packing program (EBC, Link & Crunch, X-Terminator, | ||
+ | " | ||
+ | |||
+ | 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 " | ||
+ | |||
+ | | ||
+ | short piece of code to get the graphics on screen and pack everything. | ||
+ | |||
+ | | ||
+ | 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 " | ||
+ | modern day term is " | ||
+ | |||
+ | |||
+ | Chapter 5: What's next? | ||
+ | ----------------------- | ||
+ | |||
+ | | ||
+ | | ||
+ | Just because you suddenly find yourself able to breach one protection | ||
+ | scheme doesn' | ||
+ | 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. | ||
+ | |||
+ | |||
+ | | ||
+ | | ||
+ | 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/ | ||
+ | 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 " | ||
+ | Runner on his C64 he is available for questions and/or general comments at the | ||
+ | following Internet address: kwed@pip.dknet.dk | ||
+ | |||
+ | |||
+ | |||
+ | ::::::::::: | ||
+ | / | ||
+ | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||
+ | |||
+ | |||
+ | 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. | ||
+ | I would undertake such a project. | ||
+ | previous " | ||
+ | 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 " | ||
+ | demo. These two are full motion displays using your REU. The " | ||
+ | demo is a 3-dimensional # sign transforming in and out, the " | ||
+ | full rotating Earth/ | ||
+ | |||
+ | 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. | ||
+ | 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. | ||
+ | occurs now only has about 21 cycles free instead of the usual 64, this is | ||
+ | called a " | ||
+ | |||
+ | 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. | ||
+ | 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. | ||
+ | |||
+ | 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. | ||
+ | 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. | ||
+ | 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. | ||
+ | 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 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; | ||
+ | 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. | ||
+ | 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 " | ||
+ | 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 " | ||
+ | line screen with a 60Hz refresh rate. | ||
+ | |||
+ | Synchronizing to a particular raster line is a simple matter of: | ||
+ | |||
+ | LDA # | ||
+ | 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/ | ||
+ | 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. | ||
+ | well as the VIC's idea of a frame. | ||
+ | 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. | ||
+ | |||
+ | Well we still have those 56 rasters off screen. | ||
+ | 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. | ||
+ | another 600 bytes to finish our 8000 byte bitmap... | ||
+ | |||
+ | LeT's just use the next three rows and waste a few rasters.. | ||
+ | 888, add the 7400 bytes we've done on the visible screen and we get 8288 | ||
+ | bytes. | ||
+ | |||
+ | After all this we still have another 32 rasters left, on which the audio | ||
+ | routine is still running (on every other line). | ||
+ | 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. | ||
+ | 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. | ||
+ | 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. | ||
+ | would be much lower resolution, but you would now have about 8 times | ||
+ | longer video. | ||
+ | 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.. | ||
+ | 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. | ||
+ | should in theory be enough to do it. | ||
+ | |||
+ | |||
+ | |||
+ | ::::::::::: | ||
+ | / | ||
+ | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||
+ | |||
+ | |||
+ | 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:// | ||
+ | | ||
+ | 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 | ||
+ | it to the screen. | ||
+ | |||
+ | * rand1.s | ||
+ | Not that great of a random sequence, but fine for | ||
+ | | ||
+ | |||
+ | * bitchin.doc | ||
+ | |||
+ | -- | ||
+ | ascii2bin.doc | ||
+ | |||
+ | The idea here is pretty simple. | ||
+ | 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 + 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. | ||
+ | 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 | ||
+ | |||
+ | 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, | ||
+ | DEY | ||
+ | BNE :LOOP | ||
+ | RTS | ||
+ | |||
+ | |||
+ | * | ||
+ | * Routine to divide a 32-bit number (in faq2..faq2+3) by | ||
+ | * the 8-bit number in faq2+4. | ||
+ | * 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. | ||
+ | * a typical linear congruential algorithm | ||
+ | * I(n+1) = (I(n)*a + c) mod m | ||
+ | * with m=65536, a=5, and c=13841 ($3611). | ||
+ | * 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' | ||
+ | |||
+ | Last revised: 2/20/97 SLJ | ||
+ | |||
+ | With a revision! | ||
+ | 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, | ||
+ | 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:// | ||
+ | |||
+ | |||
+ | |||
+ | ::::::::::: | ||
+ | / | ||
+ | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||
+ | |||
+ | | ||
+ | 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. | ||
+ | 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. | ||
+ | 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. | ||
+ | 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. | ||
+ | |||
+ | Epson QX10 (MFM) - CP/M Z80 DS/DD | ||
+ | Epson Euro (MFM) - CP/M Z80 DS/DD | ||
+ | IBM-86 | ||
+ | Kaypro II (MFM) - CP/M Z80 SS/DD | ||
+ | Kaypro IV (MFM) - CP/M Z80 DS/DD | ||
+ | Osborne | ||
+ | C-128 DS/DD (GCR) - The " | ||
+ | C-64 SS/DD (GCR) - C-64 CP/M (Z80 Cartridge) SS/DD | ||
+ | |||
+ | Note: The 1581 is " | ||
+ | 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 " | ||
+ | because this allows "Joe User" to easily boot up CP/M from a 1571 or even | ||
+ | a 1541 (slow!) drive. | ||
+ | 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. | ||
+ | is no small point of trivia. | ||
+ | these " | ||
+ | C-128 CP/M disk. | ||
+ | |||
+ | What about copying them over to C-128 CP/M disks? | ||
+ | |||
+ | No problem! | ||
+ | copier because as far as CP/M is concerned, the " | ||
+ | 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' | ||
+ | as part of the CP/M BIOS (Basic Input/ | ||
+ | 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! | ||
+ | memory or on the system disk). | ||
+ | the solution may be as easy as installing the parameters that match the disks | ||
+ | in question. | ||
+ | utility by Frank Prindle. | ||
+ | to ten different 5.25 MFM format-types at any one time from an overall | ||
+ | selection of twenty-four. | ||
+ | elegant program that can make these changes without sacrificing any TPA | ||
+ | (Transient Program Area) memory. | ||
+ | nowhere near as simple is the JUGGLER utility by Miklos Garamszeghy. | ||
+ | program can read and write and format over ONE HUNDRED THIRTY different | ||
+ | format-types, | ||
+ | disks. | ||
+ | for C-128 CP/M, namely Maxi 1571/1581 and MG 1581. A demo version of the | ||
+ | JUGGLER utility is publically available. | ||
+ | as the full version, you can only access twenty-two format-types and modifying | ||
+ | the " | ||
+ | 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:// | ||
+ | |||
+ | 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. | ||
+ | is the RDMS 2.33 utility. | ||
+ | diskettes, and that's all it does. It will read from MSDOS into CP/M but | ||
+ | will not write back to MSDOS. | ||
+ | (for the 1571 drive) and he would have probably added a "write MSDOS" option | ||
+ | if someone else hadn't beaten him to the punchline. | ||
+ | utility (ported over by Gilly Cabral from David Koski' | ||
+ | util.) came soon after Prindle' | ||
+ | used to communicate with the 1571 are based on Prindle' | ||
+ | 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. | ||
+ | FAT (File Allocation Table) and reconstruct it, if needed, using a backup FAT | ||
+ | as a template. | ||
+ | types with eight or nine sectors per track. | ||
+ | of the data it can transfer. | ||
+ | on the destination diskette. | ||
+ | mode MSDOS to CBM DOS programs which use internal memory buffering. | ||
+ | years, TRANSFER 128 was my only standby for large files. | ||
+ | came out for the " | ||
+ | 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. | ||
+ | CP/M programs) does not have to worry about steering clear of " | ||
+ | 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. | ||
+ | BIOS/ | ||
+ | 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 " | ||
+ | 128 has formatted. | ||
+ | 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 " | ||
+ | available for the C-128. | ||
+ | this section of this article will be rated PG-13 :). | ||
+ | |||
+ | Well Well Well !??!? Don't keep us in suspense! | ||
+ | |||
+ | Not to worry! | ||
+ | Sandru). | ||
+ | opportunity", | ||
+ | it provides (get this) *full* subdirectory support!!! | ||
+ | |||
+ | This is similar to the transparent " | ||
+ | |||
+ | Yes, except that CP/M disks carry the same directory structure no matter how | ||
+ | their format-type is arranged. | ||
+ | structure, MSDOSEM creates a separate buffer area for internal conversions | ||
+ | between CP/M and MSDOS logical constructs. | ||
+ | MSDOS format-types, | ||
+ | table. | ||
+ | MSDOS format-types. | ||
+ | means that you can play with the " | ||
+ | Any copy utility you have sitting around can now access MSDOS diskettes with | ||
+ | MSDOSEM as the go-between. | ||
+ | because you (essentially) do not have to transfer anything anymore! The " | ||
+ | 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 " | ||
+ | DOSian GCRish as anything Commodore has done for the " | ||
+ | advantage of this when backing up my CP/M disks, either with FastHack' | ||
+ | (or any GCR copier) in C-128 mode or IMAGE.COM under CP/M itself. | ||
+ | programs allow us to manipulate Commodore GCR on a gross level. | ||
+ | refined manipulation of files " | ||
+ | use the RDCBM 2.1 utility by Rob Tillotson and Turbo Penguin Software. | ||
+ | program can read files from 1541 or 1571 " | ||
+ | them out as straight binaries (eg., no translation) or it can convert files from | ||
+ | |||
+ | PETSCII to ASCII. | ||
+ | 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. | ||
+ | enough to provide limited support for files under the GEOS file structure. | ||
+ | Fortunately, | ||
+ | RDCBM to evaluate. | ||
+ | contains "Hooks and Crannies" | ||
+ | a " | ||
+ | |||
+ | You mean I cannot transfer material from my CP/M disks to my regular 15xx | ||
+ | disks??? | ||
+ | |||
+ | No I don' | ||
+ | do this. The C-128 " | ||
+ | this ability. | ||
+ | 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/ | ||
+ | |||
+ | Ok, you beat it out of me. There *is* a way to " | ||
+ | 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 " | ||
+ | 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 | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | < | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | S " | ||
+ | ---- | ||
+ | |||
+ | 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). | ||
+ | method places an absolute restriction on the file size of what you can " | ||
+ | it means that files can be " | ||
+ | is possible to save only one file per iteration of this cycle. | ||
+ | save many files, you will have to reboot CP/M and go through these steps | ||
+ | for each file involved. | ||
+ | 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 " | ||
+ | them, namely the JUGGLER, MSDOSEM, and C128LOAD utilities, and also the 28 MAY | ||
+ | 87 Version of CP/M 3.0+ on the C-128. | ||
+ | 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). | ||
+ | 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)? | ||
+ | a trump card in our sleeves in the form of the MSDOS format-types. | ||
+ | tend to be the lowest common denominator for information inter-change in | ||
+ | the entire microcomputer world. | ||
+ | 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. | ||
+ | I can simply use the MSDOS format-types as a bridge "over troubled sectors" | ||
+ | and not worry anymore. | ||
+ | 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 " | ||
+ | Blue Reader or Little Red Reader/ | ||
+ | share of inconveniences, | ||
+ | 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' | ||
+ | arising from this where a C-128 CP/M user might miss out on some software. | ||
+ | you have a machine that runs MSDOS, you can avoid that situation. | ||
+ | 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. | ||
+ | thing here is that it supports the Commodore 1581 CP/M MFM format. | ||
+ | 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 | ||
+ | some of them in the GEnie and Delphi information networks. | ||
+ | utility is available on the Internet FTP site oak.oakland.edu | ||
+ | / | ||
+ | |||
+ | Final thoughts... | ||
+ | |||
+ | Software Software Software... This article is by no means the final word | ||
+ | on what you can or can't " | ||
+ | GCR disks are completely isolated from C-128 CP/M, 22DISK140 or anything out | ||
+ | there besides an Apple drive! | ||
+ | set to master the Apple GCR format using a Commodore GCR drive. | ||
+ | drop me a line, good CP/M software is usually a thing of beauty. | ||
+ | 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. | ||
+ | s0621126@dominic.barry.edu for general comments or questions. | ||
+ | |||
+ | |||
+ | |||
+ | ::::::::::: | ||
+ | \H01:::::::::::::::::::::::::: | ||
+ | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||
+ | |||
+ | |||
+ | 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, | ||
+ | |||
+ | The most basic part of the system is the modules. | ||
+ | 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? | ||
+ | and this interface can be programmed with a Commodore 64/ | ||
+ | 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 first is the letters A-O. This is called the the HOUSECODE. | ||
+ | dial on the modules is the number 1-15, this is the UNITCODE. | ||
+ | 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. | ||
+ | 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. | ||
+ | rocker keys to respond to and then the screen shows the different rooms | ||
+ | you can " | ||
+ | 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. | ||
+ | with other computer systems have differences, | ||
+ | the room instead of using the " | ||
+ | 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 " | ||
+ | modules. | ||
+ | (graphics) that look like appliances and lamps. | ||
+ | stored in the interface as well as the HOUSECODE and UNITCODE. | ||
+ | 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, | ||
+ | And this is the beauty of the system, you can have your house have a " | ||
+ | look even though it isn' | ||
+ | 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: | ||
+ | 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! | ||
+ | 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. | ||
+ | any difference how many modules have been setup to go on or off for one | ||
+ | particular time (up to 16 modules). | ||
+ | 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). | ||
+ | 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. | ||
+ | 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. | ||
+ | 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. | ||
+ | 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 " | ||
+ | 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. | ||
+ | moving it to another room and caused a " | ||
+ | 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. | ||
+ | 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. | ||
+ | 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! | ||
+ | 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). | ||
+ | them to survive, and don't try to put a surge suppressor on them either. | ||
+ | filter the lines and will block any signals going out or coming in to the | ||
+ | attached equipment. | ||
+ | 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. | ||
+ | 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. | ||
+ | (unless you are doing an entire mansion). | ||
+ | power at the breaker!!!! | ||
+ | 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. | ||
+ | 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. | ||
+ | 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. | ||
+ | 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. | ||
+ | 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 | ||
+ | | ||
+ | |||
+ | |||
+ | INTRODUCTION | ||
+ | Software is required to use your computer to program the X-10 Home control | ||
+ | Interface. | ||
+ | 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. | ||
+ | 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' | ||
+ | |||
+ | 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. | ||
+ | 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 | ||
+ | | ||
+ | | ||
+ | |||
+ | The Interface has 8 rocker keys to give manual control of unit codes 1 thru 8 | ||
+ | onthe Base Housecode. | ||
+ | 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. | ||
+ | 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 | ||
+ | | ||
+ | |||
+ | The Interface is programmed via the 5 pin DIN socket on the back of the | ||
+ | Interface. | ||
+ | |||
+ | Looking at Back of Interface | ||
+ | | ||
+ | | ||
+ | 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. | ||
+ | < | ||
+ | longer sold with the interface. | ||
+ | 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: | ||
+ | Stop bits: 1. | ||
+ | |||
+ | |||
+ | BYTE FORMAT | ||
+ | | ||
+ | Bit D0 D1 D2 D3 D4 D5 D6 D7 Bit | ||
+ | | ||
+ | ! 0 ! 1 ! 0 | ||
+ | V- --- | ||
+ | |||
+ | 1011 | ||
+ | 1010 | ||
+ | |||
+ | 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. | ||
+ | bit is always a SPACE bit, i.e. " | ||
+ | finished and separates one byte from another. | ||
+ | bit, " | ||
+ | |||
+ | |||
+ | DOWNLOAD BASE HOUSECODE | ||
+ | |||
+ | When the Interface is first powered up, the Base Housecode is set to " | ||
+ | To change this you must first send a leading SYNC pattern of 16 x FF bytes | ||
+ | to the interface, followed by the identifier " | ||
+ | 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 | ||
+ | | ||
+ | Housecode | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | TABLE 1 | ||
+ | |||
+ | House Byte 18 | ||
+ | A | ||
+ | D | ||
+ | G | ||
+ | J | ||
+ | M | ||
+ | P | ||
+ | |||
+ | Base Housecode is used by the rocker keys on the Interface. | ||
+ | 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 | ||
+ | " | ||
+ | with change yes/ | ||
+ | |||
+ | After a successful download, the Interface will acknowledge by sending the | ||
+ | " | ||
+ | |||
+ | |||
+ | ACK MESSAGE | ||
+ | |||
+ | Byte D7 D6 D5 D3 | ||
+ | 1-6 1 | ||
+ | | ||
+ | |||
+ | The STATUS bit is reset to " | ||
+ | to " | ||
+ | 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 " | ||
+ | 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. | ||
+ | for " | ||
+ | check sum is the sum of bytes 18 through 21. See below. | ||
+ | |||
+ | |||
+ | BYTE | ||
+ | 1-16 1 | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | NOTE 1 | ||
+ | " | ||
+ | and Wall Switch Modules. | ||
+ | BRIGHT. | ||
+ | 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 | ||
+ | 0 0 | ||
+ | by upper nibble byte 19 and unit codes as | ||
+ | specified by bytes 20 and 21 will turn on. | ||
+ | |||
+ | 0 0 | ||
+ | |||
+ | 0 1 | ||
+ | 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 | ||
+ | | ||
+ | |||
+ | |||
+ | 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. | ||
+ | the power line transmission is complete the command is uploaded to the computer | ||
+ | (see command upload). | ||
+ | on the Interface, at the end of each transmission the codes are uploaded to | ||
+ | the computer. | ||
+ | of the Modules while it is connected to the Interface. | ||
+ | |||
+ | |||
+ | DIRECT COMMAND EXAMPLES | ||
+ | Example 1: Turn ON modules A1 and A4 | ||
+ | Bytes: | ||
+ | Data: | ||
+ | |||
+ | Example 2: Turn OFF modules A1 and A4 | ||
+ | Data FF 01 03 | ||
+ | |||
+ | Example 3: Turn on lamp module B9 and DIM to 50% | ||
+ | Data FF 01 75 | ||
+ | |||
+ | Example 4: Turn OFF all modules with housecode A | ||
+ | Data FF 01 03 | ||
+ | |||
+ | |||
+ | 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 | ||
+ | 1-6 | ||
+ | 7 | ||
+ | 8 HOUSECODE | ||
+ | 9 | ||
+ | 10 1 | ||
+ | 11 BASE HOUSECODE | ||
+ | 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 " | ||
+ | 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 | ||
+ | 1-16 1 1 1 1 1 | ||
+ | 17 0 0 0 0 0 | ||
+ | 18 0 0 | ||
+ | 19 0 0 0 | ||
+ | 20 0 | ||
+ | 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 | ||
+ | DATA | ||
+ | |||
+ | EXAMPLE 2 To set clock to 7:45 p.m. on Friday. | ||
+ | BYTE 1-16 | ||
+ | DATA | ||
+ | |||
+ | |||
+ | |||
+ | 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. | ||
+ | timer events and graphics data but D2 in Byte 19 is a " | ||
+ | and a " | ||
+ | |||
+ | 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. | ||
+ | of 8 bytes) is assigned a Start Address in the RAM in the Interface. | ||
+ | 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). | ||
+ | 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. | ||
+ | Modules will be controlled and byte 26 specifies the Housecode of these | ||
+ | Modules. | ||
+ | DIM and to what brightness level. | ||
+ | |||
+ | |||
+ | TIMER EVENT DOWNLOAD | ||
+ | BYTE | ||
+ | 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/ | ||
+ | 18 | ||
+ | 19 x x x x x 0 | ||
+ | 20 0 0 0 0 | ||
+ | 21 0 | ||
+ | 22 0 0 HOUR HEX 00 to 17 (0 to 23). | ||
+ | 23 0 0 0 MINUTE | ||
+ | 24 1 2 3 4 5 6 7 8 Bit map of unit codes. | ||
+ | 25 9 | ||
+ | 26 | ||
+ | 27 LEVEL | ||
+ | 28 | ||
+ | |||
+ | X=DON' | ||
+ | |||
+ | |||
+ | |||
+ | TABLE 4 - TIMER MODE SELECTION | ||
+ | |||
+ | BYTE 20 lower nibble | ||
+ | D3 D2 D1 D0 MODE EXPLANATION | ||
+ | | ||
+ | the same time each day, on | ||
+ | day or days specified by byte | ||
+ | 21 and at the time specified | ||
+ | by bytes 22 and 23. The | ||
+ | | ||
+ | are specified by bytes 24 to 27. | ||
+ | |||
+ | | ||
+ | | ||
+ | will be different each day | ||
+ | and will be within one hour | ||
+ | after the time specified by | ||
+ | byte 22. (varies in a | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | TABLE 4 - TIMER MODE SELECTION | ||
+ | BYTE 20 lower nibble | ||
+ | D3 D2 D1 D0 MODE DESCRIPTION | ||
+ | | ||
+ | the time specified by bytes 22 | ||
+ | and 23. and will be cleared from | ||
+ | memory at midnight TODAY. | ||
+ | |||
+ | | ||
+ | at the time specified by bytes | ||
+ | 22 and 23. and will be cleared | ||
+ | from memory at midnight | ||
+ | | ||
+ | |||
+ | | ||
+ | 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). | ||
+ | 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. | ||
+ | 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 ' | ||
+ | numbers increase in steps of 2 (for graphics type and X-10 code of 256 | ||
+ | objects). | ||
+ | The computer should keep track of the message numbers and load new messages | ||
+ | into vacant address locations. | ||
+ | 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). | ||
+ | |||
+ | |||
+ | GRAPHICS DATA DOWNLOAD | ||
+ | BYTE | ||
+ | 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/ | ||
+ | 18 | ||
+ | 19 X X X X X 1 0 | ||
+ | 20 | ||
+ | 21 | ||
+ | 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 | ||
+ | 1=ON ICON TYPE | ||
+ | 0=OFF | ||
+ | |||
+ | FOR EXAMPLE | ||
+ | ICON of a lamp shown in the ON state. | ||
+ | | ||
+ | ICON of a T.V. shown in the ON state. | ||
+ | | ||
+ | ICON of a coffee pot shown in the ON state. | ||
+ | | ||
+ | ICON of a fan shown in the OFF state. | ||
+ | | ||
+ | |||
+ | Byte 20 = 0 indicates a vacant ICON storage location. | ||
+ | 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 | ||
+ | HOUSECODE OF ! UNIT CODE OF | ||
+ | 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. | ||
+ | |||
+ | BYTE D7 | ||
+ | 1-16 | ||
+ | 17 | ||
+ | |||
+ | If the Interface receives the request correctly it will respond by uploading | ||
+ | the clock and Base Housecode to the computer, as shown. | ||
+ | not received correctly, no response is given. | ||
+ | |||
+ | |||
+ | |||
+ | CLOCK AND BASE HOUSECODE UPLOAD | ||
+ | Byte | ||
+ | 1-6 | ||
+ | 7 | ||
+ | 8 | ||
+ | 9 | ||
+ | 10 0 | ||
+ | 11 BASE HOUSECODE | ||
+ | 12 CHECK SUM Sum of bytes 8 to 11. | ||
+ | |||
+ | * The STATUS bit is reset to " | ||
+ | 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 " | ||
+ | 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. | ||
+ | |||
+ | BYTE | ||
+ | 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. | ||
+ | single FF byte, this shortens the time for the upload. | ||
+ | not include these FF bytes. | ||
+ | |||
+ | |||
+ | |||
+ | TIMER EVENTS UPLOAD | ||
+ | EXAMPLE WHERE ONLY FIRST TWO EVENTS ARE PROGRAMMED | ||
+ | |||
+ | BYTE | ||
+ | 16 1 1 1 1 1 1 1 1 SYNC FF X 6. | ||
+ | 7 | ||
+ | 8-15 EVENT NUMBER 1 AS DOWNLOADED, 8 BYTES. | ||
+ | 24-149 | ||
+ | | ||
+ | 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 | ||
+ | 1-16 | ||
+ | 17 | ||
+ | |||
+ | 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. | ||
+ | check sum does not include these FF bytes. | ||
+ | |||
+ | |||
+ | |||
+ | GRAPHICS DATA UPLOAD | ||
+ | EXAMPLE WHERE ONLY 5 ICONS ARE PROGRAMMED | ||
+ | |||
+ | BYTE D7 | ||
+ | 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 | ||
+ | | ||
+ | 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, | ||
+ | software (firmware). | ||
+ | for 10 seconds as part of this test. If the check is o.k. the Interface | ||
+ | will respond by sending the ACK with status " | ||
+ | the interface will Send ACK with status " | ||
+ | |||
+ | BYTE D7 | ||
+ | 1-16 | ||
+ | 17 | ||
+ | |||
+ | |||
+ | |||
+ | The above programming guide is included when you purchase the interface. | ||
+ | checked and it is freely distributable. | ||
+ | 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:// | ||
+ | as well as ones still in the works. | ||
+ | Asked Questions) file that has a wealth of information on the X-10 system | ||
+ | and compatible products. | ||
+ | packaged with the Commodore cable and software. | ||
+ | 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. | ||
+ | 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 | ||
+ | |||
+ | |||
+ | |||
+ | ::::::::::: | ||
+ | \H02:::::::::::::::::::::::::: | ||
+ | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||
+ | |||
+ | |||
+ | | ||
+ | // - The Metal Shop - // | ||
+ | |||
+ | ^...!..The Metal Shop..!...^ | ||
+ | |||
+ | |||
+ | Contributors : XmikeX | ||
+ | | ||
+ | |||
+ | David Wood (jbevren@willowtree.com) | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | |||
+ | Dear Metal Shop, | ||
+ | |||
+ | I recently found a 16 KB Commodore expander for my trusty VIC-20. | ||
+ | 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. | ||
+ | |||
+ | RE | ||
+ | -- | ||
+ | |||
+ | RE, | ||
+ | |||
+ | You are in luck RE because as the Good Lord would have it, I have also run | ||
+ | into a VIC-20 expander! | ||
+ | sought one out to view the new Veni Vedi Vic (Vedi Veni Vic?) demo by Marko | ||
+ | Makela (with umlauts over the a' | ||
+ | |||
+ | 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 | ||
+ | on off | ||
+ | off | ||
+ | off | ||
+ | off | ||
+ | |||
+ | |||
+ | 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. | ||
+ | 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. | ||
+ | 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. | ||
+ | expansion bank 1 into $6000 and bank 2 into $a000 (or vice versa!). | ||
+ | case, our DIP settings could be : | ||
+ | |||
+ | 1 | ||
+ | off | ||
+ | |||
+ | OR | ||
+ | |||
+ | on 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). | ||
+ | -- | ||
+ | |||
+ | [Ed. Note : The following is a response to the 1541 <-> Apple disk ][ | ||
+ | | ||
+ | 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. | ||
+ | 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' | ||
+ | it vice-versa? | ||
+ | |||
+ | I am commenting on the hardware aspect of the disk ][ drives on the Apple | ||
+ | computer. | ||
+ | lightning. | ||
+ | " | ||
+ | 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, | ||
+ | Voila! | ||
+ | single-sided assembly from a PC to fit " | ||
+ | ran fastloaders and GEOS. | ||
+ | |||
+ | Point at hand? The disk ]['s mechanical assembly is functionally identical | ||
+ | to the 1541's drive assembly. | ||
+ | Apple compatible drives (am I right? | ||
+ | be one hell of a challenge, because of the drive' | ||
+ | |||
+ | However, reading Commodore' | ||
+ | little advanced knowledge of the disk ][ interface. | ||
+ | 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= | ||
+ | | ||
+ | Krug on the WWW http:// | ||
+ | | ||
+ | |||
+ | |||
+ | 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. | ||
+ | | ||
+ | | ||
+ | to about 1.4Vss. This is done by two antiparallel silicon diodes | ||
+ | which cut off the signal at +/- 0.7V. The resistor limits the | ||
+ | | ||
+ | |||
+ | 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 | ||
+ | | ||
+ | | ||
+ | +-----+ | ||
+ | < | ||
+ | \ / / | ||
+ | | ||
+ | | ||
+ | (2) O---------o----------o-----------------O | ||
+ | |||
+ | |||
+ | XXXXX = resistor 470ohm | ||
+ | diodes = 1N4148 or 1N914 | ||
+ | |||
+ | |||
+ | 2. ... and stuff it in a DIN plug for the AV jack. | ||
+ | |||
+ | |||
+ | |||
+ | | ||
+ | |||
+ | |||
+ | 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, | ||
+ | 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 | ||
+ | | ||
+ | |||
+ | 3. Connect power plug and keep your C-64 running for several | ||
+ | | ||
+ | close the case again. | ||
+ | |||
+ | Possible failures | ||
+ | |||
+ | - Resistor' | ||
+ | |||
+ | |||
+ | |||
+ | ' | ||
+ | |||
+ | |||
+ | 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 | ||
+ | ' | ||
+ | |||
+ | |||
+ | Extract | ||
+ | |||
+ | | ||
+ | | ||
+ | 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, | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | 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 | ||
+ | | ||
+ | |||
+ | 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 | ||
+ | | ||
+ | other keys. Repeat that procedure a few times and if 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' | ||
+ | - 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' | ||
+ | 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 ' | ||
+ | |||
+ | 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" | ||
+ | |||
+ | If the floppy drive' | ||
+ | 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. | ||
+ | |||
+ | |||
+ | |||
+ | ::::::::::: | ||
+ | \L01::::::::::::::::::::::::::::: | ||
+ | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||
+ | |||
+ | |||
+ | 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. | ||
+ | require that every article contain what in our discretion should be a viable | ||
+ | Commodore 8-bit hardware and/or software point of relevance. | ||
+ | issue should include material that can both potentially enlighten the most | ||
+ | saavy of users as well as the layman. | ||
+ | others engaged in similar endeavours. | ||
+ | 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 | ||
+ | Associate/ | ||
+ | Associate/ | ||
+ | Webmaster | ||
+ | |||
+ | disC=overy, issue 3 logo by ' | ||
+ | |||
+ | 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 | ||
+ | | ||
+ | |||
+ | b. Sufficient technical content about Commodore 8-bit home computers, | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | |||
+ | - 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. | ||
+ | panel whose function it shall be to referee literary work which the Editor | ||
+ | in-Chief has deemed to be of advanced technical merit. | ||
+ | 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. | ||
+ | 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. | ||
+ | shall be responsible for the formation of the panel. | ||
+ | panelists shall have the option of anonymity if desired. | ||
+ | review works primarily for technical merit if the Editor-in-Chief and | ||
+ | the Associate Editor deem it necessary. | ||
+ | their works in accordance with the panel' | ||
+ | Chief shall have final discretion regarding all such " | ||
+ | |||
+ | |||
+ | Article 5 : Distribution | ||
+ | |||
+ | Although we welcome open distribution by non-commercial organizations, | ||
+ | are currently four " | ||
+ | parties. | ||
+ | or via the World Wide Web at http:// | ||
+ | at FTP site : ftp.eskimo.com - directory / | ||
+ | A " | ||
+ | from Arkanix Labs at the following physical address : | ||
+ | |||
+ | | ||
+ | | ||
+ | 17730 15th Ave NE Suite #229 | ||
+ | | ||
+ | |||
+ | This source should follow the distribution guidelines as listed in Article 6 | ||
+ | below. | ||
+ | directed at them. | ||
+ | |||
+ | Several versions of this journal may be available for your convenience, | ||
+ | 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. | ||
+ | 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, | ||
+ | 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, | ||
+ | allowable charge shall be limited to the actual cost of the | ||
+ | distribution, | ||
+ | other electronic means. | ||
+ | |||
+ | - Software included within articles (as text) may be subject to separate | ||
+ | distribution requirements as binary executables. | ||
+ | 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:// | ||
+ | |||
+ | 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. | ||
+ | |||
+ | ::::::::::: | ||
+ | \END::::::::::::::::::::::::::: | ||
+ | :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: | ||
+ | </ |
magazines/discovery3.txt · Last modified: 2015-04-17 04:35 by 127.0.0.1