@(#)top: ######## ################## ###### ###### ##### ##### #### #### ## ##### #### #### #### #### #### ##### ##### ## ## #### ## ## ## ### ## #### ## ## ## ##### ######## ## ## ## ##### ## ## ## ## ## ##### ## ## ######## ## ## ## ### ## ## #### ## ## ##### #### #### #### #### ##### #### #### #### #### #### ###### ##### ## ###### ###### Issue #12 ################## Version 1.3 ######## March 1996 ------------------------------------------------------------------------- @(#)contents: Table of Contents Features 6. "Polygonamy": A Study in 3 Dimensions by Stephen Judd (Reference: polygon) Did you ever feel real time 3 Dimensional graphics was just asking too much from a Commodore 64? Well, ask no more, as Stephen shows us just hoiw it can be done. The 64 steps up to the challenge of displaying correctly rendered shaded 3D polygons right before your very eyes. 9. Underneath the Hood of the SuperCPU by Jim Brain (Reference: cmdcpu) Delve into the technical details of this new accelerator under development by CMD. Jim will explain its advantages over existing offering, epxlain the features it provides, and dispel some myths about the unit. Columns 4. Hi Tech Trickery by Doug Cotton (Reference: trick) Trying to switch from 128 mode to 64 mode on a C128 without human intervwention is triccky. Doing it on modified KERNAL ROMs is doubly so. Doug details a routine that will work regardless of the ROM in use. 12. Hacking Graphics by Levente Harsfalvi (Reference: gfx) All you Commodore Plus/4 lovers, listen up. Levente delves into the Commodore Plus/4 TED chip, explains its many functions and details its various registers. Do you know all the things the TED chip does in addition to handle video. Now you'll know. Departments 1. The (cough,cough) Hacking Editor (Reference: editor) 2. Input/Output (Reference: io) 3. Newsfront (Reference: news) 5. Hacking the Mags (Reference: mags) 7. UseNuggets (Reference: usenet) 8. FIDO's Nuggets (Reference: fido) 10. Hack Surfing (Reference: surf) 11. Commodore Trivia (Reference: trivia) 13. ? DS, DS$: rem The Error Channel (Reference: error) 14. The Next Hack (Reference: next) 15. Hacking the Code (Reference: code) ------------------------------------------------------------------------- @(#)legal: Commodore Hacking Legal Notice Commodore and the respective Commodore product names are trademarks or registered trademarks of ESCOM GmbH. Commodore hacking is in no way affiliated with ESCOM GmbH, owners of said trademarks. Commodore Hacking is published 4 times yearly by: Brain Innovations Inc. 602 N. Lemen Fenton MI 48430 The magazine is published on on-line networks free of charge, and a nominal fee is charged for alternate mediums of transmission. Permission is granted to re-distribute this "net-magazine" or "e-zine" in its entirety for non-profit use. A charge of no more than US$5.00 may be charged by redistribution parties to cover printed duplication and no more than US$10.00 for other types of duplication to cover duplication and media costs for this publication. If this publications is included in a for-profit compilation, this publication must be alternately available separately or as part of a non-profit compilation. This publication, in regards to its specific ordering and compilations of various elements, is copyright(c) 1995 by Brain Innovations, Incorporated, unless otherwise noted. Each work in this publication retains any and all copyrights pertaining to the individual work's contents. For redistribution rights to individual works, please contact the author of said work or Brain Innovations, Inc. Brain Innovations, Inc. assumes no responsibility for errors or omissions in editorial, article, or program listing content. ------------------------------------------------------------------------- @(#)info: Commodore Hacking Information Commodore Hacking is published via the Internet 4 times yearly, and is presented in both ISO-8859-1 and HTML versions. This and previous issues can be found at the Commodore Hacking Home Page (http://www.msen.com/~brain/chacking/), as well as via FTP (ftp://ccnga.uwaterloo.ca/pub/cbm/hacking.mag/) In addition, the Commodore Hacking mail server can be used to retrieve each issue. To request a copy of an issue, please send the following electronic mail message: To: brain@mail.msen.com Subject: MAILSERV Body of Message: help catalog send c=hacking12.txt quit To retrieve a PKZIP 1.01 archive of the individual articles in Commodore Hacking, request the file c=hacking12.zip To subscribe to the Commodore Hacking and receive new issues as they are published, add the following command to you MAILSERV message prior to the quit command: subscribe c=hacking Firstname Lastname msglen (msglen is largest size of email message in line you can receive. Each line is roughly 50 characters, so 600 lines is about 30000 bytes. When in doubt, choose 600) example: subscribe c=hacking Jim Brain 600 Although no fee is charged for this magazine, donations are gladly accepted from corporate and individual concerns. All monies will be used to defray any administrative costs, subscribe to publications for review, and compensate the individual authors contributing to this issue. Any persons wishing to author articles for inclusion in Commodore Hacking are encouraged to view the submission guidelines on the WWW (http://www.msen.com/~brain/pub/c-hacking-submit.txt) or via the MAILSERV server (send c-hacking-submit.txt). ========================================================================= @(#)rch: Reading C=Hacking Starting with Issue 11 of Commodore Hacking, the new QuickFind indexing system is utilized to aid readers of the text version in navigating the magazine. At the top of each article or other important place in the magazine, a word prefixed with a special string is present. (See the title of this article for an example. Throughout the magazine, if an article is mentioned, it will be followed by a reference string. For example, if we mentioned this article, we would add (Reference: rch) after the name. By using your favorite editor's search function and searching for the string after the word "Reference:", prefixed by the magic prefix string, will move you directly to the article of choice. To merely skip to the next article in the magazine, search only for the magic prefix string. Some handy indexing strings possibly not referenced anywhere are: top top of issue bottom bottom of issue contents table of contents legal legal notice For those with access to a UNIX system, the command "what" can be run on the issue, which will result in all the article titles being printed. A slightly different magic prefix string "@(A)" is used to delimit sub-topics or main heading in articles. The text after the magic string differs depending on article content. For the Input/Output column (Reference: io), the text after the magic prefix will either be "c" for comment, or "r" for response. In features and columns, a number after the prefix indicates the ordinal of that heading or sub-topic in the article. If a specific sub-topic is referenced elsewhere in the article, a sub-topic reference will be indicated. A reference to "@(A)r" would be written as "(SubRef: r)". As time goes on, the role of this indexing system will be expanded and changed to ease navigation of the text version, but minimize the clutter added by these extra items. ========================================================================= @(#)editor: The Hacking Editor by Jim Brain (brain@mail.msen.com) Speed and the Web. The owners are asking about it. The developers are looking into it. The market is readying itself for it. No, not the PC market, I'm referring to the Commodore 8-bit market. The same market usually referred to as "mature". The same market usually referred to with a condescending tone. Well, mature we might be, but isn't that considered a good thing? People are supposed to mature as they grow older. As such, they are revered and looked up to. What parallels can we draw here? If you haven't anything about the planned introduction of the CMD SuperCPU 20 MHz accelerator cartridges for the C64 and C128, shame on you! You need to stay in touch more. For those who have, let's not overdo the hype. CMD isn't the first to produce such a cartridge, but they will be the first to introduce 20 MHz as a speed option. C128 users will rejoice as the first 128 mode accelerator ships from CMD. When this happens, performance approaching that of the venerable Intel 80386 will be as close as the on/off switch. The explosion of interest in the Internet and the World Wide Web is changing the way people view computers. Until recently, it seemed that people thought only computer systems including a 32 or 64 bit CPU, multiple megabytes of RAM, gigabyte hard drives, infinite resolution monitors and million bit sound cards were worth owning. Commodore owners have felt the sting of ridicule as they continually take blow after blow for remaining loyal to a machine with much to offer. Well, be patient, because 1996 might be the year of the "network computer", a smaller comuter system that trades all the fancy features of bloated PCs for a smaller size, cost, and a connection to the Internet. Big names like IBM, Oracle and Apple are pushing this idea, which would bring to market systems with modest RAM, small drives, television displays, and small operating systems. Does this idea sound familiar? It should, as it describes many features of Commodore 8-bit systems. No, the CBM 8-bit still lacks a few items present in the IBM/Apple/Oracle designs, but the bulk of features are already available on your so called "obsolete" CBM machine. Don't gloat yet, as there's much to do, but if your friends tout the benefits of such a machine, gently remind them that you own of of the first and best, a Commodore 8-bit. Enjoy YOUR magazine, Jim Brain (brain@mail.msen.com) editor ============================================================================ @(#)io: Input/Ouput Obviously, Commodore Hacking depends on the comments and article submissions from the Commodore community to flourish. Everyone sees the articles, but let's not forget those comments. They are very helpful, and every attempt is made to address concerns in them. Address any comments, concerns, or suggestions to: Commodore Hacking 602 N. Lemen Fenton, MI 48430 brain@mail.msen.com (Internet) @(A)c: Time Travellin' From: Robin Harbron <rfharbro@flash.lakeheadu.ca> Dear C=Hacking, I was looking at the Commodore Hacking page (fantastic magazine) and noticed that the "Publishing Schedule for 95-96" has 1995 for all the dates, while I assume that the last 4,5,or 6 probably should be 1996. Thanks for everything! Robin @(A)r: Yep, we must have just returned from our time travel experiments when we wrote that in the WWW pages. Note that the magazine was correct, but the home was in error. Oh well. @(A)c: Run (Down) the Software From: sis319@educ.di.unito.it Dear C=Hacking, I really appreciate the work you are doing with the Commodore Hacking on-line magazine. I like the new look and the new features you added, such as newsfront and hacking the mags. I would like to see on the magazine some reviews about the latest and more interesting PD and Shareware software (with a list of FTP sites where these are available) and hardware products. Please note that Commodore Hacking is the only Commodore magazine I can easily find here in Italy, because all the Italian magazine there were are dead and all the foreign magazines that were distributed, such as "RUN", "Compute!'s Gazette", "64'er" are either dead or no longer distributed. @(A)r: We appreciate your comments about the new look of C=Hacking. As for the inclusion of reviews, we're looking into it. it's not that we don't want to do it, just that we need to schedule the reviews (Commodore Hacking shouldn't do all of them, as that creates bias), and determining what software is worthy of review. Look for some reviews in upcoming issues. @(A)c: Separate But Equal From: alan.jones@qcs.org (Alan Jones) Dear C=Hacking, I like your new version of C=Hacking. I like the idea of including relevant news and summaries of other magazines and disks. Size should not be a constraint, although you should publish early when it exceeds some critical size. Don't scrimp on source code listings and uuencoded files! There is no other publication for this sort of bulky technical stuff. It would also be wonderfull if we could get an apropriate means for including diagrams or pictures, viewable by C64/128 users. I would REALLY like to have the C64/128 html viewer/printer that you mentioned. You may not know it but we came very close to having Al Angers Tower article submitted to C=Hacking in place of _Commodore World_, but C=Hacking could not really handle drawings and photos. I have been separating C=Hacking into separate articles and files, archiving them and placing the archive(s) on a local BBS. This compacts the length and makes it easier to read and use. I try to make C=Hacking easy to download and use locally, but I still want to keep it as whole and original as possible. @(A)r: Alan, we're glad you approve of the new format. We're going to try to keep the size so that it will always fit onto 2 1541 disk sides. C=Hacking is still working on the HTML viewer, but it's taking a back seat to other more pressing issues. We'll have it finished at some point, and start distributing the magazine that way as well. As for your separation, we appreciate the work you've done to make C=Hacking easier to distribute. With issue #12, we are offering an archive of all the article in separate files. The archival method has not been chosen just yet, but look on the C=Hacking MAILSERV server for the file. Late news: check Commodore Hacking Information (Reference: info) for more information of retrieving an archive of the individual articles. @(A)c: Enquiring Minds Wanna Know! From: Peter Hofman <HOFMAN%NLEV00@btmv56.se.bel.alcatel.be> Dear C=Hacking I would like to make a suggestion for your "Commodore Hacking E-Zine" page. Maybe you could add a link to a page with some info about the next issue of Commodore Hacking, so people know what will be in the next issue. The reason why I make this suggestion is that I read the other issues, and I am very curious, what will be published. @(A)r: Good suggestion. So good, in fact, that we implemented it. Mind you, we can't completely predict the future, so the information in the link may not exactly reflect the contents of the issue when it is published, but we'll try to keep the two in sync. @(A)c: Pulling It Out of the Closet From: bloodbane@rlion.com (Jeffrey S Cotterman) Dear C=Hacking, Well, I was just writing to say I think you did a great job on C= Hacking... I am throughly amazed by the support and the interest in the Commodores. I have a Vic-20, C-64, C-128, and an Amiga 1000. I have not used any of them in a long time, I have two Beamers that I use more. However seeing all this stuff makes me want to turn them back on. (Actually I use the 64 quite a bit for playing games, plus the 1702 monitor works great with a Super Nintendo!) I used to be quite proficient at the 64, but it is slipping. I will try to get my butt back in gear so maybe I can post an article or two.... Geesh, and just last year I got rid of all my Run and Compute's Gazette magazines.... Oh well I will look through the cobwebs and see what I can come up with. Anyway, congrats on the mag, I think it's going great. @(Ar: We appreciate the thanks. And, if we can get one person to pull a C64 or other CBM machines out of the closet and turn it back on through what we do, it is worth it. @(A)c: C=Hacking Flunked Geography From: Peter Karlsson <dat95pkn@idt.mdh.se> Dear C=Hacking, I saw your mention of Atta Bitar in Commodore Hacking. German? Heheheh... :-) Anyway, the English information page is available now, but not much will=20 be in English (sorry). It is a Swedish paper :) From: Erik Paulsson <ep@algonet.se> Dear C=Hacking, I'm the editor of the Swedish mag Atta Bitar (8 bitter), so I thought I should drop you a line. I really like the "new" C= Hacking it's really great, keep up the good work! One small comment regarding Atta Bitar, it's not in German, it's in swedish. I just thought you should know... @(A)r: Picky, picky, picky. It's not like we would react that way if you said Commodore Hacking came from CANADA. Wait, hold it.... I guess we would. Correction made. Thanks for the update, and if we ever learn Swedish, we'll try to read it again. (Anyone want to translate for us?) ========================================================================= @(#)news: Newsfront * Matthew Desmond, the author of Desterm, has recently resurfaced and states that he is once again working on something. Although Commodore Hacking discourages hourds from emailing him to ask about Desterm progress, Matt's email address is mdesmond@ionline.net, for those who wish to register Desterm or express their support. * Speaking of email addresses, LOADSTAR will be changing theirs. As the online service GEnie has recently been purchased and new fares have been put in place, LOADSTAR finds its monthly bill rising too high for pleasure. As of March, 1996, the Internet address for LOADSTAR will be loadstar@softdisk.com. * While we're on the subject of email addresses, CMD has expanded their set of Internet email address contacts in order to better support its online users. The following addresses are now valid: Email Address Usage cmd.sales@the-spa.com Questions relating to product prices, catalog requests, ordering onformation, cmd.support@the-spa.com Technical questions concerning CMD products. cmd.cw@the-spa.com Questions or comments relating to Commodore World magazine. doug.cotton@the-spa.com superceded the cmd-doug@genie.geis.com address previously used for all CMD inquires. Should be used items not applicable to the above addresses cmd.cac@the-spa.com Direct link to Charles A. Christianson, VP of Sales and Marketing. Again, shuld be used for items not applicable to above email addresses. * We're not done yet, as COMMODORE CEE has recently moved its office and is now at: COMMODORE CEE 5443 College Oak Drive #26 Sacramento, CA 95841 Jack Vanderwhite@cee-64.wmeonlin.sacbbx.com (Contact) ceejack@crl.com (Contact) Jack Vanderwhite, editor. Fidonet: 1:203/999 (916) 339-3403 (Bulletin Board System) * The Commodore Zone. No, it's not an alternate universe, but a magazine for the Commodore gamer and/or demo fan. Each issue's 40 pages is full of reviews, interviews with top programmers, and an exclusive comic strip done by Alf Yngve. Accompanying each issue is a 5.25" disk or tape containing game demos, demos, and full games. Free software is often included. More information can be obtained through: Commodore Zone 34 Portland Road Droitwich Worcestershire WR9 7QW England Copies are available for UK3.00. Make checks payable to Binary Zone PD. * Also in the magazine front, Computer Workshops, Inc. is planning a World Wide Web magazine to feature gaming. The blurb follows: CWI is working on a new Web magazine to feature the newest and hottest in c64/128 Gaming. But, before we can do that, we need your help. Send us what you're working on, or, if you're a programmer with something for review, send us that too! Also, if you've got a product you'd like to advertise, we'd like to hear that too (a la Yahoo). Send it to either, or both: spectre@deepthought.armory.com Computer Workshops/Cameron Kaiser ATTN: Commodore Gamer 3612 Birdie Drive La Mesa, CA 91941-8044 (Please don't send binaries to the spectre@ address.) Thanks for your support, and barring any unforseen difficulties, Commodore Gamer should be ready to premiere in about two months. Cameron Kaiser * The December 10, 1995 edition of the Waco Tribune Herald put one of our own in the spotlight. The headline read "'Antique' PCs have loyal fans here, elsewhere." and was written by Sherry W. Evans, Tribune-Herald staff writer. The Commodore user taking the spotlight was Karen Allison, known on the FIDO network. Sharing the spotlight with Karen was Brad Jackson, of Commodore Country, who said that a C64 was raced against an Intel 386 using identical programs, and the 64 won. Allison claims in the article that "the challenge is finding creative ways to solve problems since Commies have had no ... support..." Allison indirectly mentioned GeoFAX, the GEOS Fax program, and a low cost Tax program she uses to pay the IRS every year. Allison, a diehard "Commie", explained in the article that "(People who use IBMs) all think my Commodore can't do much and is just a toy. But for a toy, this computer does pretty good." * For those good with an assembler and the VIC/SID registers, Driven Magazine is sponsoring a 4K Demo competition. The deadline is July 1st 1996. Although the program must run on an NTSC 64, PAL programmers are encouraged to enter. The entries will be released as a group at the close of the contest, and entrants can re-use their entries. The complete rules follow: 4k Demo Contest Rules - 1 file only (no secondary loading) - max file size is $1000 bytes - must be started with BASIC 'run' - 1 demo per coder; multiple entries per group are allowed. Multiple coders can collaborate on a single demo, so long as there remains only 1 demo per coder. - credits for all parts of an entry must be given at time of entry; if a particular credit is unknown, mark it as "unknown" - demos will be evaluated on NTSC c64. Anything not specifically denied above is allowed; e.g. packing + crunching, use or non-use of music or graphics, entries by PAL sceners, etc. Deadline = July 1. Entries need to go to coolhand: coolhand@kaiwan.com or postal mail to: Bill Lueck 17411 Mayor Lane Huntington Beach, California, 92647 USA Evaluators will be selected shortly, but will include Coolhand and 2-3 other non-demomaking NTSC demo enthusiasts. There will be categories for evaluation, but there will not be separate winners - the scores from the categories will be added together. The categories will be announced after the evaluation team is established, but they will include design, originality, technical difficulty, artistic impact, and best overall impact, etc (all tentative at this time). * Bo Zimmerman has put his Commodore 128 on the net. No, he didn't log into some Internet service from his 128, he actually PUT it on the 'Net. Running the BBS program called "Zelch", the machine can be accessed by telntting to 147.26.162.107 and giving "zelch" as the login. Bo warns that the system is running off a single 1571 at 2400 bps, so don't hog the system, OK. For the technical types, the 128 is connected to the serial port of a Linux PC hooked up the Internet. Nonetheless, we're getting closer to the standalone CBM Internet server. * In the March 1996 issue of _Next Generation_ magazine, on pages 31 and 32, NG published a very unflattering definition of the Commodore 64 as part of their: "The Next Generation 1996 Lexicon A to Z: A definitive guide to gaming terminology". Among other things, the definition's writer confused the Apple II with the Commodore 64 and stated that the C64 could not display lowercase, a common problem on early Apples. The writer was biased in favor of the Apple II line, but evidently had never used a C64 or never owned an early Apple II. In either case, the fervor caused by the definition sparked an outrage in the USENET newsgroup comp.sys.cbm. See UseNuggets (Reference: usenet) for the scoop. If you would like to write to _Next Generation_, even though the article claimed no comments would be heard on the subject, or to request a copy of the article, their address is: Editorial: Email: ngonline@imagine-inc.com Fax: (415) 696-1678 Phone: (415) 696-1688 Subscriptions: Email: ngsubs@aol.com Phone: (415) 696-1661 Post Office Mail: Next Generation Imagine Publishing, Inc. 1350 Old Bayshore Highway, Suite 210 Burlingame, CA 94010 ========================================================================= @(#): trick: RUN64: Moving to 64 Mode by Doug Cotton (doug.cotton@the-spa.com) Reprinted with permission. Copyright (c) 1996 Creative Micro Designs, Inc. Various routines have been used over the years to allow programs to move from 128 mode to 64 mode without user intervention. With the advent of modified Kernal ROMs (JiffyDOS, RAMLink, and others) many of the methods that work on stock machines have either failed to do the job completely, and in some cases fail all together. RUN64 is the answer to those users looking to worm their way into 64 mode without having to be concerned with the different Kernal ROMs. The program is presented here in two ways: as a BASIC program that will move to 64 mode and load the program you request, and as assembly language source for ML programmers. BASIC Notes: The BASIC version uses the ML code produced by the assembly language source. This is found in the data statements beginning at line 660. When you run it, the program will ask for the file name, device number, and file load type (BASIC or ML). The first two parameters should be self-explanatory, but the load type may confuse you. If the file you're loading is itself a small loader (1, 2 or 3 blocks) then it will almost always be an ML program. Likewise, if you usually load the file with a ",8,1" at the end of the load statement, it's ML. If you're loading a larger file, or a file that you normally load with just a ",8", then use the BASIC option. Also, if you remove the REM instructions from lines 150 through 180 the program becomes a dedicated loader. Just specify the file name and other options within those lines. @(A): How The Routine Works RUN64 performs its trick by masquerading as a cartridge. When started, the code copies the payload routines into $8000, with the special header that signifies a cartridge is present. It then resets the system. The system initializes and checks for a cartridge. When it finds the payload routines, it executes them just like it would any cartridge. The pseudo-cartridge routines then switch out BASIC, call the remainder of the KERNAL init routines, switch BASIC in, call some BASIC init routines, set the "load" and "run" lines on screen, dump some "returns" into the keyboard buffer, and finally jump into the BASIC interpreter. @(A): Assembly Language Notes: The source code is pretty well documented, and ML programmers should have little trouble figuring out what everything does. Take note of the Buddy Assembler .off pseudo-op used a few lines below the code label. This adjusts all fixed references within the code that follows it to execute properly at $8000. The code uses some indirect vectors (ibv, ibr and ibm) to overcome not having an indirect jsr opcode, and switches out BASIC ROM temporarily since the KERNAL finishes intializing by indirectly jumping through the address at $a000. Since the target application hasn't been loaded yet, the code must put its own address at $a000 to regain control. To use the routine, just set up a file name at filename, put a device number in $ba, set the load type in sa1flag, then execute the routine. 100 rem run64.bas (c) 1996 creative micro designs, inc. 110 : 120 print "{CLEAR/HOME}run64" 130 print 140 : 150 rem f$="filename" : rem filename 160 rem dv=peek(186) : rem device number (8, 9, 10, etc.) 170 rem l$="a" : rem load type (a=basic, b=ml [,1]) 180 rem goto 310 190 : 200 input "filename";f$ 210 input "{2 SPACES}device";dv$ : if dv$="" then 230 220 poke 186,val(dv$) 230 dv = peek(186) 240 print 250 print "select a or b" 260 print "{2 SPACES}a. load";chr$(34);f$;chr$(34);",";right$(str$(dv),len(str$(dv))-1) 270 print "{2 SPACES}b. load";chr$(34);f$;chr$(34);",";right$(str$(dv),len(str$(dv))-1);",1" 280 get l$ : if l$<>"a" and l$<>"b" then goto 280 290 print 300 print l$;" selected" 310 print 320 print "going to 64 mode!" 330 : 340 : rem poke in main ml 350 : 360 i = 6144 370 read d 380 if d = -1 then 450 390 poke i,d 400 i = i + 1 410 goto 370 420 : 430 : rem poke in filename 440 : 450 for i = 0 to len(f$)-1 460 : poke 6356+i, asc(mid$(f$,i+1,1)) 470 next i 480 poke 6356+i,0 490 : 500 : rem poke in device number 510 : 520 if dv$="" then 570 530 poke 186,val(dv$) 540 : 550 : rem check load type 560 : 570 poke 6324,0 580 if l$="b" then poke 6324,1 590 : 600 : rem sys to ml 610 : 620 sys6144 630 : 640 : rem ml data 650 : 660 data 32,115,239,160,0,185,22,24 670 data 153,0,128,200,208,247,165,186 680 data 141,157,128,76,77,255,9,128 690 data 9,128,195,194,205,56,48,169 700 data 0,141,4,128,120,169,0,141 710 data 22,208,32,132,255,32,135,255 720 data 169,230,133,1,169,43,141,0 730 data 160,169,128,141,1,160,76,248 740 data 252,169,231,133,1,32,148,128 750 data 32,151,128,32,154,128,162,0 760 data 189,159,128,240,6,32,210,255 770 data 232,208,245,162,0,189,190,128 780 data 240,6,32,210,255,232,208,245 790 data 162,0,189,180,128,240,6,32 800 data 210,255,232,208,245,173,158,128 810 data 240,10,169,44,32,210,255,169 820 data 49,32,210,255,169,145,32,210 830 data 255,32,210,255,173,157,128,133 840 data 186,162,0,189,185,128,240,6 850 data 157,119,2,232,208,245,173,158 860 data 128,208,2,169,4,133,198,76 870 data 157,227,108,149,227,108,152,227 880 data 108,155,227,0,0,17,17,68 890 data 86,61,80,69,69,75,40,49 900 data 56,54,41,58,76,79,65,68 910 data 34,0,34,44,68,86,0,13 920 data 82,213,13,0,70,73,76,69 930 data 78,65,77,69,0,-1 ; RUN64.SRC ; Doug Cotton & Mark Fellows ; (c) 1996 Creative Micro Designs, Inc. ; .org $1800 .obj run64.obj run64 jsr $ef73 ; go slow ; ldy #0 ; copy cartridge - lda code,y ; code to $8000 sta $8000,y iny bne - ; lda $ba ; get device number sta dvtemp ; and store it ; jmp $ff4d ; go 64 ; code .byt $09,$80 ; cold start .byt $09,$80 ; warm start .byt $c3,$c2,$cd,$38,$30 ; cbm80 ; .off $8009 ; offset code ; lda #$00 ; disable sta $8004 ; cartridge code sei ; disable interrupts ; lda #$00 ; zero out sta $d016 ; VIC control Register ; jsr $ff84 ; initialize I/O jsr $ff87 ; initialize RAM lda #$e6 ; switch in RAM sta $01 ; at $A000 lda #<reenter ; set up return vector sta $a000 ; at $A000 to bypass lda #>reenter ; BASIC statup during sta $a001 ; initialization ; jmp $fcf8 ; let Kernal finish up ; reenter lda #$e7 ; back from Kernal, set sta $01 ; $A000 back to ROM ; jsr ibv ; initialize vectors jsr ibr ; initialize RAM jsr ibm ; initialize memory ; ldx #$00 ; output screen text - lda part1,x ; to form LOAD statement beq + jsr $ffd2 inx bne - ; + ldx #$00 ; print filename to be - lda filename,x ; loaded at end of beq + ; LOAD statement jsr $ffd2 inx bne - ; + ldx #$00 ; print device - lda part2,x ; variable at end beq + ; of LOAD statement jsr $ffd2 inx bne - ; + lda sa1flag ; check secondary beq + ; address flag for load lda #',' ; type, and print a jsr $ffd2 ; comma and a 1 at end lda #'1' ; of LOAD statement if jsr $ffd2 ; load type is ML ; + lda #$91 ; print two CRSR up jsr $ffd2 jsr $ffd2 ; lda dvtemp ; get device number sta $ba ; and store ; + ldx #$00 ; put [RETURN]rU[RETURN] - lda keydata,x ; into keyboard buffer beq + sta $0277,x inx bne - ; + lda sa1flag ; get load type and bne + ; branch if it is ML (1) lda #$04 ; if not ML, change .A + sta $c6 ; store kybd buffer NDX ; jmp $e39d ; enter BASIC ; ibv jmp ($e395) ; initialize vectors ibr jmp ($e398) ; initialize RAM ibm jmp ($e39b) ; initialize memory ; dvtemp .byt $00 ; device number temp sa1flag .byt $00 ; load type (1=ML, ; 0=BASIC) ; part1 .byt $11,$11 ; 2 CRSR up .byt 'dv=peek(186):load' .byt $22 ; quote .byt $00 ; part2 .byt $22 ; quote .byt ',dv' .byt $00 ; keydata .byt $0d ; [RETURN] .byt 'rU' ; shortcut for RUN .byt $0d ; [RETURN] .byt $00 ; filename .byt 'filename' ; name of file to load .byt $00 ; 00 byte must follow filename! ; .end ========================================================================= @(#)mags: Hacking the Mags Not everything good and/or technical comes from Commodore Hacking, which is as it should be. (I still think we have the most, though...) Thus, let's spotlight some good and/or technical reading from the other Commodore publications. If you know of a magazine that you would like to see summarized here, let C=Hacking know about it. These summaries are only limited by Commodore Hacking's inability to purchase subscriptions to all the Commodore publications available. We are very grateful to those publications that send complimentary copies of their publications for review. @(A): COMMODORE CEE At press time, Issue #5 was in the works, so we'll detail the contents next time. However, see Newsfront (Reference: news) for address changes for COMMODORE CEE. @(A): Commodore 128/64 Power User Newsletter (CPU) A while back, Gosser Games, Ltd., Inc. sent us a sample issue of this publication, which is published exclusively with a Commodore 128 machine, much like the defunct dieHard. For those just getting into the BBS arena, the "Cyberspace Cowboy", R.J. Smulkowski, previously writing this article in dieHard, has moved his column to CPU. The content is light, but useful, and a godsend for new users. Reviews of GeoFAX and "Radio Controlled Flight Simulator" also grace the pages. Printed on regular bond at 7" by 9", the 16 page publication is small but full of potential. @(A): Commodore World If you remember last time we spoke of Commodore World, we asked the rhetorical question: What's up with those funky graphics? We didn't expect an answer, but editor Doug Cotton called to explain the curious eye-catchers. He also mentioned that asst. editor Jenifer Esile was having trouble creating them now that we made fun of them. We're sorry Jenifer. We want you to continue, since they save us the cost of commercial inkblot cards for our self-psycho-analysis sessions here at Hacking Headquarters. (just joshing, we can be so mean sometimes). Speaking of Jenifer, we're not sure when she started, but the last few issues seem more colorful. Sure, content is great, but packaging is everything. We've even caught PC-centric folks perusing our copy. Kudos to CMD for that effect. Obviously, Commodore World iisn't for all, but the content is consistent. Issues 11 and 12 are no exception. In issue 11, Doug tackles high level serial bus routines and includes ML source, Gaelyne Moranec shares some useful WWW pages, and Jim Butterfield explains the nasty NULL character and its implications. Of special interest in this issue is the two page spread on changing device numbers on the pesky 1541 drives. The article is worthy of archival for reference. CMD also takes time to note that the SuperCPU cartridge will contain a 65C816 8/16 bit CPU, not the earlier mentioned 65C02 8-bit CPU. Issue 12 should be subtitled the "SuperCPU" issue. We think its great, but it's definitely not subtle. Doug Cotton and Mark Fellows preview the unit while Jim Brain details the CPU inside it. CMD ntes that the 10 MHz version has been scrapped, but the 128 version has been added, dealying introduction until April for the 64 version. C=H was hoping to review a prototype unit this issue, but we'll do it next time. Jason Compton and Katherine Nelson describe HTML, the markup language for World Wide Web pages, and Jim Butterfield explains using KERNAL devices 0 (keyboard) and 3 (screen). For those wanting to run a Bulletin Board System, Max Cottrell describes how to ensure success. Of special interest in this issue is a photo of the prototype accelerator. We won't even hint of our opinions on this round of funky graphics.... @(A): Driven Driven #11 waxes somewhat philosophic about the demo scene in 1995. The tone expresses a tinge of disappoinment with the hope that 1996 will be a better year for demos. This issue also ushers in Driven's first crack at covering the PAL scene. As part of the 1995 year-end review, a complete list of releases is given. In the news section, Charles Christianson's blurb on the CMD SuperCPU is reprinted, and King Fisher of Triad discusses the origins of the demo scene in "Cyberpunk". If you've ever wondered what goes on inside the mind of a demo "scene" programmer, Driven #12 will fill you in. Interviews with Phantom of the group FOE and Zyron of F4CG are included, both telling it as it is. For those wanting to set up or design a BBS system Mitron takes a look at CNET DS2 and details some general guidelines on how the networking code works. Of special note is a review of this issue's Polygonamy sample code (Reference: polygon). @(A): LOADSTAR Issue 139 starts off with the announcement that LOADSTAR is taking over the dieHard Spinner disk subscriptions, as reported in C=H#11. File Base 64 from John Serafino will be useful for anyone organizing their disk collection. Fender Tucker claims it is better than DCMR, the supposed standard. Jeff Jones cooks up the "Ultimate INPUT" for people wanting the perfect BASIC INPUT routine. The claims are substantial and Jeff delivers. The included LOADSTAR LETTER #29 contains another article in the Internet series. As we started Issue 140, we noticed something was different. We couldn't place it at first, but then Jeff alerted us to the change. LOADSTAR now has highlighted words in the text, and the color scheme can be changed and saved. Nice for the eyes. In addition, LS#140 can mark up text using highlights, bold, and underline on printers that support such features. Bob Markland presents a ML module that provides better random numbers, and Fender Tucker challenges programmers ML programmers to write a routine that searches an in memory dictionary for a word. Speed is the key. C=H gets some space, as Issue 11 is reprinted in the 3.5" version. Of particular note to programmers is Don Forsythe's "Hidden Clocks" article that describes in detail the CIA TOD clocks and their bugs, err "features". It's funny, but the LOADSTAR LETTER #40 that comes with LS #140 is subtitled "Special Commodore Hacking Issue". We were expecting C=H articles, but that shows just how egotistical we can be. Jeff Jones filled the issue with rumors of new products, handy tips, and information about CMD's SuperCPU. Of particular interest is the information about Craig Bruce modifying his Swiftlink to do 115,200 bps. Right before we went to press, issue 141 showed up in the mailbox. #141 starts off with the changes of operation since LOADSTAR publication was taken over by J & F Publishing. The first is their new address: LOADSTAR 606 Common Street Shreveport, LA 71101 Also, they say checks should now be made out to LOADSTAR, not Softdisk. For all you TUI (Text User Interface) folks, Jeff Jones goes over how to create "buttons" that depress on screen when activated. Source code is provided as well, which is rare for LOADSTAR. Of particular interest to us was Terry Flynn's "Virtual Optics" slideshow. Hard to describe, it displays impossible constructions and 3D illusions. Even C=H gets some space, as issues 3 and 4 are available on the 3.5" disk version. Jim Brain supplies article 4 in the Internet series on LOADSTAR LETTER #31, included with the issue. Of special note is LOADSTAR's new Internet address, given in the LL as loadstar@softdisk.com. See Newsfront (Reference: news) for more information. @(A): LOADSTAR 128 We loaded up LS128 #30 for a look-see. Dave's Term, the 128 Telecommunications Program presented in the last 4 issues, seems to be one focus of this issue. Don Graham supplies a keyboard overlay and macros for the terminal program, while David Jensen includes a spell checker. In the issue as well is ZED, the 128 editor of editors from Craig Bruce. @(A): Vision At press time, Issue #8 was in the works, so we'll detail the contents next time. Other magazines not covered in this rundown include: * _The Underground_ * _Gatekeeper_ * _Commodore Network_ * _64'er_ * _Atta Bitar_ (_8 bitter_) * _Commodore Zone_ * _Commodore Gazette_ In addition, others exist that C=Hacking is simply not aware of. As soon as we can snag a copy of any of these, or get the foreign language ones in English :-), we will give you the scoop on them. ============================================================================ @(#): Polygonamy: A Study in 3 Dimensions by Stephen L. Judd (sjudd@nwu.edu) We've been making some pretty small potatoes for a while now, so the time has come for a little more ambition and challenge. I decided to think up a real challenge, containing problems that I had no idea how to solve, and see what I could come up with. I set out to create a 3D virtual world for the C64, e.g. a space populated with various three-dimensional objects, which I could wander around in. I wanted it to be full-screen 320x200 hires bitmapped. Furthermore, I wanted the objects to be solid, and since there are only two colors I wanted to be able to put patterns on the faces. I also wanted it to translate nicely to the 128's VDC chip, in 2MHz mode. Finally, naturally, I wanted the program to be fast. This was the framework in which I placed myself, and a few other ideas presented themselves along the way. The outcome of all of this is Polygonamy. Just a brief history of this project: I have wanted to do a 3D world for a very long time, and have been thinking about it for some time in the back of my head; my imagination was probably first fired the first time I played Elite. I wrote down the necessary equations one afternoon last summer, for a high school student I was teaching, and the equations are very simple. I took a break to get some work of measureable value accomplished, but in October I began work on the graphics algorithm. I worked steadily on this for two months, and in December I finally began to code the graphics. In mid-January, I got them to work. Adding the rest took a few weekends more. I have about 128 pages of notes, analytical calculations, and BASIC test programs in my C64 notebook (which is, I think, a nice number of pages to have :). My original plans were to place five objects in the world, but time and memory constraints whittled that down to three. One of my disks self-destructed about the day I was ready to finish, so I had to reconstruct a bunch of tables, but other than that I finally managed to finish it up, albeit with a few rough edges ;). Although the concepts from previous articles are used as a solid foundation, the code is almost 100% from scratch -- I only borrowed a tiny piece of code from an earlier program, and even that I modified somewhat. One caveat before we begin: I am primarily interested in the challenge of designing the algorithms, which means I like to come up with my own solutions. Thus, you may find more efficient methods in a graphics book or perhaps in someone else's code; I have examined neither, so I have no idea what the relative merit of my algorithms may be. These are simply my solutions to challenges placed before me. And if you know of a better way to do things, please feel free to email me! Furthermore, I consider the code a test of the theory. Some of my assumptions work and some do not, and these will be considered at the end of this article. Finally, I am not including the source code. For one thing, it is big. Like, _HUGE_, man. I had to split it up when I ran out of editor memory on my 128 (which, incidentally, forced me to figure out Merlin 128's very cool and very powerful linker feature). I will include numerous code fragments in assembly and BASIC which demonstrate all the important concepts. By the way, if you are interested in measuring frame rates, you can use the first object. Every full 360 degree revolution is 128 frames. So time how long it takes to complete a full rev (or maybe several), and divide that number into 128, to get an idea of frames per second. For a rundown of frame rates for stock and SuperCPU operation, see "Underneath the Hood of the SuperCPU" (Reference: cmdcpu) found elsewhere in thi issue. Some brief acknowledgements: This project would not have happened without the extremely powerful macro and linking capabilities of the Merlin 128 assembler, by Glen Bredon. It would have been _really_ tough without JiffyDOS and my FD-2000, from CMD. I used my Action Replay extensively for debugging, and without the excellent documentation for the 64, such as the PRG and Mapping the 64, this would have been a nightmare. Finally, I must acknowledge my friend George Taylor; a few days before I was all finished I explained some routines to him, and he made a great suggestion which made my fast fill routine blaze. Okay, WAY too much talk. There are a ton of issues involved with this project so let's just wade in hip-deep and deal with them as they come. @(A): The Equations ------------- First some relaxing abstraction. In previous articles we have discussed how to project an object in three dimensions through the origin into a plane. We have also discussed rotations in three dimensions. In principle, then, we have all the mathematics we need to do a 3D world. But we should be thoughtful. Let's say we're standing in the world and turn to the right; we can either rotate ourselves, and change the direction we are looking, or we can rotate the world around us, so that we are always looking 'forward'. This may bother you on physical grounds, but the two are mathematically equivalent. Given the way we have derived our projection routines, it should be clear that we want to rotate the objects in the world around us. (Or, to put it another way, we are at the center of the world, and the world revolves around us.) We have another issue: how do we know when an object is visible or not? How do we know when we've bumped into an object (or blown it out of the sky :)? Moreover, if we have ten objects, and each object has six points, it would be a real drag to have to rotate all sixty points, especially if none of the objects were even visible. It should be clear that we really want to define every object relative to some center of the object. So we keep track of the center of each object, and rotate and translate the centers, and only calculate the full object if it is visible. We of course want to define the object relative to this center. What happens to this center when we translate or rotate the world? Let's simplify our model a little bit and only deal with rotations about one axis, e.g. we are driving a tank and can move forwards and backwards, and turn left or right. The generalization to other axes is very straightforward, but this way we can think in two dimensions instead of three. First we need to agree on a coordinate system. For my system I let the x-axis go _up_ a page of paper, the y-axis comes up out of the page, and the z-axis goes from left to right. Thus, I am standing on the paper in the x-z plane, at the origin, with the y-axis extending upwards from me. If you still don't understand my orientation, draw a little picture. I am going to choose my orientation so that I am always looking straight down the x-axis, e.g. in the direction that x is increasing. Thus, if I walk forwards or backwards, this corresponds to decreasing or increasing the x-component of the center coordinate: let C=(cx,cy,cz) move forwards => cx=cx-1 move backwards=> cx=cx+1 So far so good. As always, draw a picture if you can't visualize it. That takes care of translations, what about rotations? We certainly know how to rotate points about the origin. In particular, if we have a point with coordinates (x1,z1) and rotate it clockwise by an angle s, we get the new point as follows: (x1,z1) -> (x1*cos(s)+z1*sin(s), z1*cos(s)-x1*sin(s)) So that's easy enough. The problem is that we have this big object sitting around this point, and need to figure out what to do with it! Consider the following: let's say we have a line out some distance from the origin, X X | X z-axis ----O------------c---- c=center | X | X Origin X <---- line and we rotate it by some amount theta about the origin: X XX Xc c=rotated center | XX z-axis ---O------------XX- | X XX You can see (from my incredible ASCII artwork) that the line is now at an angle with respect to the origin. Imagine that we draw a line from the origin to the center of the point, in the first picture (or get a pencil and paper and actually do it), so that we have the letter "T" laying on its side. Now we rotate this "T" by some angle theta, so that the top of the "T" -- our line -- has now been rotated. The stem of the "T" meets the top of the "T" at the center point c. Drop a line from the rotated center straight down to the z-axis, and call this line l2. Since the T is at a right angle, and we have rotated it by an angle theta, the angle between our line and the z-axis is 90-theta. But this means that the angle between our line (the top of the "T") and the line l2 is just theta. Thus, if we rotate the center by an amount theta, all we have to do is rotate the object by an amount theta *about the center*, and our perspectives will all be correct. How is that for simple? It should be clear now that this works no matter where the "center" of the object is chosen. Thus, our center is not some physical center of the object, but rather the center of rotation of the object. Since this is true of rotations about any axis, we now know how to generalize to higher dimensions. Note further that we can now implement local rotations -- that is, let's say the object is a tank, and this tank turns independently of whether or not we turn. Piece of cake. You can also see that the rotations are cumulative. If we turn to the left, and then turn left again, we can simply apply two rotations to the points of the object. In fact, if we turn left, move forwards, and then move left again, we still apply just two rotations to the points of the object; the center, however, has moved. This is quite important, as it allows us to measure an object's relative rotation to us, whether or not it is visible. Remember that we only want to rotate the points that define an object when the object is visible. We never actually change the points which define an object. Instead, we track how much the object needs to rotate, and rotate the original points by that amount. The center of the object will change with each rotation and translation. We never change how we define an object about this center, though. We simply apply a rotation to the original points when appropriate. The object centers must be kept track of because they can undergo translation as well as rotation. To summarize then: we define each object relative to a center of rotation. The center determines where the object is located in the world, and allows us to operate on centers when we need to rotate or translate the world. It also lets us perform local operations on an object, so that we could, for instance, have a spinning cube located inside our world. If an object's center is visible then we can consider the object to be visible, and plot it. Whoops -- what does it mean to be 'visible'? Well, think about yourself. You can see things when they are in front of you. Or, to be more precise, you have a field of vision. Perhaps a decent model of this would be a cone. I think a better model, certainly one which is easier to deal with computationally, is the intersection of two planes: a pyramid. Anything which lies within this pyramid we consider visible, and anything which lies outside we consider not visible. Two-dimensionally, we draw a little wedge extending from the origin. Anything within the wedge we count as visible, and anything outside of it we count as not visible. The sides of this wedge are two lines, with equal but opposite slope (i.e. slope=+/-m). \ Visible / \ View / Outside of visual area \Area / \ / \ / * <--- Me Probably lines at some angle are more reasonable than others. But I'm a simple guy, and the two simplest lines I can draw are at 45 degree angles from the axis, so their slope is +/-1. Thus, any points which lie between the lines x+z=0 and x-z=0 are visible. If the center of an object is within this area, we will consider the object visible. That is, if cx+cz>0 and cx-cz>0 the object is visible. One last thing: if we are too close to the object, we either want to bump into it (i.e. not move) or else not display it. So we also need to check if cx<x0 for some x0. We are now in a position to write some simple code. I wrote the following in evil Microsoft QBasic, but BASIC7.0 on the 128 would work just as well, although you need to change the variables (I didn't have my 128 handy, otherwise I would have written this on the 128): @(A): Polygon Prototype Code SCREEN 1 '320x200 delta= 3 'Rotations will be in 3 degree increments rad= 3.1415926/180 cdel= COS(rad*delta) sdel= SIN(rad*delta) theta=0 d=-135 x0= 60 'Bumped into the object? REM z0 y0 would be 160,100 to place the object in the center REM of the screen y0= 170 'I want the bottom of screen to be ground z0= 160 REM Set up the object REM Tetrahedron: 0,sqrt(3),0 0,0,1 0,0,-1 2,0,0 DIM obx(4), oby(4), obz(4) obx(1)= 0 oby(1)= 50*SQR(3) obz(1)= 0 obx(2)= 0 oby(2)= 0 obz(2)= 50 obx(3)= 0 oby(3)= 0 obz(3)= -50 obx(4)= 100 oby(4)= 0 obz(4)= 0 cx= 100 cy= -10 cz= 0 REM Get input main: DO a$=INKEY$ LOOP UNTIL a$<>"" IF a$="[" THEN cx=cx-20 IF a$="/" THEN cx=cx+20 IF a$=";" THEN GOSUB rotl IF a$="'" THEN GOSUB rotr IF cx<x0 THEN CLS: GOTO main: IF cx<cz OR cx+cz<0 THEN CLS: GOTO main: ctheta= COS(rad*theta) stheta= SIN(rad*theta) p1x= cx + ctheta*obx(1) + stheta*obz(1) 'Rotate and add to center p1y= cy + oby(1) p1z= cz + ctheta*obz(1) - stheta*obx(1) p1y= y0 + d*p1y/p1x 'Project and add offset p1z= z0 + d*p1z/p1x [... similar for p2x,p2y,p2z,...,p4x,p4y,p4z] CLS LINE (p1z, p1y)-(p2z, p2y) [... lines between p2-p3, p3-p1, p1-p4, p4-p2, p4-p3] GOTO main: 'Main loop REM rotate left rotl: theta= theta + delta blah= cdel*cx + sdel*cz cz= -sdel*cx + cdel*cz cx= blah RETURN rotr: theta= theta-delta blah= cdel*cx - sdel*cz cz= sdel*cx + cdel*cz cx= blah RETURN (You may note that cx=cx+20 is used for a translation, instead of cx=cx+1. This will be detailed later). So much for the easy part. @(A): Filling ------- If there is one thing that the previous programs have taught us, it is that graphics are slow. At least, they are far and above the major thing slowing down the program, and deserve the most attention and thought for improvement. Moreover, because there is lots of looping involved, the elimination of just a few instructions can translate to thousands of cycles saved. We have examined several fill routines up to now, but neither of them is up to the task of Polygonamy. The cookie-cutter method is OK, but doesn't allow multiple objects, and certainly doesn't allow pattern fills. Using an EOR-buffer is just plain slow and inefficient and a big drag. So it's time to rethink this problem. Recall that on the 64 the bitmap screen is divided into 8x8 cells, which are arranged horizontally in rows. It's a pretty kooky way of doing things, but we shall overcome. First of all it should be clear that we want to fill from left to right (as opposed from top to bottom). We can then fill a byte at a time, instead of dinking in little pixels at a time. Previously we used a custom character set to plot into. One of the major reasons for doing so was to use Y as the Y-coordinate, so that storing a particular point was as simple as STA COLUMN,Y. We can still use this idea, but only within each row. That is, if we let Y=0..7, we can address each individual pixel-row within each 8x8 block row with an STA ADDRESS,Y. For real speed, we are going to want an unrolled fill routine. That is, we don't want to mess around with loop counters and updating pointers and such. Since there are 25 rows on the screen (25 times 8 = 200 pixels high) we are probably going to need 25 separate fill routines. I constructed my fill routine as follows: STA COL1,Y DEX BEQ :DONE STA COL2,Y DEX BEQ :DONE STA COL3,Y ... etc. :DONE RTS Thus X would be my counter into the number of columns to fill, A can contain our pattern to fill with, and Y can range from 0..7 to index the individual rows within the block. The first thing to notice is that each STA/DEX/BEQ code chunk is six bytes. So, all we need to do is calculate which row to start filling at, multiply by six, and add that number to the start of the fill routine. The idea is then to jump into the correct place in the fill, and let it fill the right number of columns, stored in X. There is a little problem though -- what we're talking about doing is an indirect JSR, and there is no such thing. But it's easy enough to fake, because we can use an indirect JMP. So a call to the fill routine would look like the following: ... JSR FILL ... FILL JMP (ADDRESS) where ADDRESS simply points to the correct entry point in the fill routine. Moreover, you may also note that 40 columns times 6 bytes/column is 240 bytes, so that each little fill routine handily fits in a page. Thus, moving between rows in the bitmap corresponds to a simple decrement or increment of the high byte of the ADDRESS pointer. This was the state of things when, days before I was to be all done with Polygonamy, I mentioned it to my friend George Taylor, who suggested the following modification: instead of using X to count how many columns to fill, just make the fill routine: STA COL1,Y STA COL2,Y STA COL3,Y ... Then, insert an RTS into the right place in the routine. Thus, we calculate which column to stop filling at, multiply by three, and stick an RTS in the fill routine at that point. To fix it up we stick an STA ..,Y back on top of the RTS. I don't think you're going to make a fill routine faster than that :). Moreover, note that each fill routine takes up just 120 bytes, so we can now fit two fill routines in each page. I did not do this, but it is easy to do, and instantly frees up 25 pages. @(A): Filled Polygons --------------- I mean, hey, this _is_ "Polygonamy", so let's talk polygons, and lots of them. Clearly all that is needed to draw an object are the left and right endpoints of the object, since everything in-between will be filled. An observation to make is that if you take a slice out of a convex polygon, the slice will intersect the polygon at exactly two points. Another, more important, observation is to note that the highest and lowest point of a polygon will always be at a vertex. Finally, it is important to note that any vertex of a polygon has exactly two lines extending out of it, one to the left, and one to the right. Consider a piece of a polygon: \ / \ / \ / \ / \ / * <--- Vertex v0 where the vertex v0 is the lowest point of the polygon. All that needs to be done is to move upwards (DEY), compute the left and right points of the polygon at that point, and then fill between the two (JSR FILL). The idea then is to start at the bottom (or the top) and to steadily move upwards while _simultaneously_ calculating the endpoints of the left and right lines, and filling in-between. But we need the equations of the left and right lines to do this. Now it's time for another observation. Let's say we have a polygon with n vertices v1, v2, ..., vn, and furthermore that as we move between these points we move around the polygon counter-clockwise. Thus v3 is to the right of v2, v1 is to the left of v2, v4 is to the right of v3, etc. For example: v1____v3 \ / \/ v2 What happens if we rotate this polygon? v2____v1 \ / \/ v3 The vertices have changed position, but *their order has not*. v3 is still to the right of v2, and v1 is still to the left. Now we have a real plan. We simply define the polygon as a list of points v1 v2 v3 ... vn. We then figure out which one is lowest, i.e. has the smallest (or greatest) y-coordinate, call this vertex vm (vmax). The endpoints of the left and right lines are vm-1,vm and vm,vm+1. So move along those lines until the next vertex is reached. At that point, recompute the appropriate line, and keep moving upwards until the top of the polygon is reached. Perhaps an example would be helpful: v1 |\ | \ v3 | / |/ v2 v2 is the minimum. The left line has endpoints (v1,v2) and the right line has endpoints (v2,v3). We steadily move along the left and right lines as we creep upwards. At some point we hit v3, and at this point we compute a new equation for the right line, this time with endpoints (v3,v1). Now we continue to creep upwards and move along the left and right lines, until we hit v1, at which point we are finished. It is important to keep in mind that the order of the points never changes. We don't need to do anything complicated like sorting the points; we only need to find the lowest point, and branch left and right from there, keeping in mind that the points are cyclic (i.e. v1 is to the right of vn). It is now time to start thinking about code. One aspect of the fill routine we haven't considered is the clear. In the past the entire draw buffer was cleared and then the new stuff was drawn into it. But this seems like a bit of a waste; it seems wasteful to clear a bunch of memory that is just going to be overwritten again. So, as long as we can do it efficiently, it might be smart to combine the clear and fill routines. Here is how Polygonamy does it: If a line needs to be cleared, then it is cleared up to the edges of the object, but the part that is going to be filled is ignored. (It isn't clear if this provides any substantial efficiency gains, though). To see the status of a particular line, a table is used, containing a value for each Y-coordinate. If the entry is 255 then the line is clear, if it's 0 then the line has old junk in it, and if it's 1 then the line has new junk in it. Thus we only clear the line if its entry in the fill table is a zero. So a fill routine might flow like the following: let Y count from 7..0 If we are at the left endpoint then recalculate the left line. If we are at the right endpoint the recalculate the right line. Update xleft & xright If line needs to be cleared then clear line. If the starting fill column is different than the previous fill column then update the pointers, etc. Plot the left and right endpoints (since the fill routine only plots eight bits at a time) Fill the in-between parts Update Y If Y passes through zero then update fill entry point, set Y=7 etc. Keep going until we reach the top The next thing to figure out is how to calculate the left and right lines. We do have the old line routine, which we could use to advance to the left and right endpoints, but clearly this isn't too efficient. The question is: if the y-coordinate increases by one, then how much does the x-coordinate increase by? The equation of a line is: (y-y0) = m*(x-x0) m=slope or change in y = m*change in x So, if the change in y is 1, then then the change in x is 1/m. All we need to do then is calculate the inverse-slope=dx/dy, where dx=x2-x1 and dy=y2-y1, and add this to the x-coordinate with each step in y. Isn't this a fraction? Sure, big deal. The fraction can be written as dx/dy = N + Rem/dy, where N is an integer, and Rem is the remainder, which is always less than dy. So to calculate x=x+dx/dy: x= x+N xrem= xrem+Rem If xrem>=dy then x=x+1:xrem=xrem-dy As usual, we want to start xrem at dy/2, which has the effect of rounding numbers up. 10 REM LINE ROUTINE TAKE TWO SLJ 11/24/95 12 REM ACTUALLY IT'S A FILL RTY NOW 15 GRAPHIC 1,1 20 X0=160:Y0=100 30 X1=5:Y1=-50:X2=7:Y2=11:XL=X1:YL=Y1:Y=Y1 35 X3=50:Y3=Y1:X4=X3+100:Y4=Y2:XR=X3:YR=Y3 40 D1=Y2-Y1+1:DX=X2-X1:LI=INT(DX/D1):LR=DX-LI*D1 45 TL=INT(D1/2) 46 D2=Y4-Y3+1:DX=X4-X3:RI=INT(DX/D2):RR=DX-RI*D2 48 TR=INT(D2/2) 50 DRAW1, X0+X1,Y0-Y1 TO X0+X2,Y0-Y2, X0+X3,Y0-Y3 TO X0+X4,Y0-Y4 60 REM MAIN LOOP 70 XR=XR+RI:TR=TR+RR:IF TR>=D2 THEN TR=TR-D2:XR=XR+1 75 DRAW1, X0+XL,Y0-Y TO X0+XR,Y0-Y 80 XL=XL+LI:TL=TL+LR:IF TL>=D1 THEN TL=TL-D1:XL=XL+1 90 REM DRAW1, X0+XL,Y0-Y TO X0+XR,T0-T 100 Y=Y+1:IF Y<=Y2 THEN 60 In this program (x1,y1)-(x2,y2) is the left line, and (x3,y3)-(x4,y4) is the right line. The first thing to note is that in lines 40 and 46, Y=y2-y1+1. This issue was discussed in the very first C=Hacking 3D-graphics article. The problem is that although the line will be anatomically correct with DY=y2-y1, it will look silly. The easiest way to see this is to consider y2-y1=1, e.g. say we draw a line between (0,10) to (50,11). Ideally this line will consist of two line segments, one from (0,10) to (25,10) and the other from (26,11) to (50,11). But ifi we use DY=1 we will have one line segment from (0,10) to (50,10), and a single point at (50,11). Adding one to DY is just a simple cheat. Most of the time the lines will look just fine, but lines which have a slope near one will come out a bit wrong. The other, accurate solution, which was used in the first article, is more complicated to implement in this routine. Adding one to DY will also have a useful benefit which we shall shortly see. In line 50 above the boundaries of our object are drawn in, to check the accuracy of the algorithm. In lines 70-80 the right point is updated, then the thing is filled, then the left point is updated. This is because both lines are moving to the right, e.g. they both have positive slope. Think about how the line segments will be drawn; in general, we want to draw from the left end of the left line segment to the right end of the right line segment. (Sometimes this will look a little off where the two lines meet). Since the left and right lines can each have either positive or negative slopes, there are four possibilities: Plus-Plus, Plus-Minus, Minus-Minus, and Minus-Plus. Plus-Plus: Update right, fill, then update left Plus-Minus: Fill, update left, update right Minus-Minus:Update left, fill, update right Minus-Plus: Update left, update right, fill If this is still confusing, try out the above program with various left and right line segments, and these things will jump right out. Now we need to think about implementing this in assembly. Since this is being done in hires 320x200, the x-coordinate requires two bytes, and the y-coordinate requires one. We also need another byte to store the remainder portion of the x-coordinate. The most glaring question is the calculation of dx/dy: somehow we need a fast way of exactly dividing an eight bit number dy into a nine bit number dx. Recall that we always add one to dy, so that dy actually ranges from 2 to 200. Since the maximum value of dx is 320 or so, the largest value of dx/dy that we can have is 320/2 = 160. In other words, both the integer and remainder part of dx/dy will fit in a byte. Simply adding one to dy makes life pretty easy at this end. One very fast method of doing division is of course by using logarithms. But they have a problem with accuracy. One the other hand, one thing we know how to do very quickly is multiplication. This then is the plan: use logarithmic division to get an estimate for N, the integer part. Then calculate N*dy, compare with dx, and adjust the integer part accordingly. A quick reminder of how logarithms can be used for division: log(a/b) = log(a) - log(b) exp(log(x)) = x thus a/b = exp(log(a)-log(b)). How do we take the log of a 9-bit number? We don't. Instead, we construct a table of f(x)=log(2*x), and use, not x, but x/2, as a parameter. Remember that the logarithms merely give an estimate to the integer part. Moreover, if the tables are constructed carefully we can insure that the estimate for N is either exact or too small. Thus we only need to check for undershoots, which simplifies the calculation considerably. In particular, the tables were constructed as follows: 10 DIM L1%(160), L2%(200), EX%(255): C=255/LOG(160) 20 FOR I=1 TO 160 30 L1%(I)=INT(C*LOG(I)) 40 NEXT 50 FOR I=2 TO 200 60 L2%(I)=INT(C*LOG(I/2)+0.5) 70 NEXT 80 FOR I=0 TO 255 90 EX%(I)=INT(EXP(I/C)) 95 IF(I=129)OR(I=148)OR(I=153)OR(I=81)OR(I=98)THEN EX%(I)= EX%(I)-1 100 NEXT 110 L2%(3)=L2%(3)+1 The constant C is needed obviously to improve accuracy (log(160) simply isn't a very large number). Note that I divided the arguments of the logarithms in half; instead of calculating 2*dx/dy I calculate dx/(dy/2), which is of course the same thing. This was done to make C work out. By 'fixing' the tables in this manner, exactly 3927 calculations will undershoot, which works out to about 6% of all possible calculations we may perform. The actual division routine works out pretty slick in assembly: DIVXY MAC ;Macro to compute 2*X/Y LDA LOG1,X ;This is the division part SEC SBC LOG2,Y BCS CONT LDX #00 ;dx/dy < 1 LDA ]1 ;LDA dx, since dx is exactly the remainder BCC L2 CONT TAX LDA EXP,X TAX ;X is now integer estimate STA MULT1 EOR #$FF ADC #00 ;Carry is guaranteed set STA MULT2 LDA ]1 ;ldxlo or rdxlo (i.e. low byte of dx) ADC (MULT2),Y SEC SBC (MULT1),Y ;Calculate remainder L2 CMP ]2 ;ldy or rdy (i.e. ]2 = dy) BCC DONE L1 INX ;Remainder is too large, so up int estimate SBC ]2 ;and subtract dy CMP ]2 ;Repeat until remainder<dy BCS L1 DONE <<< ;Now X contains integer, A remainder Do you see how it works? First the initial guess N is calculated. If log(x) - log(y/2) is negative then dx/dy is less that one, so the remainder is simply dx and the integer part is zero. Otherwise, R= dx - N*dy is calculated. Since N always undershoots, dx-N*dy will always be positive, so the high byte of dx isn't needed. This quantity R is the remainder, so if it is larger than dy simply increase the integer estimate and subtract dy from R, and repeat if necessary. The end result then is a 9-bit/8-bit divide which takes 52 cycles in the best case. Pretty neat, huh? And quite adequate for our purposes. Wait just a minute there, bub... what about when dy=0? Consider what dy=0 means: it means that two vertices lie along the same line. That in turn means that the next vertex can be immediately skipped to. That is, simply move on to the next point in the list, be it to the right or to the left, if dy=0. Well, ah reckon that that just about completes the polygon fill routine. To summarize: start at the bottom (top, whatever) of the polygon. Calculate the "slopes" of the right and left lines from that point. Update the coordinates, fill the in-between parts, and plot the end-sections. Then update Y and keep going. If another vertex is hit, then recalculate the corresponding line. Alert people may have noticed that this algorithm translates very nicely to the 128's VDC chip. I should probably briefly mention the pattern fills. I use Y as an index to a pattern table, so it was very natural to use 8x8 character patterns. With different indexing of course more complicated patterns can be used. Moreover, it dawned on me that animated patterns were just as easy as normal ones, so I tried to think up a few interesting animated patterns (there are two in Polygonamy, each pattern is eight frames). So that's the graphics part, more or less. We ain't even CLOSE to being done yet. @(A): 3D Code ------- Now it's FINALLY time to start writing the master program to control the 3D world. Luckily we have the BASIC program from waaaay up above to work from. First is to decide how angles will be measured. The smart thing to do is to let the angle variable vary between 0..127 or 0..255; that is, to measure angles in units of 2*pi/128 (or 2*pi/256). The reason this is smart is because the angle is now periodic, wrapping around 256. Angles can be added together without checking for overflow, etc. (257=1, 258=2, 259=3, etc.). Note that in previous programs I did a very dumb thing and let the angle variable vary from 0..119, so angles were measured in three degree increments, and I had to place all sorts of checks into the code. Polygonamy uses angle increments of delta=2*pi/128. Next there is the issue of cx=cx+20 instead of cx=cx+1. The problem is that if cx=cx+1 is used it takes forever to move around in the world. Moreover, the objects get really small at around cx=5000. What this means is that in the assembly version we can use a single byte for cx, and just treat each unit of cx as 20 "real world" units. That is, in the assembly program, we will keep track of cx/20 instead of cx. Sort-of. Consider the rotation which takes place when we turn left or right: the world is rotated through an angle delta=2*pi/128, so the calculation is: blah= cdel*cx + sdel*cz. cz= -sdel*cx + cdel*cz The problem is that sin(2*pi/128)=0.049 and cos(delta)=0.9988, which means that, in practice, cdel*cx=cx. Equally bad is that sdel*cz is very small when cz starts to get small (e.g. 10*sdel = 0.49). The result of this is that objects close to the origin (e.g. us) will not be rotated at all! Thus the centers need to be calculated more accurately. In particular, a second byte is needed to store the 'decimal' part of the center. To be precise, this second byte will contain the decimal part of the center times 256. This way we can add and subtract remainders and any over- or underflows will then affect the integer parts cx,cy,cz. Very quickly we should decide how to represent remainders of negative numbers. A number like -1.5 can be represented as -1 - 0.5, but it can just as well be represented as -2.0 + 0.5. By using the second method remainders are always positive, and that's the smart way to do things (if nothing else it lets the remainder be a fraction of 256, instead of a fraction of 128). It's also the way any computer will round: type INT(-1.5) and see what happens. further question arises about how to represent the centers, specifically, how do we represent an object which is behind us, e.g. has a negative value for cx. The normal way to represent negative numbers is of course to use 2's complement notation, but this has some disadvantages. One of them is multiplication: recall that in an earlier code some really fancy footwork needed to be done just to be able to multiply numbers between -64..64, and we certainly want the centers to range over more numbers than that. This gets worse if we decide to use more bits to represent the centers, as we must do if a larger world is constructed. Moreover, Polygonamy is an excuse for testing new and different ideas and investigating their strengths and limitations, so why not try something different. As I look through my notes I'm not really sure what motivated this choice, but how about the following: let's add 128 to all of our numbers.(I think this is called excess-128 notation). -2 will be represented as 126, -1 will be represented as 127, six will be represented as 134, etc. Shifting between the excess numbers and 'real' numbers is as simple as EOR #128. Recall that to multiply two numbers, let f(x)=x^2/4, so that a*b = f(a+b) - f(a-b). In the new system: xo = 128+x yo = 128+y which means: xo+yo = 256 + (x+y) 256+xo-yo = 256 + (x-y). The 256 added above can be thought of as the carry bit. What this means is that all that is needed is to construct a single function, f(x) = (x-256)^2 where x=-255..255. We can now very quickly multiply signed numbers in the range -128..128, and with just a single (albeit 512 byte) table, using essentially the same multiplication procedure as before. Now the downside of this method: adding and subtracting excess-128 numbers, and in particular checking for overflow. xo+yo = 256 + (x+y) if x+y >= 128 then we have overflow if x+y < -128 then we have underflow which implies: xo+yo >= 256+128 implies overflow xo+yo < 128 implies underflow with similar results for subtraction. Note also that after every addition or subtraction 128 needs to be either added or subtracted from the result, which either way corresponds to an EOR #$80. So it's a little more work to add numbers in this system. (Of course, adding normal numbers to excess-128 numbers is no problem, so INC and DEC work fine). Back to rotations. The most obvious thing to do is to create two tables: f(x) = (x-128)*cos(delta) + 128 g(x) = (x-128)*sin(delta) + 128 but remember that the remainders are also needed: fr(x) = 256*(remainder((x-128)*cos(delta))) gr(x) = 256*(remainder((x-128)*sin(delta))) Since remainders are always positive none of this excess-128 junk is needed. Note that we could also let f(x) and g(x) be 2's-complement tables, then convert from two's-complement into excess-128 after performing additions etc. The conversion is, what do you know, EOR #$80. This is the smarter thing to do, and an even smarter thing to do is to let the cosine table (f(x) above) to be in excess-128 format, and the sine table g(x) in 2's complement. This way the numbers can be added as normal, and no conversion need take place: * Compare to BaSiC subroutine rotl: above ROTL INC THETA LDY #NUMOBJS ;Y indexes the object DEY :LOOP LDX CX,Y ;center coordinate LDA CDEL,X ;CDEL = f(x) above LDX CZ,Y CLC ADC SDEL,X STA TEMP ;t1 = ci+si LDA CXREM,Y CLC ADC SDELREM,Y ;Add remainders BCC :CONT1 INC TEMP CLC :CONT1 LDX CX,Y ADC CDELREM,X BCC :CONT2 INC TEMP :CONT2 STA CXREM,Y LDX CZ,Y LDA CDEL,X LDX CX,Y SEC SBC SDEL,X STA TEMP2 ;t2=cz-si LDA CZREM,Y SEC SBC SDELREM,X BCS :CONT3 DEC TEMP2 :CONT3 LDX CZ,Y CLC ADC CDELREM,X BCC :CONT4 INC TEMP2 :CONT4 STA CZREM,Y LDA TEMP2 STA CZ,Y LDA TEMP STA CX,Y DEY BPL :LOOP Well, that takes care of two lines of BASIC code :). As it turns out, using a single byte for the remainder does a pretty good job of holding the number. Rotating by 360 degrees one way, then rotating back again, produces a center which is within a few decimal places of the starting value. Next up: projections. The projection calcuation is: Proj(P) = d*(P+C)/(px+cx) where P=(px,py,pz) and C=(cx,cy,cz). In terms of the implementation, we want to calculate: d*((P-128) + s*(C-128)) / ((px-128) + s*(cx-128)) where s=20, to translate C into the 'real world'. To calculate this, consider the following function: g(x) = r*d / (s*((px-128)/s + cx-128)) + 128 where r is some scaling factor. The projection calculation then becomes: 1/r*( (g-128)*(P-128) + s*(g-128)*(C-128) ) Thus we need some more tables, one of 1/(4r) * (256-x)^2, the other of s/(4r) * (256-x)^2, to do the multiplication. Furthermore a table of (x-128)/s would be pretty handy, and finally we need a table of g(x) = r*d/(s*(x-128)) + 128. The general outline of a program would be: Get keypress 1- If translate, then update all cx's (just some INCs and DECs) 2- If rotate left or right, then rotate world 3- Update angles for global & local rotation matrix (e.g. theta) 4- Figure out which objects to display/construct a list 5- Call each object in turn 6- Update bitmap: clear out remaining garbage and swap bitmaps Numbers 1 and 2 are done. In number three, by global matrix I mean the object rotation that results from us turning left or right. By local rotation I mean rotations independent of whether or not we turn. The local rotation allows e.g. the octahedron to spin around in Polygonamy. Figuring out which objects to display is easy: just check to make sure it lies within the viewing cone/pyramid, that we are not too close, etc. If an object is to be displayed, it needs to be placed in a list. I constructed the list to make sure that objects which are farther away are drawn first; that way objects can overlap one another correctly. This was done via a simple insertion sort -- i.e. bump up objects in the list until the right spot is reached to insert the object. We have most of the tools to deal with #5. Handling an object consists of rotating and projecting it, then displaying it. Rotation is the same as it has always been, albeit now involving sixteen bits, and projection is described above. Then each polygon needs to be drawn, by sticking the points of the polygon into the polygon list, setting up the fill pattern and the pointer to the minimum Y-value, and calling the polygon fill routine. Of course, if the face is hidden then we certainly don't want to plot it. The minimum y-value can be found very easily while inserting the points into the point list -- just keep track of ymax and compare to each point as it is inserted. We have discussed several methods of calculating hidden faces -- cross-product, rotated normal, parallel faces -- each of which involves looking at a vector normal to the face, and either projecting it or taking the dot product with a vector going to the origin. What a big pain in the butt, especially since values can be sixteen-bits, etc. Did you ever stop to wonder about what happens to all the previous polygon-fill calculations if the point-list is entered in reverse order? Quite simply, left -> right and right -> left. And what happens when a face is invisible? The polygon is turned away from our eye. The points in the polygon, which go counter-clockwise around the polygon, will go clockwise when the polygon is turned around. (I should point out that at least in my code the points on the polygon are actually done in clockwise-order, since projection reverses the points). So, we have hidden-faces already built-in to the polygon plot routine! In essence, we simply don't plot any polygon which the routine will freak out on. We can of course be systematic about this; within the plot routine: - Calculate the left and right lines. - Take a trial step along the left and right lines - If xleft < xright then we are OK, otherwise punt. In principle we only need to do this on the first calculation, and use some properties of the lines to make things easier (for instance, if the left line is moving left and the right line is moving right, and they emanate from the same point, we know the polygon is visible). Unfortunately, nasty situations can arise, for instance when the left and right slopes have the same integer parts. So a check needs to be placed within the fill code to make sure the left point doesn't get ahead of the right point. This is unfortunate, as every cycle counts in the fill code, but luckily there is (was) a natural place to put in a quick check. All that is left then is #6: run through the fill table, and clear any lines that still have old junk in them. Since I used two bitmaps as a double-buffer, all that is left is to swap the bitmaps, and do it all again. Et voila. @(A): Analysis and Conclusions ------------------------ As you can see, the program is not without its flaws. The biggest one, I think, deals with the projection. Recall that I calculate px/s, where s=20, and add it to cx. My feeling was that px was going to be very small compared with cx, and so not modify the projection by much. But either this is a bad assumption, or the rotations are all screwed up, because certain rotations look a bit goofy. For instance, when you walk up close to the octahedron it starts to get jumpy, or wobbly. I note further that when you are far away from an object it looks much better, so that might be a way to fudge around the problem (e.g. make the value of d in the projection much larger). Speaking of rotations, the 'funky shake' which used to plague the old programs has now been fixed. For instance, a rotation in the y-direction would work well but at some point it would appear to start rotating backwards, then start going the right way again. The problem was due to an overflow in the calculation of the rotation matrix, in a term that looked like(sin(t1) + sin(t2) - sin(t3) - sin(t4))/4, and the solution is to split such terms into two, e.g. (sin(t1)+sin(t2))/4 - (sin(t3)+sin(t4))/4. Speaking further of rotations, I find the current system of rotation and projection unsatisfying, in particular too slow. Notice how much the program slows down when all three objects are visible; some 40 points are being rotated, both locally and globally, at this point. It is possible to reduce the number of matrix multiplications from 9 to 8 (and even lower, with lots of extra overhead), but I find this unsatisfying. A better method is needed... There is another bug somewhere in the global rotations which sometimes causes the objects to wander around -- occasionally I can get the ship or the octahedron to move close to the pyramid. Also, when you are really close to an object and turn, you might notice the curious effect of the object rotating by small amounts, and then jumping position by a large amount. This is due to the 'units of 20' that are used in the program; the remainder part of (cx,cy,cz) needs to be used here, and then the display will be smooth as well. Of course, if multicolor mode was used many of the calculations would be much simpler, since the screen x-coordinate would only require one byte instead of two. The program should be made more efficient memory-wise of course. Shoving the fill routines for each buffer together would help out, and a system for rotating points out of a list, similar to that used in the last 3D program, would greatly streamline things (although it would be a tad slower). There is still a minor bug or two in the fill routine, which causes little blue chunks to be taken off the ends of some polygons, but I didn't feel like tracking it down. Note that although Polygonamy only lets you run around in a plane, running around in a full three dimensions is quite simple to add. And, although there are only three objects in the world, it is all set up to deal with a lot more. In summary, I see no major problems standing in the way of doing reasonably fast 3D graphics on the 64. The object file for this article is available in "Hacking the Code" (Reference: code, SubRef: polycode) found elsewhere in this issue. ============================================================================ @(#)usenet: UseNuggets COMP.SYS.CBM: The breeding ground of programmers and users alike. Let's see what topics are showing up this month: @(A): What is the HECK is BCD? As most ML programmers know, the 65XX CPU line has a arithmetic mode called "decimal mode", and is used to manipulate Binary Coded Decimal numbers (BCD). BCD numbers treat each nybble as a decimal digit. Possibel values for a byte than ar $00 to $99. Some fool asked on the group what earthly use BCD has on the 65XX CPU. Well, among other things, Willem-Jan Monsuwe shared this tidbit: I recall someone asking what the use of BCD (Binary Coded Decimal) was. I have here a 99-byte program that uses it to print out a number stored in the memory in decimal, with a maximum of more than 10^500 digits, Within 5 seconds ;). What's the use ?? Well, you can impress your friends by calculating the answer to the chessboard-problem ( 2^64 - 1 or 0xFFFFFFFFFFFFFFFF ) within 0.06 of a second. Oh, and the maximum is pretty easy to overcome, with a slight code change, if anyone needs numbers greater than, oh, 509 digits.. ;) * = $1000 SNUM = $1100 BUFF = $1200 PRINT = $FFD2 SNUMPTR = $FB SNUMBF = $FC BUFFEND = $FD LDA #0 TAX CLRBUFF STA BUFF,X INX BNE CLRBUFF SED STA BUFFPTR LDY #210 STY SNUMPTR BYTELOOP LDA SNUM,Y STA SNUMBF LDY #8 BITLOOP ASL SNUMBF LDX #0 ADDLOOP LDA BUFF,X ADC BUFF,X STA BUFF,X INX BCS ADDLOOP CPX BUFFEND BCC ADDLOOP STX BUFFEND DEY BNE BITLOOP DEC SNUMPTR LDY SNUMPTR CPY #$FF BNE BYTELOOP CLD LDA #13 JSR PRINT DEX LDA BUFF,X AND #$F0 BEQ LOWNYB PRINTLOOP LDA BUFF,X LSR LSR LSR LSR CLC ADC #48 JSR PRINT LOWNYB LDA BUFF,X AND #$0F CLC ADC #48 JSR PRINT DEX CPX #$FF BNE PRINTLOOP @(A): Commodore's Can't Compute! (or can they?) OK, try the following on your beloved 128: print 23.13 - 22.87 hit RETURN Do you get .260000005? The resuling thread after this question was posed started to lean in the direction of attacking the arithmetic units of BASIC in the Commodore 8-bit machines. Then an eloquent post from Alan Jones (alan.jones@qcs.org) started to set the record straight. We can't express it any better than Alan: Recently, the C64/128 floating point arithmetic has been maligned here. The C64/128 has good floating point math. It uses 5 byte reals with a 4 byte (32 bit) mantissa. There are no bugs in the basic FP arithmetic. The reals ARE limited in range and precision. They are more useful than compters using 32 bit reals, but not up to IEEE standard arithmetic. IEEE FP arithmetic (double and extended precision...) would be much slower than our existing FP routines. Of course it might be possible to interface a hardware FPU to the new Super64/128CPU (65816). The other C64/128 FP routines, such as SIN, EXP, and functions that use them are not accurate to full 32 bit FP precision. When used with care, they are often accurate enough for engineering work. The most annoying inaccuracy may be the conversion between binary FP and decimal for I/O. BASIC only prints 9 decimal digits of a FP number, but our binary FP number has about 9.6 decimal digits of precision. What you see is not what you have! Of course there are some simple tricks that you can use to print the FP number with more decimal precision, and you could do I/O using HEX notation. If you save intermediate results for later use, make sure you write the FP values as binary rather than ASCII (converted to decimal). If you do accounting type stuff with dollars and cents, using binary FP with its limited precision and rounding can be anoying. If your results are off one penny, all of your work will be suspect. Our 6502 family of CPUs also has decimal arithmetic. It can do decimal arithmetic exactly, although you may have to program it yourself. I think the Paperclip word Processor will do simple calculations with up to 40 decimal digits of precision. If you are using 64+ bit FP you can compute some things in a fast and sloppy manner. Some programs that work OK on an IBM PC or workstation need more careful attention when coded for a C64/128. Some numbers can not be represented exactly in binary FP formats of any precision. If you want to calculate: a:=(1/3)*(1/5)*(1/7)*(1/11) You should code it as: a:=1/(3*5*7*11) Aside from being faster, it is more accurate. There are many tips for preserving numerical accuracy in computations. There are often interesting tradoffs between computation speed, memory usage, and accuracy and stability. There are even some C64/128 specific tips. (e.g. we usually store a real value in 5 bytes of memory but push it onto a stack as 6 bytes when we want to use it.) This is not intended to be a Commodore FP tutorial. It is reminder that the C64/128 can be used for "heavy math", and there are no bugs in the Commodore +, -, *, /, Floating Point arithmetic routines. It uses 32 binary bit mantisa FP reals with proper rounding. Simple examples can always be contrived to demonstrate a perceived FP bug by computer illiterates(?). Alan got his dig in at the end there. That post, and others like it, pretty much squelched the arithmetic discussion. But, as is usually the case, we all learned a neat trick along the way. Peter Karlsson shared his easy way of determining whether his programs are running on a C64 or C128 by issueing the following statement: C=64+64*INT(.1+.9) Since the 64 and 128 differ ever so slightly in their arithmetic routines, the above line gives 64 on a C64 and 128 on a C128. @(A): We need another OS! It all started when Benjamin Moos posted a message in the newsgroup mentioning that he had been off the net for a while but was returning and wondered whether anyone would want him to finish work on a C++ based comiler for the GEOS 2.0 environment. Of course, everyone was for that, but Moos continued on, asking if there was any interest in an alternate OS for the 64 or 128. Moos mentioned that he had been also working on Common Graphic OPerating Environment (CGOE), and was thinking about finishing the project, which would provide a C= graphics character based graphic windowing system that would allow all 64 programs to run in the 128 80 column screen in 40 column windows. Well, that brought out some friendly debate, to state the obvious. Part of the group posted words of encouragement, noting that we need to support those programming for the environment. The other half of the camp echoed the words of Patrick Leung, who expressed concern that there are many programmers in the arena that are doing the same thing separately. He encouraged programmers to consolidate features and code bases to arrive at robust full-featured programs instead of fragile bare- bones applications that single programmers can't support. ACE, Craig Bruce's UNIX-like OS detailed in earlier C=Hacking issues, was brought up by some, who asked that programmers heed Leung's advice and build modules for the already supported ACE environment. Perhaps J. Shell has the best idea, as he is planning to set up an interactive WWW site to allows programmers to work with him to build COMMIX System II (CX2). The site will allow programmers to bring new ideas to the table and have them rapidly incorported into the design. We'll see if Mr. Shell can deliver on this neat idea. Going full circle, Benjamin Moos reponded to some of the posts, saying that the OS work was going to be placed on the shelf for now, as many had expressed interest in the C++ like compiler. However, he did say that work would begin again at a later date, but no decision was made as to how he will proceed. @(A): The "More Power" Swiftlink Ever striving to squeeze the most performance out of his C128 system, Craig Bruce modified his Swiftlink and lived to tell about it in the newsgroup.. Basically, after researching the data sheets for the 6551 ACIA IC used in the SL, Craig noted that Dr. Evil Labs (the original creators of the SL) had used a double speed crystal to up the 19,200 bps maximum in the ACIA to 38,400 bps. The IC claims that any baud rate up to 125,000bps can be achieved with the IC, given the correct crystal frequency. Well, another feature of the 6551 is to use the crystal frequency/16 as the bps rate, which is 230,400 bps or the stock crystal. Too fast for the IC. However, by replacing the crystal ( a 3.6864 MHz unit) with a 1.8432 MHz unit, the 1/16 speed becomes 115,200. That speed, less than 125,000 bps, is the standard top frequency for IBM UARTs and is supported by most newer modems. Craig verified that his 2MHz 128 can keep up with the extra data that his modofoed SL allows him to receive, but not always. he claims that every once in a while, the systm gets choked up and crashes, so he is working on solutions. Understandably, one will need very tight terminal program code to keep up with this speed, but it will fit nicely with the SuperCPU. As with all things, there is a downside in that 19,200 becomes the next lower bps rate. 38,400 is gone forever. Craig speculated that perhaps a switch could be installed, but wasn't sure of the effects. @(A): The Eternal Problem Although this didn't receive much discussion, C=Hacking feels many users can relate. How many have ever went into the local CompUSA of local computer store and asked to look at modems, printers, or SCSI drives, only to hear the dreaded laugh and chide that you should "buy a REAL computer", or watch the quizzical look of the sales person as they exclaim "You can't hook that up to a Commodore!" We particularly enjoyed the ending to the lament that appeared in the newsgroup: When someone keeps an old car around, babies it, works on it, adds to it, drives it around in style, no one says "Look at this dummy driving an out-dated gas guzzler that can't even do 80, and gets atrocious gas mileage. The frame is archaic. The windows aren't electric. Why doesn't he upgrade?". Nah.. they are 'enthusiasts of classic automobiles'. Well, ... we are "enthusiasts of a classic computer". ============================================================================ @(#)fido: FIDO's Nuggets The CBM and CBM-128 FIDONet echoes. The place where Commodore users unite. Let's what things they discussed over the past month or two: @(A): UNZIP 2 or not UNZIP 2? For a while now, Commodore users have been able to uncompress archives created with the popular PKZIP 1.01 compression program by PKWare or one of its clones. Well, PKWare upped the ante and upgraded the PKZIP product to version 2, and that left a bunch of Commodore users compressed! The easy solution is to ask all archive creators to not use version 2 of the ZIP product, but that presents a problem. Most of the FIDONet crowd reads their mail offline via popular programs like QWKIE 3.1 on the 64 or QWKRR128 4.3 on the 128. The programs work by retrieving a COMPRESSED packet of news and mail from a BBS. Well, it turns out that BBS systems have migrated over to the new version of ZIP, and some refuse to offer ZIP version 1 as an optional compression method for retrieval packets. So, the FIDONet crowd, including David Schmoll and others, have been working on or searching for a way to bring PKZIP 2 functionality to the 64. Some thought it was a done deal when a FIDNetter contacted Info-Zip, the authors of a free clone of PKZIP 2 by the same name. They were told the source code was available. The catch, it is written in C, and so far, no compilation on the 64 or 128 has been successful. @(A): QWKIE v3.1 FREE! Many C64 users have delighted over the use of QWKIE v3.1 to read offline news and mail. However, many had been unable to register the product. The mystery was solved as of late a letter by the author was read that stated that he was ceasing support for the product and had placed it into the public domain. As well, interested programmers could contact him about source code. So, QWKIE FREE, a patched version of the program that is marked as registered, was uplodade to the many CBM BBS systems for users to enjoy. @(A): That Darn Internet! As of late, many FIDONet regulars have been diappointed in the trafiic flow on the CBM echoes. They blame the growing popularity of the Internet as one reason the amount of messages has dwindled. Almost immediately, reasons why FIDONet is still useful started popping up in the echoes. Many claim that the Internet and FIDONet are complementary for the Commodore user, and that both resources are needed. Others, however, stressed that FIDONet is still the most useful. While C=Hacking isn't going to cast a vote here, we do hope that interest in the echoes stays high, as some only have access to FIDONet, and Commodore support should be on every network. @(A): Let's Randomize Some soul on the echo was looking for a way to generate a random number from 2 to 350. Well, always eager to help, many FIDONetters came to the rescue, with varying degrees of complexity. The first post, by Ken Waugh, included the text from one of Rick Kepharts WWW Site pages that explained, in two BASIC lines or less, how to create a set of 255 nonrepeating random numbers. Then, ever the guru, George Hug, of 2400 bps on a 64 fame, described a method to find random numbers based on "linear maximal length shift registers", complete with 3 part article on the method. Wow! needless to say, the method looks promising, but was probably more than what the original author was looking for. Nonetheless, the treatise looks worthy of inclusion in an upcoming C=Hacking issue. @(A): Catch the Wave! By now, most know that Maurice Randall, the author of GeoFAX, has been working on a GEOS telecommunications program that will operate at the 14,400 bps or better mark. It's been discussed in both USENET and FIDONet before, but Gaelyne Moranec reopened the discussion with a statement that World Wide Web page viewing support might possibly be incoporated and under test. Mr. Randall was hoping to add such support at some time, but it was unclear when. It looks like sooner rather than later. @(A): Who's First? Rod Gasson posed an interesting question on FIDONet a while back. He asked which CPU was in control of the 128 when it is first powere up. The abvious answer of "the 8502" was given many times over, but Rod finally noted that it is, in fact, the Z-80 in the system that gains control of the system first. Herman Yan supplied the relevant page from the C128 Programmer's Reference Guide that explains the reasons. If you want to know more, check out page 576 in the manual. @(A): Desterm Confusion Many in the 128 arena use a telecommunications program called Desterm, by Matt Desmond. At present, there are two versions of the shareware application out, 2.00 that works on all drives except the RAMLink, and 2.01 that works with RAMLink, but has bugs not present in 2.00. So, which to use? That questions gets asked in verious forms in the echoes repeatedly. That, coupled with the inability to find Mr. Desmond for a while, the supposed hand-over of the code to Steve Cuthbert, and the recent emergence of Matt (Reference: news) added to the confusion. The current thinking is that Matt will be working on a new release of Desterm that will include CTS/RTS support (the present version only supports XON/XOFF flow control) and some bug fixes. Somehow, the rumor that Matt will add Z-modem capabilities keeps pooping up, but Matt has denied any such work. He merely doesn;t see a need, since add in modules can be created to do this. So, that gives you a glimpse into the world of FIDO, the wonder dog of networks. C=Hacking laments that their own FIDO feed has been experiencing problems as of late, so we too may have missed some juicy tidbits. We'll catch them later on, though. Here, boy.... ========================================================================= @(#)cmdcpu: Underneath the Hood of the SuperCPU by Jim Brain Does your mind go blank when you hear about the SuperCPU? With all the mention of it in magazines and newsletters, are you left wondering how much of the discussion is hype and how much is true? Are you worried that this latest attempt is just another design destined for failure like the others before it? Well, if so, then you're not alone. With the reputation accelerator cartridges and their manufacturers have acquired over the years, you are wise to be concerned. Judge for yourself, as we peer under the hood of the Creative Micro Designs SuperCPU accelerator cartridges. Note: The information contained in this article has been gleaned from talks with CMD, Mr. Charlie Christianson's post to comp.sys.cbm, responses to USENET posts by Mr. Doug Cotton, and information from Commodore World Issue #12. While general information is not likely to change, some details discussed in this article may differ slightly from those incorporated in the final product. @(A): What's An Accelerator? Did you know a Commodore 64 CPU executes things at 1 MHz? A tiny clock inside the 64 ticks off 1 million "cycles" per second, and instructs the CPU to move forward one cycle at a time. The CPU, in turn, either executes an internal operation, reads from memory, or writes to memory during that cycle. These operations are concatenated to form funtions, which is the smallest piece of work a programmer can ask the CPU to perform. These function are called instruction, and take an average of 3 cycles each to perform. So, the typical C64 CPU does 333,333 things a second. The C128 fares a bit better, as it can run twice as fast when in "fast" mode. In either case, there is an upper bound on the amount of useful work each CPU can do in a amount of time. An accelerator increases that amount of work done by substituting a faster CPU and clock speed for the 1 MHz 64 CPU. The ratio of increase should be as easy to determine as dividing the new clock frequency by 1 MHz for a 64. If this were true, an accelerator that runs at 4 Mhz would execute things at 4 times the speed of a stock 64. Sadly, this is not true, since not all parts of the system can be sped up to the higher frequency. So, the accelerator runs at full speed while it utilizes ICs designed for the faster clock speed, and slows down when it must "talk" with ICs like the SID and VIC-II in the 64, which run only at the slow 1 MHz clock speed. Most accelerators are produced as large cartridges that plug into the expansion port of the computer system. Some require special wires be attached to internal components, while others do not. @(A) The New Kid on the Block In mid 1995, Creative Micro Designs, after having evaluated the FLASH 8 accelerator from Europe with only mild success, noted that there might possibly be a market for a speedy accelerator that would run GEOS and other useful applications in the USA. After surveying the readership of Commodore World, the Internet, and FIDONet, CMD decided that interest in such a unit was forthcoming. Shortly thereafter, the SuperCPU announcement was made. As development work ensued, progress reports and preliminary information about the product surfaced from CMD. The first items involved the processor choice, which was originally the 65C02S but is now its bigger brother, the 16 bit 65C816S. Another piece of information involved the case, which is an enclosure 6" wide by 2" deep by 3" wide. This enclosire contains a circuit board protruding from the front of the unit that will plug into the Commodore 64 or 128 expansion port. In back, a complementary card edge connector is provided to pass signals through the cartridge. This will allow users to attach other expansion port cartidges to the system. On top sit three switches, described below. The first switch enables or disables the SuperCPU unit. The second switch enables or disables JiffyDOS, which is built into the unit. The third switch determines the speed of the unit. This third switch has three positions. The first position forces the accelerator to operate at 1 MHz speed (the same speed as the stock C64). The second position allows the programmer to change the speed via a register in the SuperCPU memory map. The third position locks the SuperCPU into 20 MHz mode, regardless of register settings. The use of the CMD SuperCPU will be straightforward. Simply plug the unit into the expansion port, set the appropriate switches on the top of the unit, and powering on the unit. @(A) Technical Details The basic system utilizes a WDC W65C816S 16 bit microprocessor running at 20 MHz. This CPU can not only fully emulate a CMOS 6502, it can be switched into "native" mode which allows access to 16 bit registers and 16 megabytes of RAM without bank switching, DMA, or paging. Attached to the CPU is a bank of 64 kilobytes of Read Only Memory (ROM) and 128 bilobytes of high speed static RAM (SRAM). The extra RAM above 64 kB is used to "mirror" the contents of the slower ROM. See below for details. A number of features designed to maximize the performance of the SuperCPU are being developed into the unit. Since the late 1980's ROM speeds have not been able to keep pace with CPU clock frequencies. With the CMD accelerator moving into the frequency range of newer PC systems, this becomes a problem for the SuperCPU as well. The Commodore typically stores its KERNAL and BASIC code in ROMS, and the SuperCPU will need to read that code. The easiest solution is to read the stock ROMs in the computer, but those ICs can only be accessed at 1 MHz (they are part of that set of older ICs that cannot be utilized at 20 MHz). So, the next option is to copy that code into faster ROMs and instal those ROMs int the cartridge. Well, as stated earlier, ROMs of sufficient speed are very expensive and not widely available. So, the third option, which is the one CMD will use, is to copy the KERNAL and BASIC at startup to RAM and write protect the RAM area, making it look like ROM. Fast static RAM (SRAM) is available to meet the 20 MHz clock requirements, and is not terribly expensive, as most new PC systems use the same memory for similar uses. This technique is called ROM shadowing and has been utilized for a few years in the IBM PC community. The heart of the unit is the Altera Complex Programmable Logic Device (CPLD). Analogous to electonic "glue", this single chip can replace ten or hundreds of discrete ICs in circuits. This unit is responsible for decoding the complex series of signals presented in the expansion port, handling DMA requests to an REU unit, emulating the specialize I/O port found at locations $00 and $01 on the 6510 CPU, and handling the synchronization of the SuperCPU memory and C64 memory. One item that has plagued accelerator designers for years and minimized the widespread acceptance of accelerators invoves this RAM sync operation the Altera CPLD handles. In areas of the stock C64 memory map where only RAM is present, like $0002 - $40959, the synchronization of memory can be handled very easily. However, when dealing with areas like $d000, where RAM AND IO can be present, the situation becomes more complex. The SuperCPU overcomes this problem as well, which is important since many video applications use the RAM under IO at $d000 for graphics or text. As the VIC-II IC in the C64 and C128 requires that screen information be present in on-board memory, memory "mirriring" is necessary. However, CMD has introduced two new technologies, called WriteSmart(tm) and CacheWrite(tm) to reduce the slowdown associated with mirroring the SuperCPU SRAM and the slower on-board DRAM. According to documentation, WriteSmart allows the programmer to decide which portions of memory need mirroring. The four selections include "BASIC", where only text and color memory are mirrored, "GEOS", where GEOS foreground bitmap and color memory are mirrored, "ALL", where all 64 kB of RAM is mirrored, and "NONE", where the SuperCPU does not attempt to syncronize memory contents between the two RAM areas. The other technology, called CacheWrite(tm), minimizes the effect of this mirroring. When storing a value into SuperCPU RAM in a range of RAM that requires mirroring, the value is stored not only in SuperCPU RAM, but also into a special cache memory location. The SuperCPU is allowed to continue processing, while the system waits for the on board DRAM to acknowledge readiness to store a value. When successive stores to mirror ranges are done, the system must slow down, but can still operate at about 4 MHz. This speed is achieved because the SuperCPU need not wait for the value to be successfully stored before it attempts to fetch the next opcode and operand. Since opcodes that write value to memory avarage 4 cycles to complete, the SuperCPU can effectively do 4 cycles worth of processing in 1 period of the 1 MHz clock. Note that this slowdown does not occur if the cache is not full when a store instruction is executed. @(A) Features Being a CMD product, the CMD SuperCPU comes with JiffyDOS, CMD's flagship speed enhancement routines, installed. However, JiffyDOS can be switched out for those applications that fail to run with this serial bus enhancement functionality. The unit also features compatibility with RAMLink, CMD's RAM drive unit. As the RAMLink fucntions by sharing the CPU with the computer system and runs a special set of instructions called RL-DOS, the SuperCPU contains its own version of RL-DOS optimized to take advantage of the speed and extra features available in the 65C816S. Preliminary information suggests that RAMLink data retrieval, typicially much slower the REU data retrieval, will now operate at speeds approaching that of the REU. In addition, the on-baord RL-DOS will handle usage of the special parallel CMD HD drive cable available with the RAMLink. For those with expansion in mind, CMD has incorporated a special expansion port internal to the unit. The port, called the "Rocket Socket", will allow access to the complete signal set from the W65C816S CPU and possibly other support ICs. This will allow developers to produce peripheral cards for the unit containing hardware that will run at 20 MHz (The cartridge port will still be limited to slow speed). @(A): Myths About the Unit In the early phases of development, CMD hinted that possibly extra RAM installed in the unit could be used as a fast RAM disk, a la RAMLink. However, the inability to battery back up that RAM area, coupled with the small increase in speed gained form doing so and the lengthy development time needed to realize this feature, has prompted CMD to abandon this idea for the time being. Later in the development cycle, such an idea might resurface, but the feature is most likely never to be implemented. Also, early information about the units noted that two speed options would be available, but low support for the slower 10 MHz model prompted CMD to discontinue development on that version. As of now, there is only one speed option available: 20 MHz. When CMD first announced the unit to the public, it was to include the Western Design Center W65C02S microprocessor. However, in late 1995/early 1996, CMD opted to switch from that CPU to its bigger brother, the W65C816 16 bit CPU, owing to small increase in per item cost, more flexibility, and more expansion options. Although the speed of the CPU in the SuperCPU unit is running at 20 MHz, that does not imply all operations will occur twenty times faster. Some operations, like reads from I/O ICs, derial bus operation, and mirroring of video memory, require the CPU to slow down temporarily. This will reduce the effective speed to about 17-18 MHz. @(A): Compatibility Issues All legal 6502/6510/8502 opcodes are supported in the accelerator. Undocumented or "illegal" opcodes are not supported and will fail. Although not a compatibility issue, some applications that rely on the CPU running at a certain speed to correctly time events will most likely fail or operate too quickly to be useful. Event or interrupt driven code should operate correctly. The SuperCPU 64 model will operate correctly with any C64 or C64C model of computer system, as well as with any C128 or C128D in 64 mode. However, CMD has recently announced a 128 native version of the cartridge. @(A): Super128CPU In early 1996, CMD announced that interest was compelling and that would begin development on a 128 version of the SuperCPU. As a result of this announcement, the ship date was moved from Februarty to April as CMD validated the SuperCPU design so that it could be used to manufacture both the SuperCPU 64 and SuperCPU 128. Both units will operate at a maximum of 20 MHz, and will most likely be packaged in the same enclosure. The SuperCPU 128 will operate in both 64 mode and native 128 mode. It will not enhance CP/M mode on the C128. CMD announced that the availability of this unit would be Auguest or September ot 1996. As far as cost is concerned, a current estimate falls at $300.00, and advance orders are being taken with a security deposit of US$50.00 needed to place an advance order. As this announcement was made, some confusion has resulted in the naming scheme. Previously called the SuperCPU or SuperCPU 64/20 (64 model at 20 MHz), the new models are referred to as alternately: 128 model 64 model Super128CPU Super64CPU SuperCPU 128/20 SuperCPU 64/20 @(A) Prototype Testing and Benchmarks As no developer unit have shipped as of this date, CMD has the sole unit availabel for be testing and benchmarks. CMD's prototype unit consists of a handwired unit on perfboard. At first, CMD was hesitant that the prototype would actually run at 20 MHz, since such designs are not "clean" and can suffer from eignal degradation, signal skew, and crosstalk, which inhibits operation at higher frequencies. So, with that in mind, early tests were done at 4 MHz. CMD reported in late Fenbruary 1996 that the prototype had been ramped up to 20 MHz and was operating correctly. In fact, the unit appears to run faster than it can, illustrated by the following example: CMD tested the following program at 1 MHz on a Commodore 64 10 TI$="000000" 20 FORI=1TO10000:NEXT 30 PRINTTI The result from this test was 660. After enabling the unit, the test was rerun and the result printed out again: 31. Quick calculations by the CMD personnel verified that the unit was executing this program 21.29 times the normal speed. However, that is impossible, as the CPU is only clocked 20 times the nortmal speed. The supposed impossibility is explained if you delve deeper into the timing of the 64. As many know, the VIC-II "steals" cycles from the CPU in order to refresh the VIC-II video screen. Extra cycles are "stolen" for sprites. With the SuoperCPU disabled, the above code runs at 1 MHz minus the amount of time the VIC-II "steals" from the CPU. With the SuperCPU enabled, the VIC-II does not "steal" cycles from the unit, as the accelerator uses it own private memory area for operation. The VIC, meanwhile, uses the on-board C64 memory. CMD notes that games that use timers or are event driven function correctly, but hotse that count processor cycles or utilize spin-wait loops run so quickly as to be virtually unusable. Of partiular note to Commodore Hacking readers is the test done with the object code for the Polygonamy (Reference: polygon) article elsewhere in this issue. On a stock 64, the program renderes approximately 12-13 frames per second. With the SuperCPU enabled, the frame rate jumped to 128 fps. CMD notes that further gains might be realized if the code was modified to cooperate more fully with the CupserCPU memory scheme. As for Ram Expansion Unit compatibility, CMD responds that the issues have been tackled and that DMA operation is available on the SuperCPU unit. In adiition, CMD notes that the CPU need not be running at 1 MHz to initiate a DMA transfer. As stated from the beginning, the 64 model of the SuperCPU accelerator wil work on the Commodore 128 in 64 mode, and test have confirmed that the prototype 64 model does indeed frunction correctly any the C128 and C128D. @(A): Conclusion While it is too early to determine the success of the CMD SuperCPU product, the company has a reputation for delivering stable products packed with features. While no accelerator can guarantee 100% compatibility with all Commodore software, the CMD offering should provide the best compatibility options thus far, due to its solutions to RAM synchronization problems that have plagued accelerator designers for years. The fact that CMD also owns the marketing rights to the GEOS family of software products and manufacturers a wide variety of successful mass media storage devices bodes well for compatibility with those applications and peripherals. @(A): For More Information TO find out more about the CMD SuperCPU family of accelerators, contact CMD at the following address of via email: Creative Micro Designs, Inc. P.O. Box 646 East Longmeadow, MA 01028-0646 (413) 525-0023 (Information) (800) 638-3263 (Ordering only) cmd.sales@the-spa.com (Internet Contact for Sales) Advance orders are being taken for all units, and the cost to place an advance order is $50.00. For programmers, CMD is planning to make available a Developer's Package, which will help those wanting to exploit the potential of the new unit to achieve success. A W65C816S assembler supporting all the new opcodes and addressing modes will be provided, as will documentation pertaining to the unit, the CPU, and its capabilities. ========================================================================= @(#)surf: Hack Surfing For those who can access that great expanse of area called the World Wide Web, here is some new places to visit that are of interest to the Commodore community. In early 1994, when the US Commodore WWW Site started, the number of sites online that catered to Commodore numbered in the 10's. Now, the number is in the 100's. What a change. If you know of a site that is not listed here, please feel free to send it to the magazine. The following links have been gleaned from those recently changed or added to the US Commodore WWW Site Links page (http://www.msen.com/~brain/cbmlinks/). To encourage these sites to strive to continually enhance their creations, and because we like to gripe :-), we'll point out an improvements that could be made at each site. @(A): Companies o http://www.armory.com/~spectre/cwi.html Computer Workshops Incorporated. CWI shows off their newest software offerings on this well-crafted WWW site. The darkbackground provides for visual effects, and the content is good as well. At the time we "hit" the page, CWI was working on a new game called Nether for the 64/128. From the information, it looks like a 3D action adventure. CWI offers both CBM and MS-DOS titles. Some are shareware, while others are commercial. C=Hacking gripe: We don't mind the MS-DOS information, but the diehard CBM user should be able to skip it. As of now, it's all on the same page. o http://www.msen.com/~brain/guest/Gaelyne_Moranec/qwkrr/ QWKRR128, by Rod Gasson. Gaelyne Moranec, a supporter of QWKRR, presents this site for new and advanced users. The site is devoted to QWKRR128, a QWK-based offline mail reading program for BBS and Internet use, and Browser, a utility for reading large files on the 64/128. The site is clean and simple, with no fancy graphics, but lots of meaty information. Links include the QWKRR128 user's manual, the actual product's binaries, and helper applications needed to use QWKRR128. C=H gripe: It's hard to tell what all I need to read Internet email via QWKRR128. o http://www.msen.com/~brain/guest/rms/ RMS Computer Systems. RMS offers up its line of services from this site, including software distribution, parts and accessories, and consulting/ training. RMS can even design your WWW pages. The pages are colorful and clean, using either Microsoft Explorer or Netscape Navigator extension depending on the browser chosen off the home page. RMS offers the C-Net BBS software for sale and present information on the 64 and 128 versions of the program. C=H gripe: The home page offers a choice of using Netscape of Microsoft Explorer. What about the Lynx text mode browser? Which do they pick? @(A): Publications o http://www.the-spa.com/cmd/cwhome.html Commodore World. CMD's publications is presented at this site, with select articles, and information for potential writers and subscribers is detailed. The site is laid out well and provides for easy reading. Of course, we're not sure it does justice to the magazine, but that's true of LOADSTAR's home page as well. C=H gripe: the site needs updating, as the change dates are 9-95. When they do update it, we hope they'll remove that annoying "blink" tag! @(A): User's Groups o http://www.ccn.cs.dal.ca/Technology/CUGNS/CBM.html Cnada Commodore Users Group of Nova Scotia. The site makes use of color and grpahics to provide links to a number of Commodore content sites on the Internet. It links up with other user groups on the 'Net, and provides a public download area for software retrieval. C=H gripe: We still think this is a user's group, but no meetings, minutes, newsletters, or times and dates were mentioned. Whare are they? o http://www.fastlane.net/homepages/msessums/64.html Metro C-64/128 User's Group. Meeting dates, times, agendas, and some general information are provided on this page. You can also learn about this groups parent organization, the Metroplex Commodore Computer Club. C=H gripe: some newsletters from past meetings and a bit more about the group would be nice. o http://www.inna.net/mpcug/mpcug.html The Middle Peninsula Computer Users Group. Go here to find out just WHY the groups is named this way. Meeting times, dates, places, past newsletter articles, and background information is provided. The site has a sprinkle of color and graphcis to break up the text. C=H gripe: It looks like the group is multi-platform, but no mention is made of what Commodore 8-bit owners will find at meetings. Maybe we missed it. @(A): Demo Groups o http://rphc1.physik.uni-regensburg.de/~pem03049/eqx/ The EQUINOXE WWW Site. This demo group puts on a good show, with content and color on their WWW site. Here is where you can find the announcement on the upcoming Shout! #2 magazine release. The list of links is implressive as well. C=H gripe: The front page use of large fonts sizes is a bit overdone. o http://flash.lakeheadu.ca/~jgvotour/index.html The OMNI/Revenge WWW Site. Color and content are mixed well on this site as well. A bit of history about Revenge is given, links to the demos to download is present, and information about upcoming releases is detailed. C=H gripe: We'd like to know more about the person behind the well-done page. @(A): Miscellaneous o http://vanbc.wimsey.com/~danf/cbm/languages.html Dan Fandrich's Commodore Languages List. Extensive doesn't really describe this page, which provides information on assemblers, compilers, cross-compilers, and interpreters for many different programming langauges supported by the Commodore 8-bit. Rare items like language support for the 264 series and the SuperPET are described as well. C=H gripe: the page is HUGE. Any chance of a breakdown into spearate files? o http://rrnet.com/~bfrandse/viccarts.html The Commodore VIC-20 Cartridge List. Cartridges from many different software companies are detailed, and both games and utilities are listed. As with the Programming Language Page, this list is extensive. It notes in the opening credits the trasnsitions the list has made to arrive at this current form. C=H gripe: same as for the langauge list. This thing is LARGE, and might benefit from a more heirachial listing treatment. o http://fox.nstn.ca/~ptiwana/john/webpage1.html John Elliot's WWW Site. This page explores the use of Commodore computers and other "orphan" machines to better education by improving the student/ computer ratio. The information presented in this site is heartwarming, as it shows practical uses to dispel the myth that 8-bits are truly useless. C=H gripe: Not really a gripe, but we sure would like to see more of these reall world examples. o http://www.ksk.sala.se/~sp93rob/dungeon/ The Alternate Reality WWW Site. For those wanting to relive the best of this game for the 64, visit this site. Everything from tips to tricks, stories to confidential material, and screenshots are available at this site. C=H gripe: The color scheme is a bit rough on the eyes, but it does look neat. o http://www.lysator.liu.se/tolkien-games/c64.html Fredrik Ekman's Tolkien Games WWW Site. The name says it all. If you've ever played a Tolkien game, here is where they are listed and examined. Fredrik give the history of each game, the solutions if there are any, and describes the game itself. C=H gripe: We left impressed with the information but wondering why someone would go to this effort. Tell us, Fredrik. o http://ubmail.ubalt.edu/~telliott/commodore.html Todd Elliott's Commodore 64/128 WWW Site. Todd provides some commentary and links to hardware hacks and ML tips. Of particular interst is his introduction to the Commodore C64 and C128 computers, which explains some of the history behind the machines. Our favorite passage in this page details his experisnces with Radio Shack.... C=H gripe: We'd like to know how Todd Elliott fits into the Commodore 8-bit arena. @(A): Change of Address o CMD recently moved to http://www.the-spa.com/cmd/ CMD heard our issue #11 gripe, as the home page now has links directly to the SuperCPU information. o LOADSTAR has moved to http://www.softdisk.com/comp/loadstar/ o Marc-Jano Knopp's CBM WWW Site is at: http://www.student.informatik.th-darmstadt.de/~supermjk/c64.html o The US Commodore WWW Links Site has moved to: http://www.msen.com/~brain/cbmlinks/ ============================================================================ @(#)trivia: Commodore Trivia by Jim Brain (brain@mail.msen.com) @(A): Introduction I had the good fortune of receiving some fine back issue of magazine and old books from a friend in Michigan (thanks Gaelyne), so I got busy reading and gleaning. The result is a new crop of trivia questions guaranteed to rack your brain and have you reachin' for those numerous Commodore publications. Go ahead, I won't mind. As some may know, these questions are part of a contest held each month on the Internet, in which the winner receives a donated prize. I encourage those who can received the newest editions of trivia to enter the contest. This article contains the questions and answers for trivia editions #23-26, with questions for the current contest, #27. If you wish, you can subscribe to the trivia mailing list and receive the newest editions of the trivia via Internet email. To add your name to the list, please mail a message: To: brain@mail.msen.com Subject: MAILSERV Body: subscribe trivia Firstname Lastname help quit @(#): Trivia Questions A publication describing BASIC on the Commodore makes the claim that BASIC variables are limited to 5 characters, with the first two being significant. The example to prove this point in the book is given as: ABCDE=5 works, while ABCDEF=6 does not. The following questions refer to this claim: Q $160) What is wrong with the above statement? A $160) Variables can indeed be longer than 5 characters. Q $161) What causes the variable ABCDEF to fail? A $161) The variable name fails becase the BASIC keyword "DEF" in it. Q $162) How long can variable names really be? Extra Credit: Who was the book publisher? A $162) As long as the maximum command line length. Theoretically, using automated code generation, you can get a variable name that is just shy of 255 characters in length. Oh, and Abacus wrote the offending book. The Commodore LCD Computer system, much like the Commodore 65, was a product that never reached the market. Do you remember this pint-size CBM machine? Q $163) How many keys were on the CLCD keyboard? A $163) 72 keys, including 8 function keys and 4 separate cursor keys. Q $164) What does LCD in the Commodore LCD stand for? A $164) Liquid Crystal Display. Q $165) Was an internal modem to be includes? A $165) Yep, A 300 bps auto dial/auto answer modem. Q $166) Like the Plus/4 the CLCD unit had integrated software. What programs were included? A $166) As referenced in $158, there are 8 integrated programs: Word Processor File Manager Spreadsheet Address Book Scheduler Calculator Memo Pad Telecommunications Package Q $167) How many batteries of what type did the CLCD use for power? A $167) 4 AA alkaline batteries. Q $168) Approximately how much did the CLCD unit weigh? A $168) 5 pounds. Q $169) What version of BASIC was to be included with the CLCD computer? A $169) 3.6. It contained all of Basic 3.5 plus a few extras. Q $16A) The CLCD unit contained a port that could be used with a Hewlett-Packard device. What did the device do? A $16A) An HP bar code reader. Q $16B) What microprocessor did the CLCD unit utilize? A $16B) The 65C102 CPU. This CPU was built using the 65C02 core from Western Design Center, who licenses the popular 65C816S CPU as well. CBM licensed this chip at little or no cost as a result of a lawsuit settlement between WDC and CBM over 6502 architecture patent infringements. Q $16C) In addition to the usual inclusion of standard Commodore ports, what two industry standard ports were included on the CLCD? A $16C) Centronics Parallel (printer) port, and an EIA-232 (RS-232C) port. Q $16D) How much RAM did the CLCD computer include? A $16D) 32kB of battery backed RAM. Q $16E) How many pixels are on the LCD screen on the CLCD machine? A $16E) 480 x 128 or 61440 pixels Q $16F) How much ROM did the CLCD computer contain? A $16F) 96kB of ROM, which held the OS and the integrated programs. Q $170) What text is displayed on the screen of a Commodore 128 upon bootup? A $170) The following text is centered on either the 40 or 80 column screen: COMMODORE BASIC V7.0 122365 BYTES FREE (C)1985 COMMODORE ELECTRONICS, LTD. (C)1977 MICROSOFT CORP. ALL RIGHTS RESERVED Q $171) How many bytes free does a Commodore 128 have on powerup? A $171) As shown above in Q $170, 122365 bytes. Q $172) On the Commodore B-128 series, the bell beeps at the right margin. What column is the default right margin on the B-128? A $172) Column 70. Q $173) When a Commodore C64 is hooked up to a 1541 and an MPS 801 printer, everything is powered up and connected correctly, and the floppy won't load. What is wrong? A $173) The printer is offline. Put the printer on-line, and the floppy will operate correctly. Q $174) How do you access the "hidden message" in the C128DCR? A $174) One brute force way: While in the machine language monitor, type: m f63f5 f640b Q $175) Some of you may remember the Commodore Magic Voice cartridge. If so, how many words was in the base unit's vocabulary? A $175) 235 Q $176) Who write the 3+1 software bundled with the Commodore Plus/4 in ROM. A $176) Tri Micro wrote the code, and created a version for the C64. It turns out that the 3+1 software included with the Commodore Plus/4 was originally designed to be but one of the many choices for bundled software with the 264. When the focus changed, 3+1 became the only software bundled, and some assumed Commodore had written it. (Ref. RUN April 1985:43) Q $177) The BASIC extension "Simon's BASIC" was created by whom? A $177) David Simons (Ref: Commodore Power/Play April/May 1985:56-7) Q $178) Simons' BASIC was influenced a lot by what other computer manufacturer's BASIC? A $178) Hewlett Packard. (Commodore Power/Play April/May 1985:56) Q $179) How many commands does Simons' BASIC add to the Commodore 64? A $179) 114. (P/P Apr/May 1985:57) Q $17A) In the United Kingdom, there was an extension to Simons' BASIC developed by David. Among other things, what major complaint about the original BASIC extension does it address? A $17A) Renumbering GOTOs and GOSUBs when renumbering a program. Q $17B) In the Commodore Plus/4 File Manager, there exists two bugs, which show up if you have over a certain number of records. What is this magic number? A $17B) When merging over 255 records in the Word Processor, a printout might stop early int the file and continually reprint a single record, or entering one record might trash another record. (RUN April 1985:43) Q $17C) Commodore Semiconductor Group (CSG) manufactured an 8500 IC. What common IC number is this IC functionally equivalent to? A $17C) The 6502. The change in number owes more to a change in manufacturing process than anything else. Q $17D) How many BASIC commands were included in BASIC 3.5, not including the monitor commands? A $17D) 80. (RUN November 1984:37) Q $17E) On the Commodore VIC-20, 64, and C16 keyboards, what row and column pins on the keyboard connector does the letter D correspond to? A $17E) Row 2 Column 2. (RUN July 1984:109) Q $17F) What is special about the keys in Row 4 of the hardware keyboard matrix? A $17F) Column 2-4 spell out CBM. (RUN July 84:109) Q $180) Most people know what CPU is in a Commodore disk drive, but what CPU powers the venerable CBM 1525 printer? A $180) You had better sit down.... The 1525 is powered by an Intel 8039 8-bit microcontroller. Actually, this isn't so hard to believe, since Commodore didn't actually develop the printer, but used a Seikosha GP-100 printer mechanism for the unit, and most likely contracted Seikosha to develop the firmware. Q $181) What is the maximum number of characters per line on a CBM 1520? A $181) 80. 22 columns per inch times 3.63... inches of usable paper width. Q $182) Commodore rarely manufactured its own printer mechanisms. Who's mechanism did Commodore use in the DPS 1101? A $182) The Juki 6100 printer mechanism. Q $183) What is unique about the DPS 1101 printer? A $183) It is daisy-wheel, but Commodore made other daisy-wheel printers. what makes it unique is that it is the only such serial daisy-wheel made for the Commodore line. Q $184) Which was the first Commodore modem with DTMF dialling capabilities? A $184) The first to offer some kind of DTMF support was the Commodore 1660 modem. The modem itself didn't provide any DTMF support, but included a cable to allow the SID to output to the phone line. Thus, with the SID's ability to reproduce DTMF tones, the modem could tone dial. Note that this was only possible on the C64, which has a SID. The first mode to INCORPORATE DTMF into the modem itself was the 1670. Q $185) Which was the last Commodore 8-bit peripheral drive developed? A $185) By develop, we are referring to actually produced models. With that definition, the 1581 holds this title. For models not actually produced, The prototype 1590-D-1 3.5" 1.44 MB model owned by Jack Vander White probably was the last under development. Q $186) What is the maximum size of RAM available for use for program storage on an expanded VIC-20 A $186) If you discount the screen area (512 bytes) and Color RAM (512 bytes), up to 28159 bytes can used for BASIC programs and variables (original 3583 bytes and 3 banks of 8192 bytes each), and up to 40448 bytes can be used for ML programs. (0-32767 minus 512 bytes for screen and 40960-49151). Q $187) One of the most poular magazines for computers in the 1980's was COMPUTE! What Commodore content magazine did it give birth to? A $187) COMPUTE!'s Gazette. Q $188) In a strange twist of irony, COMPUTE! was itself descended from a Commodore content magazine. Which one? A $188) The PET Gazette. The PET Gazette was started in April 1978 by Len Lindsey. For the first year, the magazine was sent out for free to at times 4000 people. In August of 1979, Small Systems Services, headed by Robert Lock, purchased the magazine from Len and changed the name to COMPUTE. The focus changed from PETs to all computer systems at that time. The first issue of COMPUTE. appeared in the Fall of 1979. It seems the relationship between Len Lindsay and Robert Lock was less than ideal, but I refer readers to INFO #15, page 8 for the scoop. Q $189) COMPUTE! underwent a name change very shortly after introduction. What subtle change was made to the name? A $189) COMPUTE. changed to COMPUTE! Notice the change? Q $18A) How were LOADSTAR and Commodore Microcomputing-Power/Play once connected? A $18A) In the mid 1980's, LOADSTAR distributed the type in programs for both magazines in the disk magazine. Q $18B) What is the fastest Commodore ever clocked a 6502 or derivative CPU in a machine? A $18B) The CSG65CE02 CPU, clocked at up to 3.54 MHz in the Commodore 65 (64DX) prototype. Q $18C) Name one byte that yields the same character when printed and poked to a Commodore screen. A $18C) Any byte between 32 and 63 will produce identical results. Q $18D) Quick, which chr$ value flips to uppercase/lowercase mode? A $18D) chr$(14) Q $18E) Quicker, which chr$ value flips it back to uppercase/graphics? A $18E) chr$(142) Q $18F) How do you get INPUT to not display a question mark? A $18F) open 1,0:input#0,a$ Q $190) In reference to Commodore, what does TOI stand for? A $190) The Other Intellect. Evidently, it was the computer the CBM engineers were working on before the VIC-20 project. The name sounds like it was dreamed up after the fact. In either case, this machine might have been the "Color PET" mention in _The Home Computer Wars_ that Chuck Peddle was designing before company shifted to the VIC architecture. Q $191) Name two values that, when poked to the screen, will yield the identical character appearance. A $191) 32 and 96 or 160 and 224. Space and reverse space. 103 and 106 or 101 and 116. Left and right lines. Q $192) What chr$ codes lock out and re enable the shift/commodore keyboard flip from uppercase to lowercase on the VIC-20? A $192) chr$(8) and chr$(9), respectively. Q $193) What chr$ codes lock out and re enable the shift/commodore keyboard flip from uppercase to lowercase on the C64? A $193) chr$(8) and chr$(9), respectively. Q $194) What chr$ codes lock out and re enable the shift/commodore keyboard flip from uppercase to lowercase on the C128? A $194) chr$(11) and chr$(12), respectively, while in 128 mode. Q $195) On CBM machines prior to the VIC-20, what chr$ code outputs the same character as chr$(44), the comma. A $195) 108. Q $196) Is the character described in $195 of any use? A $196) To put commas in strings read via INPUT. Remember, INPUT treats a comma (chr$(44)) as a delimiter between input fields, but chr$(108) does not produce the same effect, so you could replace 44 with 108 in data written to disk, and read it in with INPUT. Q $197) The speed of Commmodore BASIC increased dramatically after the first OS upgrade in 1979. Why? A $197) Jim Butterfield supplies us the answer: "The original PET 2001 suffered from the same kind of "screen sparkle" that was later seen in the early Commodore 64. So the original code would write to screen memory only during the "refresh" period; that really slowed down the speed of output to the screen. By the time the first revised PET came out, the screen sparkle was solved, and characters were delivered to the screen with no wait. (The new operating system also did a massive relocation of system variables, and used zero page very heavily, to the dismay of home programmers. When asked about this, Commodore pointed proudly at the "new, higher speed". But in fact it was the screen reorganization that caused 95% of the improvement)." --Jim Related to this question is $00C, which implies that the "sparkle" problem was fixed in the original PETs, so some people increased the performance of the original PET by setting the RETRACE line mentioned above to an output, which fooled the system into thinking the video was ALWAYS in RETRACE mode. Q $198) COMAL, a programming language available for Commodore computers, was created by whom? A $198) Borge Christensen and Benedict Lofstedt, although Borge is given the most credit. Q $199) At the 1980 COMDEX, Commodore PETs proved instrumental during a crisis. What happened? A $199) The following is excerpted from _The Whole PET Catalog_, page 21: "PET PROVEN USEFUL" During the 1980 MGM Grand fire in Las Vegas, Commodore moved its entire COMDEX '80 booth dowstairs to help track rooms, guests, etc. According to _InfoWorld_, 7 PETs with OZZ data-bases (predecessor to SILICON OFFICE) were used for two straight days. Local police agreed they could not have kept of the guests as well as the PETs did. Also, untrained operators quickly learned the system. In the crisis, PET was both powerful and useable. Q $19A) Who designed the PET/CBM 8032 computer? A $19A) Bill Seiler, the able assistant to Chuck Peddle, designed the unit. Q $19B) What was the "cursor gone out to lunch" bug in the first PETs? A $19B) No answer available yet (I can't find my notes!) Q $19C) On a PET/CBM (early models), what will "POKE 14,1" do? A $19C) If done immediately prior to an INPUT, the poke will suppress the question mark prompt. Q $19D) What version of BASIC would not utilize disk drives? A $19D) BASIC 1.0 Q $19E) Who is Lyman Duggan and why is he important? A $19E) He is one of the founding fathers of the Toronto PET User's Group (TPUG), along with Jim Butterfield. Q $19F) Jim Butterfield notes to me that he received plenty of help in creating the first PET memory map (Q $0D8) from the Sphinx group, who published critical information in their early newsletters. How did Commodore influence the name of the group? A $19F) The name "Sphinx" was chosen because of the way early PETs resembled the Great Sphinx, the Lion with the head of a pharoah. Q $1A0) Commodore produced an assembler for the 128 called HCD65. What does HCD stand for? Q $1A1) Who wrote most of RAM DOS? Q $1A2) What is the name of the first C64 disk copy program? (hint: it sported a "gas gauge".) Q $1A3) What was the case color of the original Commodore 64s? Q $1A4) There are at least two ways to enter 64 mode from 128 mode on a C128: go 64 and sys 65357. They produce the same result (64 mode), but they differ in at least one noticable way. How? Q $1A5) What CPU powers the B-128 computer system? Q $1A6) What type of drive mechanisms are in the D series hard drives from Commodore? Q $1A7) Commodore produced a 16kB RAM expander for the Commodore VIC-20. What is its model number? Q $1A8) Commodore produced at least one disk drive with an optical track one sensor. Which drive? Q $1A9) The Commodore PET series used the IEEE bus to communicate with peripherals. Each peripheral had a unique ID. What range of IDs are supported by the PET? Q $1AA) Many people have developed Commodore software with the PAL assembler. What does PAL stand for? Q $1AB) Many people remember Compute's Gazette. This magazine is best known for the word processor program it shared with thousands of subscribers. Name the program? Q $1AC) In some 6502 assemblers, the opcode "bge" is available. It stands for "branch if greater than or equal to". What more common opcode is this opcode referring to? Q $1AD) If I wanted to do a "blt" (branch if result less than), what 6502 opcode would i use? Q $1AE) Each Commodore peripheral has a device number, which is associated with a type of device. 8-15 implied disk drive, 4-5 implies printer. These have remained constant from the PET to the C128. However, one peripheral in the PET was phased out and its device number was reused. What device number was reused? Q $1AF) What is the maximum amount of general purpose RAM can one utilize in a stock C64? (I need an exact number here) ========================================================================= @(#)gfx: Talking to TED: The MOS 7360/8360 Text Display ICs by Levente Harsfalvi (TLC@MSZI.PMMF.HU) @(A): Introduction This information file is based on my old books, descriptions, and especially my experiences while I was coding. That's no mistake. The Plus/4 series was not very famous in the world, but they were very poular in mideast Europe. In fact, there were even demo groups for the machine. I learned some of this information while writing demos for the machine in demo groups, while other things were gleaned from personal work on the machine. These computers did indeed play an important part in Commodore computer history. I started my first code development on a Plus/4 in late 1986. After I saw a HomeLab 3 (made in Hungary, U880 - GDR made Z80 compatible proc, B/W, 16K), I started writing demos and other software for the Plus/4 machine I owned. It actually wasn't that strange to see demo groups sprout up for all kinds of machines, including the Plus/4. All over, there were groups and individuals, writing software while trying to keep the flame lit for each machine. In fact, I know people currently working in groups writing for the Plus/4 in Hungary, Germany, and as far away as Alaska. @(A): Overview Let's discuss the TExt Editor (TED) IC and its environment. This DIL-48 IC was designed specifically for the 264 series of machines, which initially included the CV364 and the 264, evolving into the Plus/4, C16, and C116 machines. Unlike the CIA or ACIA or other machines, this IC isn't well suited to any other system. The TED contains all functions done by several chips in former Commodore computers. The TED is a complete video-interface and composite video signal generator, sound generator, keyboard input latch, timer, clock generator, memory manager and DRAM refresher in a single IC. It can address the full memory map of the 264 series machines, and it generates the RAS', CAS', and MUX signals for the DRAM memory used in that series. For ROM, it generates the chip select (CS) lines, depending on the state of the internal registers. So, in addition to all the above duties, the TED IC is a simplistic MMU as well. @(A): Video Information We see the TED chip shine as it does its primary job, displaying graphics. Its abilities mostly parallel those of the uniquitous VIC-II video IC in the C64. It has the following modes: * 40x25 screen (characters) * enhanced color mode * multicolor mode * 320x200 Hi-Res Graphics * 160x200 Multicolor Graphics Of course, there are differences. TED does not contain sprite support. To offset this omission, the TED chip can select 8 intensities for each of the 16 supported colors, giving 121 colors (the 8 shades of black are all black). Other features include a hardware cursor, hardware text blinking, and hardware inverse character support. Character sets, screen and color memory, and graphics bitplanes can be addressed directly, without additional logic as found on the C64. In fact, even RAM/ROM selection requires change of a single bit. Character modes need $800 bytes of RAM for screen and color memory. The first $400 bytes act as color memory (the memory permanently located at $d800 on the C64), with the lower 4 bits containing color codes, exactly as found on the 64. Bits 4-6 denote the intensity level of the color, while the high bit select flashing/no-flashing attributes. The other $400 bytes contain the screen codes for the displayed characters. If hardware character inversion is selected, the lower 7 bits hold the screen code and the high bit selects inversion for the character. If character inversion is not selected, all 8 bits denote the screen code. Extended Color Mode (ECM) and Multi Color Mode (MCM) modes work exactly as described on the 64. While these two modes are in effect, inversion and blinking are disabled. Things get a bit more complex in graphics mode (pun unintentional). In graphcis mode, the bitplane occupies $2000 bytes and is handled just like a VIC-II biplane. The colors are handled differently. $800 bytes are needed for color memory, which is laid out in $400 bytes of intensity memory and $400 bytes of color memory. An "off" bit in the bitplane uses the lowest nybble of the appropriate color memory location as the color and retreieves the intensity from bits 4-6 of the appropriate intensity memory location. For an "on" bit, the color is taken from the high nybble of the appropriate color memory location, while the intensity is taken from bits 0-2 of the intensity memory location. Bits 3 and 7 in intensity memory are unused. In multicolor mode, differences abound. The 64's VIC-II enabled one to utilize 3 different colors in each 8x8 cell and a single background. The TED simply cannot accomplish this due to the lack of adequate color memory. So, TED allows only 2 varying colors per 8x8 cell. Those colors are chosen from the palette of 121. The remaining 2 colors are chosen for the entire screen, again from the 121 color palette. The mapping is as follows: 00 background color 01 same as "off" color in hires mode 10 same as "on" color in hires mode 11 another "background" color The TED IC is able to generate both PAL and NTSC compatible signals from a single IC. Only the crystal need be changed to go from one standard to the other. In PAL mode, there are 312 lines hown, while NTSC only has 262 lines of display. The line synchronization is the same in either PAL or NTSC mode. It's always 57 clock cycles per rasterline. The TED divides the supplied crystal frequency by 20 for PAL display and by 16 for NTSC. For the serious video programmer, raster interrupts are implemented as on the VIC-II. However, the 0 line of the register corresponds to the first line of the character screen area, not the top of the border. In addition, the current raster line can be read from TED registers. you can modify the counter as well. Doing so will most likely affect the screen display. As a bonus, the horizontal location of the raster can be read and modified in the same way. Unfortunately, these registers provide the basis for most effects, as the TED can't handle sprites. @(A): Running The Show As earlier mentioned, the TED IC does more than produce graphics. One of its tasks involves generating the clock signal for the 7501/8501 microprocessor. The clock is not constant, as it switches from from 885 kHz and twice that speed, 1.773 Mhz. The speed depends on TED's current task. It generates the slower clock signal when refreshing DRAM or fetching data for the video screen. Otherwise, the high clock signal is generated. The user can disable fast clock generation via a register. The end result is a machine that operates at approximately 1 MHz, as the CPU runs in slow mode while the screen is displayed, and operates in fast mode when the TED starts drawing the top and bottom borders. @(A): Sound Advice As far as a sound device is concerned, the TED doesn't stack up to the SID in the 64. Just 2 squarewave generators, of which the second can be switched to generate white-noise, are available for sound generation. Volume control is available in 8 levels. To play samples, the TED can switch the sound generators to constant level outputs. D/A is then done by changing the volume register setting. Each generator can generate frequencies from 100Hz to 23kHz. @(A): Other features The timers available in the TED appear to be nothing more than 16 bit decrementing timers. They are always clocked with the slow clock. The first timer reloads its starting value when it reaches 0, the other 2 are free-running. Since it already does almost everything else, it's not unusual to notice the TED handles the keyboard matrix. A simple 8-bit imput latch handles keyboard interfacing. As noted above, a single bit in the register space will page ROM or RAM into the upper 32kB of the address map. Since the TED knows what is paged in at all times, it knows what to output to access the memory locations in this area. @(A): Conclusion Well, that about wraps up the TED IC. All that is left is a map of the registers. Assume all registers are read/write unless noted otherwise. If you have questions, I cna be reached at the Internet address listed above or at: Levente Harsfalvi 7200 Dombovar Gorkij 33. Hungary By the way, catch FLI ED. V1.0; Its info file may contain some more about TED's screen-handling. It may be retrieved as ftp://ftp.funet.fi/pub/cbm/plus4/tlc/cns.lzh @(A): Register Map Register Description -------- ----------- $ff00- $ff01: Counter #01. It always starts to decrement from the last written value into it. $ff02- $ff03: Counter #02. It runs freely from $ffff. $ff04- $ff05: Counter #03. Same as above. $ff06 : Mostly the same as VIC's $d011. Bit 0,1,2 : Vertical smooth-scrolling Bit 3 : 24/25 rows screen Bit 4 : Blank screen Bit 5 : Bitplane mode Bit 6 : Enhanced color mode Bit 7 : TED's internal test, it should be 0. $ff07 : Most similar VIC-reg is $d016. Bit 0,1,2 : Horizontal smooth-scrolling Bit 3 : 40/38 columns screen Bit 4 : Multicolor mode Bit 5 : TED stop. If set, the TED stops it's counters and screen-generating, only single clock and refresh cycles remain. Bit 6 : PAL/NTSC. 0:PAL, 1:NTSC Bit 7 : Disable reverse mode. If 0, we got 128 characters and higmost bit tells if the character should appear in inverse. If set, no inverse mode but 256 characters. $ff08 : Keyboard input latch. Giving a strobe - writing to the register, the latch stores the values of the input-lines. Then, we can read them from this register. $ff09 : Interrupt request register. When a counter sends want to send an IRQ, it's bit will appear as a 0; then, if the IRQ was caused then highmost bit is set. Bit 0 : Unused Bit 1 : Raster-counter Bit 2 : Lightpen. Not implemented. Bit 3 : Counter #1 Bit 4 : Counter #2 Bit 5 : Unused Bit 6 : Counter #3 Bit 7 : Interrupt occured. This bit is set when an IRQ was enabled and therefore, the IRQ was sent to the processor. Physically, this is the negated level of the TED's IRQ output. The IRQ should be deleted with writing the register-value back after accepting an interrupt. $ff0a : Interrupt mask register. These bits could be used to disable and enable interrupt-sources. When a place is set to 1, that will be able to cause an interrupt to the processor. If not, the sign of the interrupt request will only be appear in the above register. Bit 0 : 9th bit of $ff0b (see there) Bit 1 : Raster-counter Bit 2 : Lightpen. Not implemented. Bit 3 : Counter #1 Bit 4 : Counter #2 Bit 5 : Unused Bit 6 : Counter #3 Bit 7 : Unused $ff0b : Raster interrupt register. Same as $d012 when writing; it stores the position of occuring raster interrupt. Higmost bit is in $ff0a's 0. bit. $ff0c,$ff0d : Hardware-cursor position (10 bits). Lower bits: $ff0d, higher 2 bits in $ff0c's 0. and 1. places. Beyond 1000 the cursor is not seeable. $ff0e : This reg is the first sound-source's frq-value's lowmost 8 bit. More 2 bits are in $ff10's 0. and 1. places. $ff0f : 2nd. source, lowmost 8 bits. More 2 bits in $ff12, 0. and 1. places. The soundregister-value can be calculated as reg=1024-(111860.781/frq[Hz]) (NTSC) reg=1024-(111840.45 /frq[Hz]) (PAL) $ff10 : 1st. sound-source, higmost 2 bits. 2-7 bits are unused. $ff11 : Sound control register. Bit 0-3 : Volume. Maximum value is 8. Bit 4 : Sound #1 on/off. Bit 5 : Sound #2 squarewave on/off. Bit 6 : Sound #2 noise on/off. If You set both, the square will sound. Bit 7 : D/A mode. See above for more. $ff12 : Bit 0,1 : 2nd sound-source, highmost bits. Bit 2 : Character generator in ROM or RAM. When set, TED will enable ROM when trying to get data from the charactergenerator to build screen. Else, it will give out control-signals to the DRAM's. Bit 3,4,5 : These bits tell, where to find bitplane in the memory when using bitplane-mode. TED assumes them as A15,A14 and A13 bits. So, the bitplanes can be switched as 8K pages, anywhere in the 64K. Bit 6-7 : Unused. $ff13 Bit 0 : A sign to having control about memory paging. This bit always sets to 1 when ROM is active over $8000. Else, it will be 0. READ ONLY. Bit 1 : Force single clock mode. Then, TED will disable to generate twiee clock. Bit 2-7 : Charactergenerator. Bit 7 corresponds to A15, 6 to A14 and so on. This value shows and sets the start of the charactergenerator. It can be paged as $400 bytes. Use with addition of $ff12-2.bit. $ff14 Bit 0-2 : Unused Bit 3-7 : Start of the video-ram. Bit 7 also corresponds to the A15 line as above. So, video-ram is mappable as $800 bytes - 2K. The above $ff12-2.bit doesn't affect this, but the actual RAM/ROM mapping (see at $ff3e/$ff3f and $ff13/0) does. $ff15 : Background. Lower bits contain color-code, higher 3 luminance and higmost is ignored. $ff16 : Color-reg 1 $ff17 : Color-reg 2 $ff18 : Color reg 3. This and the above are used in ECM and MCM modes. $ff19 : Border. All color registers use codes as described in $ff15. $ff1a : Bit 0-1 : Higmost bits of the next $ff1b Bit 2-7 : Unused $ff1b : Actual character-position. Higmost bits in the above register. TED counts the characters that it had fetched and put out to the screen. The number is increasing by 40 after every characterline (8 rasterline). $ff1c : Bit 0 : Higmost bit of $ff1d Bit 1-7 : Unused $ff1d : Actual position of vertical scanning. Higmost bit is in $ff1c. Read/Writeable! $ff1e : Actual position of horizontal scanning. R/W!. Lowmost bit is unused. It contains the TED's internal counter's highmost 8 bits. So, it increases 4 with every character. When writing, it seems to put the value to a functionally different register (writing back a reading value in right time affects the screen). $ff1f : Bit 0,1,2 : Actual vertical scanning-line in a character-row. R/W!. Bit 3-6 : Flashing counter. It's value increases with every frame, and TED fits it's flashing feature to this register's reaching to 15. Bit 7 : Unused $ff3e : Switching to ROM. A writing statement to this address will cause to turn on the ROM between $8000-$ffff. It's an other matter, which one; this time, only sure thing that it'll give CS signals instead of RAS', CAS' and MUX. See $ff13/0 and $ff14 $ff3f : Switching to RAM. The opposite of the above. ============================================================================ @(#)error: ? DS, DS$: rem The Error Channel We are not aware of any errors with issue 11, save the changes to some WWW addresses as noted in Hack Surfing (Reference: surf). ============================================================================ @(#)next: The Next Hack "... and that's not all you get." Well, it is for this issue, but here's what Commodore Hacking is cooking in its TV informercial cookware for issue #13: o CMD has announced that SuperCPU development units should be made available shortly, so C=Hacking will scrutinize it and detail the registers of interest as soon as it shows up. o Exploiting the 65C816S. We're holding this article over to next issue to allow testing of the examples with the CMD SuperCPU. This article will detail the new opcodes available to programmers, show how to detect CPU clock speed on any C64, accelerated or not, and discuss pitfalls in code migration. o Let's get HTMLized! It's about time the Commodore 8-bit learned to do HTML. There's nothing that says this popular WWW markup language can't do used to create nice disk magazines and newsletters on the CBM system, so C=Hacking begins a 4 part series on the language and how to render HTML pages on a Commodore machine. o And, of course, C=Hacking's regular goodies. So, go ahead, buy that box of disks, and label one now for Commodore Hacking Issue #13. ============================================================================ @(#)editor: Hacking the Code For articles in Commodore Hacking that include binary files as part of their article, these binaries files are made available in this section as encoded text files. The format used for encoding is called UUCode, which is a standard widely used on the Internet to transmit binary files using only printable ASCII characters. To that end, each of these files must be decoded with a suitable decoding program before they can executed. Typical examples inlucde UUXFER for the 64, uudecode on the ACE OS for the 64 and 128, and uudecode on most UNIX OS machines. Some encoders can decode multiple files, while others will require the user to manually split this section into individual pieces prior to decoding. WARNING: The UUCode format trasnlates files from binary to ASCII, not PETSCII. Therefore, either decode this section before downloading this section to a PETSCII mode computer system, or download this section without translation to PETSCII. Some decoder programs can handle PETSCII converted UUCode files, but the practice is not recommended because conversion is typically done in a telecommunications program and cannot be guaranteed to be accurate. @(A)polycode: Binary for Polygonamy begin 600 polygonamy M`0@0",0'GC(P-C8@5C4N,````'BB_YJ]-PB=^`#*T/>.$=#N,-"&`:G-H&F% M+80NA:Z$KZ`Y3``!`*@%D3_,:;TL"9WH!^C0]^X"`>X%`8C0[J("()T!\"S) M!I`2*0&H()H!:0:0"*H@G0&%^1#CA8NE_#CEBX7\A8RE_>D`A?V%C2"&`:;Y M\`3&^1#%()T!\`D@F@&B`H:+D!OH()T!\`GH()T!()H!:0%I`X6+Z""=`<@@ MF@%E_H6,I8UE_X6-.""&`?",I(NE_N6+A?ZP`L;_L8R1_HC0^6"^Z@&I`(6- MI/OP#`;Z*B:-QOO*$/*H8(6.L?R%^JD(A?NECJ3\T`+&_<;\P.?0W*3]P`?0 MUJDWA0'.,-"I&XT1T%BI`(T`""!@IB".IDRNIP,'"PL("@">,C`V,>-_>*E_ MS+&I-(4RC0R@(KFJ:9G=_XC`_]#USB#JE0CL'0@XC>8!HO.:R&"""B$!F+X+ M*=@8@$I*4MK(T.KN/PL.0@CN2<B`.0C./`@0V:(.XP<"U)T#<"&=!.`&")T% MU*F`G0;4BCCI!ZH0XJ`/J0`*D!>B_XX.U(X/U(T3;GSPCA34HH&.$J!XCXP8 MU*`"J?^@.-R9`=V(T/?`$+`,N3#@>0#<N4`;W;D`#9D`T,C`+]#E(%`-K3#` M>L.M,0.%R*D@H@:-8)F-_M_@#-ZFH`!,C@![69I,!,Y)FHV#"$@@+)!H(,J. M)("I"B\UR@(T`U0#=`.4I,5U*PC$'X88AB"Q"L8<A0"E$)$*B!#SQA[*E7?G M3`X"?P@(@0$(4[(M_Y5"_P1J8`1X)0`DR@J0&2(#,,84!$BMW:/F8:3.4V)@ M%*J`F!#P+,KM\`6D!(6$H`O)__#C4`+T\!0&WY`$)M_&ET;_D.$@2(V1W,C0 M^.;=T.AR[*T2T,F`T/DR#``$W`P`K0C=)N_JZL8!(8"I_XU@`*(*3!$`J7N- M$=#F`820A(0``H0"`!#%62@0,$.H`F#___S]""8!`P$`,S@Y,3%JW#`P,'X` MQ@8`+P,`BP%`"@!$````O;U*`.J9/_]]F0X"B!#ZC!G0ZH8!:S,`:$`("``P M`(!&X>FG>::<X\FZ)TX,YT(&L:@R`%,!T`H<.(8@)&P#&3J,#+!28*)"D!-J MO1!,!`(K/*@8>J1P%!=<`"$Q>`EA"Q#Q`HH0`$`,`$P`$(+Q[NY&`$``X>$H M`"4`"$%H$1$CBQX>C0"0X"`$!9LWUJ`5R``5</`L"`[^]BD`"!*3_)2%F(B3 M*P=L/1*,QP`_!@`PGQ&L`'\0$(-Y$/NBF%^E,T0>D30P'N$%,`XAI357'I$V M,![=XQ%C0*4WC01,.(PH@HT%<@BQI3F-!MRE.HQB@HT'F@)"W*U`"2T@`]VE M,(T-W&`%GC,R-S;/`#@`+C%*+D^B.+W)!94"Y9V1`LH0\^8!J9`L$=`P^\T2 MT-#VJ0@2X@Q`W7'=H#U(:*4`J0&B"(T.W(X/W*D`HG=,X`$%./'Y,`B!"`4" M;P44/A:`#KX$"B=+$`=(ZP"JL9&S(J$X`"`/B@1Q@!F!>@IVHP4&`$"CL[V2 M-87@&0`!`S"2H`[%H#BHD)FD!2$FC__P!04`"J/F>M`"YGNM!@+).K`*!18C M3F/W@Z1DZAJGY*>&KMBL3$BR`#'J`[!'_DKSD?(.\E#R,_-7\<KQ[?8^\2_S M9OZE].WUR2#P[T6-!S`XZ=!@@$_'4EA`+/-D57\"!``*@`!O`!&!)H`""0!8 MIG+V/`,D(PUO8&`(GX,0:*`!%A'$"`L(P=$)()3`!P``)Q@-P'`'A$41A0(' MA@(&A\#;@>LLIVN`3#)7KR`0#PP9!P\.`0T9`D<3M`OL(%0%$`@%#B`,+B`* M%00$`04TG3(8(#(O-B\Y-@+`(3,#%!,@-CHX(#HI`A<T"P'H(`$8O0`,RU<% M!@<("0H+#`T.#U"91A.2&Q=)<B0;T9$@J%`06"C@D2&82(SAA8+@(P$+%55E MA8JP(U^)C@0L9I2H4!"4;@@I<Y2@4'=R0GM\?7YA"8&"@X2%AH>(B8J+C(V. MCY"1DI.4E9:7F)F:FYR=GI^@H:*CI*6FIZBIJJNLK:ZOL+&RL[2UMK>XN;J[ MO+V^O\#!PL/$Q<;'R,G*R\S-SL_0T=+3U-76U]C9VMO<W=[?X.'BX^3EYN?H MZ>KK[.WN[_#Q\O/T]?;W^/GZ^_S]Y>X1!P;Y=Q!TEA44.DL5RIT-%87.DA4% M!P7((B`>'!D7%1,0#@P*"`8#`?_]^_GW]?,]XMH1Z.;DXN#>W!36CM&A;$?' MQ</!P+Z\NKBW$+D[KZZLJJBGI:.BH)Z=8NZ.E).1D(Z,BXF(AH6#@J`S=Q1W M=G1S<7!OA;UC9F5D8F%@7EU<6XB\'4M.34P+CT`ZOO`=1R"/8#P"\@B\+1"W M(2!H,+KC"?86B,<1P*,)YA&,QQ'*HP@?``80*((!"`<*B$@+`$@(`4!P`D@% M`T"B6T@2'DTHCR/L6C`>2S"/%A8CC<<?'Y/8(R)ACR5D/8(J*[0>04B/(WQ' M%]XC3$U.2X];7%U>8&%B9&5F);)[#(&B<W1V=T+W*(*#A8:(B8N,CI"1DY0Z MQT>=GJ"BHZ6GJ*JLKJ^0>3ZWN+J\OL#!P\7'0IZ/T:#(Q]S>X.+DYNA0F#Z" M\_7W^?O]_P$#!@@*#`X0$Q47&1P>("!>$`$"\)`"`O$``@^;`/[\^OCV]/+P M[NSJZ>?EX^'?W=O:V-;4TM#/S<O)R,;$PL&_O;NZN+:UL[&PKJRKJ:>FI*.A MGYZ<FYF8EI63DI"/C8R*B8>&A(.!@']]?'IY>'9U=')Q<&YM;&II:&=E9&-B M8%]>75M:65A75E134E%03TY-2TI)2$=&141#0D%`/SX]/#LZ.3@W-K[PP30S M,C$P+\&Q+2PK*EDH.O0E)!15(HX_!0$5$%1P4(%"!7'A4,%9C$5$!6&B@O`4 M%A6$(*`G)FH))<`'<"$$BF@`#@L0@4P,`$P(`4P&`N.``PD$3`0%!@8&&%ZG MH)R";PH*BJ@I#`P-#0X.#P\0$!$1$A(3$Q04%146%Q<8&!D:&AL<'!T>'A\@ M("$B(R,D)28F)R@I*2HK+"TN+B\P,3(S-#4U-C<X.3H[/#T^/T!!0D-$149' M2$E*2TU.3U!14E-45E=865I;75Y?8&)C9&3_F&EJZ&-P<7)T=79X>7I\?7^` M@8.$AH>)BHR-CY"2DY66F)F;G)Z?H:.DIJ>IJZRNL+&SM;:XNKN]O\'"Q,;( MR<O-S]#2U-;8VMO=W^'CY>?IZNSN\/+T]OCZ_/ZM@%,F^<V@=$@<\<6:;T09 M[L2:<$8<\LF@=TXE_=6LA%TU#N:_F7)+)?_9LXUH0AWXU*^+9D(?^]>TD6Y+ M*`;DPJ!^7#L:^=BWEW96-A;WU[B9>EL]'@#BQ*:);$\R%?C<OZ.';%`U&O_D MR:^4>F!&+1/ZX<BPEW]F3C<?!_#9PJN5?FA2/"81_.;1O:B4?VM70S`<"?;C MT;ZLFHAV9%-!,!\/_N[>SKZ2KIZ/@'%B5$4W*1L-`/+EV,N_LJ::CH)V:V!5 M2C\T*B`6#`+Y\.;=U<S$N[.KI)R5CH>`>7-M9F!;55!*14$\-S,O*R<C(!T: M%Q01#PT+"0<&!`/_ID?_5298F>`]`0(#!`8'"0L-#Q%2QAH=(",G*R\S-SQ! M14I055M@9FUS>8"'CI6<I*NSN\3,U=WF\/D"#!8@*C0_2E5@:W:"CIJFLK_+ MV.7R``T;*3=%5&)Q@(^>KK[.WN[^#Q\P05-D=HB:K+[1X_8)'#!#5VM_E*B] MT>;\$28\4FA^E:O"V?`''S=.9G^7L,CA^A,M1F!ZE*_)Y/\:-5!LAZ._W/@5 M,D]LB:;$X@`>/5MZF;C7]Q8V5G:7M]CY&CM<?J#"Y`8H2VZ1M-?['T)FBZ_4 M^!U":(VSV?\E2W*9O^8.-5V$K-7])4YWH,GR'$9PFL3N&41OFL7Q'$ATH,WY M)E.`GWZB!!;Z`^Z$,`>XA1D0P@"NJ`*<@)`$$`4/$&X`F5@!2H`/(`.8`!J` M`S5$%S8`%Q8!%Q("%PX#%PT$8#H%%PL&%PH'8)@(8`@)%PD*D@M@"`P7"`TR M#F`(#X80%P<1(`,2)A-@`A07!A72*P<2D?H)^YB`_`G]F(#^"?^8@``)`9B` M`@D#F(`$!Q0%!Q(&`@*#Y)TA-$%*4%9:76!C96=H:FML;6YO;W!Q<7)R<W-T M='1U=74;#W8"!'<"!G@""'D""WH"#WL"&'P"$WT(<9L(`%@-`U(&`!0#`!0` MB!```01P`D``_Q@\\"A()R8F)B4E)20D)"%9(R(B(B$A(2`@("%9'QX>'AT= M'1P<'"%9&QH:&AD9&1@8&"%9%Q86%A45%104%"&Y$Q(2$A$1$1`0$`\/#^%9 M#@T-#0P,#`L+"R%9"@D)"0@("`<'!R%9!@4%!00$!`,#`R%9`F'^(P```/__ M_V"%_OW]_?S\_/O[^V2%^OGY^?CX^/?W]V2%]O7U]?3T]//S\^2&\O'Q\?#P M\._O[^[N[F>%[>SL[.OKZ^KJZF2%Z>CHZ.?GY^;FYF2%Y>3DY./CX^+BXF2% MX>#@X-_?W][>WB@$W=S<W-O;V]K:VMG9V;C%T=[J]P00'2DV0D\@#W6!CIJG ML\`=#N;R_PL8)#$^2E=C<'R)C0ZON\C4X>WZ!Q,@+#E%4HT.>(21G:JVP]#< MZ?4"#AN-#D%-6F9S?XP=#K*^R]?D\/T*%B,O/$A586Y[AY2@K;G&T]_L^`41 M'BHW1%!=:7:"CYRHM<'.VN?S``T9)C(_2UAD<7Z*EZ.PO,G6XN_["!0A+3I' M4V!L>862GZNXQ-'=ZO8#$!PI-4).6VAT@8V:IK._S-GE\OX+%R0P/4I68V]\ MB)6BKKO'U.#M^083'RPX15%>:W>$D)VIML+/W.CU`0X:)S1`35EF<G^+F*6Q MOLK7X_#\"18B+XUZYJCM`@0`R)!@!0`H!$!,@,`$P`(('`3).]`.Z"@(\!#H MQ#+P"\``\`>F'$4Q1R2%!2C0!Z1/Q#+0`>CD'(8<\#S@";`XO(`?Q3+PP.*# M$2`P`2$3(C`!(Q,E,`$F$R<P`2@3*C`!*Q,L,`$M$R\P`3`3,3`!,A,T,`$U M$S8P`3<3.3`!.A,[,`$\`0@^N0`)D13(QB_0]HT$_ZD`8,E@D`(I7V"@!(0& MHC4^V4<@??^.('51++I$:2`-`*(%H"<@A$0@8@!:'<X;!Z\(")B`$`D8F(`@ M"2B8@#`).)B`0`E(F(!0"5B8@&`):)B`<`EXF("`"8B8@)`)F)B`H`FHF("P M";B8@,`)R)B`T`G8F(#@">B8@/`)^"`HL0@(F(`0"1B8@"`)*)B`,$$X(2CU M*$)(P`103%C`!&!,:,`$<$QXP`2`3(C`!)!,F,`$H$RHP`2P3+C`!,!,R,`$ MT$S8P`3@3.C`!/!,^"%`B44(P`003!C`!"!,*,`$,$PXP`1`3$C`!%!,6,`$ M8$QHP`1P#'@B0JE'$0*()I!@`I@FH&`"J":P8`*X)L!@`L@FT&`"V";@8`+H M)O!@`O@B2BP"""808`(8)B!@`B@F,&`"."9`8`)()E!@`E@F8&`":"9P8`)X M)H!@`H@FD&`"F":@8`*H)K!@$+@C2CV*$,@P`=`3V#`!X!/H,`'P$_@C4&(1 M"#`!$!,8,`$@$R@P`3`3.#`!0!-(,`%0$U@P`6`3:#`!<!-X,`&`$X@P`9`3 MF#`!H!.H,`&P$[@P`<`3R#`!T!/8,`'@$^@P`?`D)20VZE&$@`@)$)B`&`D@ MF(`H"3"8@#@)0)B`2`E0F(!8"6"8@&@)<)B`>`F`F("("9"8@)@)H)B`J`FP MF("X"<"8@,@)T)B`V`G@F(#H"?"8@/@E$HN`"`D0F(`8"2"8@"@),!B$."92 MCR($2$Q0P`183&#`!&A,<,`$>$R`P`2(3)#`!)A,H,`$J$RPP`2X3,#`!,A, MT,`$V$S@P`3H3/#`!/@FE%@$"$P0P`083"#`!"A,,,`$.$Q`P`1(3%#`!%A, M8,`$:$QPP"!X)Y1Z%"&(8`*0)IA@`J`FJ&`"L":X8`+`)LA@`M`FV&`"X";H M8`+P)O@GH,0B"&`"$"888`(@)BA@`C`F.&`"0"9(8`)0)EA@`F`F:&`"<"9X M8`*`)HA@`I`FF&`"H":H8`*P!K@HH=2C"`'($]`P`=@3X#`!Z!/P,`'X*"46 M`0@3$#`!&!,@,`$H$S`P`3@30#`!2!-0,`%8$V`P`6@3<#`!>!.`,`&($Y`P M`9@3H#`!J!.P,`&X$\`P`<@3T#`!V!/@,`'H$_`I4&(IHQY%"`B8@!`)&)B` M(`DHF(`P"3B8@$`)2)B`4`E8F(!@"6B8@'`)>)B`@`F(F("0"9B8@*`)J)B` ML`FXF(#`"<B8@-`)V)B`X`GHF(#P"?@J*+$(")B`$`D8F(`@"2B8@#!!."LH M]2A"2,`$4$Q8P`1@3&C`!'!,>,`$@$R(P`203)C`!*!,J,`$L$RXP`3`3,C` M!-!,V,`$X$SHP`3P3/@K0(E%",`$$$P8P`0@3"C`!#!,.,`$0$Q(P`103%C` M!&!,:,`$<`QX+$*I1Q$"B":08`*8)J!@`J@FL&`"N";`8`+()M!@`M@FX&`" MZ";P8`+X+$HL`@@F$&`"&"8@8`(H)C!@`C@F0&`"2"908`)8)F!@`F@F<&`" M>":`8`*()I!@`I@FH&`"J":P8!"X+4H]BA#(,`'0$]@P`>`3Z#`!\!/X+5!B M$0@P`1`3&#`!(!,H,`$P$S@P`4`32#`!4!-8,`%@$V@P`7`3>#`!@!.(,`&0 M$Y@P`:`3J#`!L!.X,`'`$\@P`=`3V#`!X!/H,`'P+B4N-NI1A(`("1"8@!@) M()B`*`DPF(`X"4"8@$@)4)B`6`E@F(!H"7"8@'@)@)B`B`F0F("8":"8@*@) ML)B`N`G`F(#("="8@-@)X)B`Z`GPF(#X+Q*+@`@)$)B`&`D@F(`H"3`8A#@P M4H\B!$A,4,`$6$Q@P`1H3'#`!'A,@,`$B$R0P`283*#`!*A,L,`$N$S`P`3( M3-#`!-A,X,`$Z$SPP`3X,)18!`A,$,`$&$P@P`0H3##`!#A,0,`$2$Q0P`18 M3&#`!&A,<,`@>#&4>A0AB&`"D":88`*@)JA@`K`FN&`"P";(8`+0)MA@`N`F MZ&`"\";X,:#$(@A@`A`F&&`"("8H8`(P)CA@`D`F2&`"4"988`)@)FA@`G`F M>&`"@":(8`*0)IA@`J`FJ&`"L`:X,J'4HP@!R!/0,`'8$^`P`>@3\#`!^#(E M%@$($Q`P`1@3(#`!*!,P,`$X$T`P`4@34#`!6!-@,`%H$W`P`7@3@#`!B!.0 M,`&8$Z`P`:@3L#`!N!/`,`'($]`P`=@3X#`!Z!/P,U!B,Z,>10@(F(`0"1B8 M@"`)*)B`,`DXF(!`"4B8@%`)6)B`8`EHF(!P"7B8@(`)B)B`D`F8F("@":B8 M@+`)N)B`P`G(F(#0"=B8@.`)Z)B`\`GX-"BQ"`B8@!`)&)B`(`DHF(`P03@U M*/4H0DC`!%!,6,`$8$QHP`1P3'C`!(!,B,`$D$R8P`2@3*C`!+!,N,`$P$S( MP`303-C`!.!,Z,`$\$SX-4")10C`!!!,&,`$($PHP`0P3#C`!$!,2,`$4$Q8 MP`1@3&C`!'`,>#9"J4<1`H@FD&`"F":@8`*H)K!@`K@FP&`"R";08`+8)N!@ M`N@F\&`"^#9*+`(()A!@`A@F(&`"*"8P8`(X)D!@`D@F4&`"6"9@8`)H)G!@ M`G@F@&`"B":08`*8)J!@`J@FL&`0N#=*/8H0R#`!T!/8,`'@$^@P`?`3^#=0 M8A$(,`$0$Q@P`2`3*#`!,!,X,`%`$T@P`5`36#`!8!-H,`%P$W@P`8`3B#`! MD!.8,`&@$Z@P`;`3N#`!P!/(,`'0$]@P`>`3Z#`!\#@E.#;J482`"`D0F(`8 M"2"8@"@),)B`.`E`F(!("5"8@%@)8)B`:`EPF(!X"8"8@(@)D)B`F`F@F("H M";"8@+@)P)B`R`G0F(#8">"8@.@)\)B`^#D2BX`("1"8@!@)()B`*`DP&(0X M.KH30$I(P`103%C`!&!,:,`$<$QXP`2`3(C`!)!,F,`$H$RHP`2P3+C`!,!, MR,`$T$S8P`3@3.C`!/!,^#I`B44(P`003!C`!"!,*,`$,$PXP`1`3$C`!%!, M6,`$8$QHP`1P#'@[0MT)@"6(8`*0)IA@`J`FJ&`"L":X8`+`)LA@`M`FV&`" MX";H8`+P)O@[H,0B"&`"$"888`(@)BA@`C`F.&`"0"9(8`)0)EA@`F`F:&`" M<"9X8`*`)HA@`I`FF&`"H":H8`*P!K@\H>Z$P!+(,`'0$]@P`>`3Z#`!\!/X M/%!B$0@P`1`3&#`!(!,H,`$P$S@P`4`32#`!4!-8,`%@$V@P`7`3>#`!@!.( M,`&0$Y@P`:`3J#`!L!.X,`'`$\@P`=`3V#`!X!/H,`'P/24]-GA`\(J`"`D0 MF(`8"2"8@"@),)B`.`E`F(!("5"8@%@)8)B`:`EPF(!X"8"8@(@)D)B`F`F@ MF("H";"8@+@)P)B`R`G0F(#8">"8@.@)\)B`^#Z9``P(F(`0"1B8@"`)*)B` M,#^9.#\!B.&S(/\>+R#`R@"`8@"`"`!20,!`"<#E"&"K`F$F8F`"8R9E8`)F M)F=@`F@F:F`":R9L8`)M)F]@`G`F<6`"<B9T8`)U)G9@`G<F>6`">B9[8`)\ M)GY@`G\F@&`"@2:#8`*$)H4!"(8@`1`-`$"&`2T`(`$`"`!``0"]`:D/X+&- M(=#('B,5A?Q3C_U,38&3#AP1`0Z05T],64=S'DU9#04!$F`<#1\($F&9IT`E M-"(4R(W$`$1)3;J)4TE:#B:!A"H*8W-OQE!&CX)LLFH\!T!!!5U32E5$1$!. M5U4N1415SR.0`08@<T5%PX19`YYC/6A!0TLRK$Z0($99($16K4%)3%/F!Y4! M!R!UFAD).I%`$1&=+Y$[QS01`H!624=!)6*0#9P!!2`^/CX@<"3;Q5\@T$M% MD%@H3P$%14<YDB`\/#P-#9IAJ2XN+G-/4E+AE4%"3U5<`N(G0E5'4R$-=&$- M&@(!!=Y-DZQ3(%"<`T].04Q)5%D@14Y(04Y#15)3`+'\\"X@TO\F#O8W<#$% M!4]W%4$@4T5#4D4(#U1%6%0@34534T%'1303(%E/5R$@Y/_)`/#YI0$I_H4! MJ0AT$T<8C1C0K<<.Q`$"@A`%*?P)`[DPK<D)((T1T,#:_(7^80\>:&!,!@"- M05DP4*D$A?VI7('7@ZD6LB2,YOWFEBORB8'`2-#WJ1V1_)'^R-#YHL"&6NB& M6*(*AFBB#(9JH@Z&;*(0AFZB$H9PD,@=*W*AEB`P`F$2"%*[DNA)M(T$%`(! MR$R-`L`-@XTAW(*-(L`-1(U!W+R-0A9`=HT@%HTERP5G\3DV1'@@G_^ER\E` M\"_)+LT*0MY)("#)-]`+H@/*_@`6RA#Z,!')+6(W1Z.%3)N"R3+"UP:&$0'F M..8YI3H$%P.%.J6QK`+)P#"6$%^QI?@8:0C!Z\"%^*4YE"*L#%UL`#L%`4$H MO!0$A3PI"(T_^0!"/<$,`#J%/FTB"CN%0*4\=@!"I?]HA3@#0#C)-`5$ICND M//6112EY3$9AG<L*(,E'ID)@QD)(4,*?$-Z`22%X"`%L@E@D]!A(A0GH`L(0 M%.!`Y@<+?D200$FF0Z1$:HD1$$J0'B/(3:9`OQ,\`%=`6&$"",L2`0Q%"SZD M/=)DRCCYL(202Z8_I$)!#:#0ID"D0;VS`8#*&!`!.&HXY?^F/:0^Q'-HRR07 M`,NU*4RB`-EA!`_)AI`KV>@`)AAY0!:0(,(*A?^$^8I(\`ZT!KD`%L7_D`58 M%T3RI/F4!VBJZ(@0R\HP)(:MM0?)`%?W`6B)9``!T`8@3(M,=83)`M`#(-"/ MIJW*$-REO]`_-/$;&*3L`!B%QD`I+EH!X<>B&,%PC%FB(X036Z+(O7`P'-[_ M6/`7AJ!XBDI*2AAIIX5<BBD'J.(9(7*FIO_*T-R"I22_J<:B>(X8T(T`W:D9 MA;Q,8X(B5^Z)<(B.(`DL*$5612*>`!<`4S`$1$0IQAT)@0?$0`4P`:$(24Q( M&_$05$L@2;<0)%*#1S$F(4$R%1%2,2U,DT]25$%,LA=#$R!.3U0@2E535$E& M6=+L2$4@5T%94R!/1B!G3T0@5$\@34%.(B`M+2"0X@!%+D-534U)3D=3YLM6 M4C`4PA<0"(U0&Q``E!=LA/`%!!KYHY``-$:(XL:LH`.(Z@5``@20,`!,_[F* M./VB3`+&_[<<B$`"!)@0%L(`-@@')@J`"87YN4@8,0D8\_D8OHTU?0`7D`+F M!`]0S/F90!9`AID`%H@0HV`.KP#(Q<8+,$#8B"ZTK+X`R25&",06>*+_BD@6 MT3CE0C6W"*;_DD[</%NX8M9(4B-B29%!2K'(H$&E2]AJ1$PL,BA-EAD3PZ5% MI#M>&F#!`D:D/#/P0H5'I#V%:[%K2$0L0JAHI)9KP4F`@A04$*@^R0JP7/^J MO0`5JJ0>5@HJ%@,/H$*D0'90,$BIH+:"_Y`#YD,5"X9":&4S0TKP!LVP6(B& MJ&K)H)`(W#Y"J8D:0Z1!#B0D:29#:2D@9^,!9Q0/::"`1*0_BH5.2F^821QI M`44IL6](L6VD_SCQ;87_:/%OI?]<=T$0"UP!#:D`\`D8::C)R)`"J<>%09$: M/((893G6'4?NZ8XC6(`8M*,)(D@P0S%H1Q.T@H'&H!U-$$$"2%"0&)JF0"DY M>Y'D1,"2$P`)3@0@!2>"0()G7?B3X#&2#)\S8WCG(VQ'BR$S:@QW<P2P6#%X MQ(RA=HY@$T-XE1'#5M08!*A@I:Q(..4Z*`P7P7`$3>7!Q9`63;P9,8)-?*&- MKB""Q90)$T-:-$1%'C^1.T?&N>!&5<BM+[#)B.&V1@PU2G"-&B7DU8AA+6H, MW78$T`K"G'T068QB:(6L:%4``XWA7YI@%7A$D$`Q_$L33(!@%1`LAG]I@@D0 MK$)3BV`!8OB7)H@@J&7"Q)`R31"(U2E8"HT!)#,2(909"4'*C`2OAREBIR<B M$$$H$8@FH!19C$$T:@RG5(0<(;S$B$&5QE!"PX27&#&HTB]8"(DF<C@IAE49 MI?@3DZ88?&;$L%<U!H<Y@@X0$&K$<$,UACHK0HX0@&C$$$PUAL,IIBG28Z48 M@++&$$%%8!D5@@.,X;ZJCS+F8KBOO*H\N!CVJPE00+;)<3'L5Z)3OFP,>K8$ MF@I02N;!Q=!<540Y?4%L:\AQ<G2"V-:0(=B"P(-B33E.04Y/D!(AX,!06$Y1 MD!-2Q-R6`!(4)%.6$U3D!%4!ISL$R3RIC#(0.AJQT%`;0D,<B4"]J3B:E)@D M`@4E%"@CH$`!(V5>7@PGT0F<1"=P$IU`F@S!D@DC<2`4[4@Q),F0-L4+-RA> M0#79,C.*%S10O(`RX@4R%*=H,>A$L"8NB9H$+$5-@K`80P"CJ4`E`414400B M52@"$5.4TXHQG,0.<!([P$GL`"<A#V+0`0+MC!A.8@<XB1W@)':`DY`',>@` M(44'(B@Z0"#1`2!*2/P8_HU3`HMB>(\DX#V2@/=(`DIC"'I8N+="OP0A*G:` MJ-@!HF('B`H=(+S'#O`>.\![[`!T,P0:2*;0,`%B1@RN-&.I**)A0E3L`%&Q M`T3%#A`5.D`VT0$WB@XU4'2`-0)#()4<IDTA)0&WD03<1A)P&TG`;2`!&P4) M'"A(0!I!`AI*_50PQ9-.*/<13Y3["$T*?@0I`-,^)88C*3&8QXB!.222Y0A$ MRG($!`4YC@2E5(TE.E6-17`/4XT%1U,Q$D`%I5&-)AU2C4;&I5"-!L;D4%C^ MC`:@V$8'HC5#&)F-_S`#3'6B*D@13(``B6(0D"H(A#B+04"J8`($2!2#@%1N M)<?%("!5T`.#RGH,&4R`@0(?.882DJ&,Q(LRY00S.31!RH6&<GJ.3)LU6,XV MD7,W)#6^*N(%*Q0O*:!X`2FE2R<H7D`H\0(FBA<F4+B().(%)10O(Z!X`2$T MAI"EI;$DT"@MBE4$+L4J@BPR%4<VL8HWH%A%-5"L(C4H53$S%*L(-(I5!#+% M*H(R4A5#P(LCY"Z"0W(700.YBR`$10,2%`1)8APA1`EF*""6$R'D!"(I$5]* MHXLCY00D.25!2H19DN-B)CDG04XHD"6`I4R8*5A.*I`3*Z1$IR@G?LB$B2SE M!"TY+JEBA3NIH84\J7R%/:T"07H^K2+@!C^M0A:%0"!IAJ5!A2^E0H4PI4.% M,:4A1AP)(BA(0"`I,B<*$BA0D(`F@@0FE",DH2`!)04)(RA(0"/YD4(@<5*E M*HV$A:4KC5ZE*8WI!46JI3"-(?X.,8U!G"^-`<--+[`"7*4MC2)W#BZ-0L:E M+(T"QN0L+.NJH`*$^ZD#A:.%_R!VF6"D^UU;!310A?ZH2DI*&*:_T`YI0/0\ M&C`*0!MAT`QII\B!6H;!O@!;AL*%7(5FA6"I:;);F"D'A?I@".V:LL"Y+9R; M0&+2D!9#T!?LG6#:)74!WP@/\F<8D2^\FQ,.HV%6@C]`*Q*"#I@H=A`(Y:FJ MF.D`D/KPND.@8-`4C)>*\)2->D":HOJO+O2&1BRU6B"GJBKEJ)`6J(HGN)"0 M`<@XY;<"YH@P!B"LG$SQI&`8IJ=[YHHE9$6FM98&(X5EJ&JV$03&J&`*M(UF M65*J"-W1;I4YH2+T6<)A*NX.1Y*%G\"0.^R<DXB,#UE2J@COD6QPCK2D-,<^ MHI+*:-$@,$/H#8$9P@(1>+817F!>@F4R+T'8!;;*MD09IB+K<"19^`D,N4.? M,]'(C[G%#_V9DKF@!/T,GQ#^`SONYY]-#Y)H@)%HPWD,$L4\BK!`%!0'D`_H M.H8`%MF0`QCFJ)$^QXP!/VX-4S*$G\B0.YJAQJ70>Z3\$_<%I*.(X,E9Z84) MI83\_?*0<!9Y2+VAXA.G2A^H4"#"#Z2ADZ9*'*96]HBDT@>DQ:0T/ZK$#ZN& MJ<:ST'VD_9BJR,2CT`*@ZX/_$`H)_I@)!@#&\.>%LH6SA/V0)0"2<+1`'/D0 MAK`#3)"=2KT@XH$X0,:%MD^(:JJDLLAUPCCY`,.P!J(`.'Z0%*HXX,2JA5=) M_VD`A5FEM'%9./%7ZX*0!^CELL6RL/F%N)A*Y]V&MZ6K?`N&<*2=!B"XQH$2 M6JNEI^6IA:<1Y@2HBJCKI!K%7_`0A5^!<8U`J#^\7LBQN]`F;R8300&X`!"$ M3[)?,(="`/$@4JA5(-BE94(]7[`;:0/0%*2GN<D<I+4Y)Q(+$4&P(*1!^K%Q M(%6FIJ<@<<S"(%V17::UO0#-,7$18Y'@S+DXY;BP$V6R5-P`&!0#D`Z%N:6U MY;>%M:JP)G.V&$Z1\`*4?0#%Q#4#Q67P'"V%PJP(@29,`HHI^!AEP24X"+9E MPA.I`:3^D;N8\`G&_@+&^C`&JO9,2*;!<(C&8,9FQERI8,0RH`>$^J5=P0E` M7:5>4UZE8\`2@&.E9*9DI<$XZ4"%P:7"Z0&%PDSQHZ1EJ9F16V!L6P"*!V4` M;%\``JB]%+='$`@P`1`3&#`!(!,H,`$P$S@P`4`32#`!4!-8,`%@$V@P`7`3 M>#`!@!,00R$6`9@3H#`!J!.P,`&X$\`P`<@3T#`!V!/@,`'H$_`P`?A@)18! M"!,0,`$8$R`P`2@3,#`(.&&E'D4(2)B`4`E8F(!@"6B8@'`)>)B`@`F(F("0 M"9B8@*`)J)B`L`FXF(#`"<B8@-`)V)B`X`GHF(#P"?AA*+$(")B`$`D8F(`@ M"2B8@#`).)B`0`E(F(!0"5B8@&`):)B`<$%X8BCU*$*(P`203)C`!*!,J,`$ ML$RXP`3`3,C`!-!,V,`$X$SHP`3P3/AB0(E%",`$$$P8P`0@3"C`!#!,.,`$ M0$Q(P`103%C`!&!,:,`$<$QXP`2`3(C`!)!,F,`$H$RHP`2P#+AC0JE'$0+( M)M!@`M@FX&`"Z";P8`+X8THL`@@F$&`"&"8@8`(H)C!@`C@F0&`"2"908`)8 M)F!@`F@F<&`">":`8`*()I!@`I@FH&`"J":P8`*X)L!@`L@FT&`"V";@8`+H M)O!DH,1D1CV*$`@P`1`3&#`!(!,H,`$P$S@P`4`32#`!4!-8,`%@$V@P`7`3 M>#`!@!.(,`&0$Y@P`:`3J#`!L!.X,`'`$\@P`=`3V#`!X!/H,`'P$_AE4&(1 M"#`!$!,8,`$@$R@P`3"#.&90ZE&$@$@)4)B`6`E@F(!H"7"8@'@)@)B`B`F0 MF("8":"8@*@)L)B`N`G`F(#("="8@-@)X)B`Z`GPF(#X9A*+@`@)$)B`&`D@ MF(`H"3"8@#@)0)B`2`E0F(!8"6"8@&@)<!B$>&=2CR($B$R0P`283*#`!*A, ML,`$N$S`P`3(3-#`!-A,X,`$Z$SPP`3X9Y18!`A,$,`$&$P@P`0H3##`!#A, M0,`$2$Q0P`183&#`!&A,<,`$>$R`P`2(3)#`!)A,H,`$J$RPP""X:)1Z%"'( M8`+0)MA@`N`FZ&`"\";X:*#$(@A@`A`F&&`"("8H8`(P)CA@`D`F2&`"4"98 M8`)@)FA@`G`F>&`"@":(8`*0)IA@`J`FJ&`"L":X8`+`)LA@`M`FV&`"X";H M8`+P:4II;-2C"`$($Q`P`1@3(#`!*!,P,`$X$T`P`4@34#`!6!-@,`%H$W`P M`7@3@#`!B!.0,`&8$Z`P`:@3L#`!N!/`,`'($]`P`=@3X#`!Z!/P,`'X:B46 M`0@3$#`!&!,@,`$H$S`P"#AKI1Y%"$B8@%`)6)B`8`EHF(!P"7B8@(`)B)B` MD`F8F("@":B8@+`)N)B`P`G(F(#0"=B8@.`)Z)B`\`GX:RBQ"`B8@!`)&)B` M(`DHF(`P"3B8@$`)2)B`4`E8F(!@"6B8@'!!>&PH]2A"B,`$D$R8P`2@3*C` M!+!,N,`$P$S(P`303-C`!.!,Z,`$\$SX;$")10C`!!!,&,`$($PHP`0P3#C` M!$!,2,`$4$Q8P`1@3&C`!'!,>,`$@$R(P`203)C`!*!,J,`$L`RX;4*I1Q$" MR";08`+8)N!@`N@F\&`"^&U*+`(()A!@`A@F(&`"*"8P8`(X)D!@`D@F4&`" M6"9@8`)H)G!@`G@F@&`"B":08`*8)J!@`J@FL&`"N";`8`+()M!@`M@FX&`" MZ";P;J#$;D8]BA`(,`$0$Q@P`2`3*#`!,!,X,`%`$T@P`5`36#`!8!-H,`%P M$W@P`8`3B#`!D!.8,`&@$Z@P`;`3N#`!P!/(,`'0$]@P`>`3Z#`!\!/X;U!B M$0@P`1`3&#`!(!,H,`$P@SAP4.I1A(!("5"8@%@)8)B`:`EPF(!X"8"8@(@) MD)B`F`F@F("H";"8@+@)P)B`R`G0F(#8">"8@.@)\)B`^'`2BX`("1"8@!@) M()B`*`DPF(`X"4"8@$@)4)B`6`E@F(!H"7`8A'AQ4H\B!(A,D,`$F$R@P`2H M3+#`!+A,P,`$R$S0P`383.#`!.A,\,`$^'&46`0(3!#`!!A,(,`$*$PPP`0X M3$#`!$A,4,`$6$Q@P`1H3'#`!'A,@,`$B$R0P`283*#`!*A,L,`@N'*4>A0A MR&`"T";88`+@)NA@`O`F^'*@Q"((8`(0)AA@`B`F*&`","8X8`)`)DA@`E`F M6&`"8"9H8`)P)GA@`H`FB&`"D":88`*@)JA@`K`FN&`"P";(8`+0)MA@`N`F MZ&`"\'-*<VS4HP@!"!,0,`$8$R`P`2@3,#`!.!-`,`%($U`P`5@38#`!:!-P M,`%X$X`P`8@3D#`!F!.@,`&H$[`P`;@3P#`!R!/0,`'8$^`P`>@3\#`!^'0E M%@$($Q`P`1@3(#`!*!,P,`@X=:4>10A(F(!0"5B8@&`):)B`<`EXF("`"8B8 M@)`)F)B`H`FHF("P";B8@,`)R)B`T`G8F(#@">B8@/`)^'4HL0@(F(`0"1B8 M@"`)*)B`,`DXF(!`"4B8@%`)6)B`8`EHF(!P07AV*/4H0HC`!)!,F,`$H$RH MP`2P3+C`!,!,R,`$T$S8P`3@3.C`!/!,^'9`B44(P`003!C`!"!,*,`$,$PX MP`1`3$C`!%!,6,`$8$QHP`1P3'C`!(!,B,`$D$R8P`2@3*C`!+`,N'="J4<1 M`L@FT&`"V";@8`+H)O!@`OAW2BP"""808`(8)B!@`B@F,&`"."9`8`)()E!@ M`E@F8&`":"9P8`)X)H!@`H@FD&`"F":@8`*H)K!@`K@FP&`"R";08`+8)N!@ M`N@F\'B@Q'A&/8H0"#`!$!,8,`$@$R@P`3`3.#`!0!-(,`%0$U@P`6`3:#`! M<!-X,`&`$X@P`9`3F#`!H!.H,`&P$[@P`<`3R#`!T!/8,`'@$^@P`?`3^'E0 M8A$(,`$0$Q@P`2`3*#`!,(,X>E!W0D`)2)B`4`E8F(!@"6B8@'`)>)B`@`F( MF("0"9B8@*`)J)B`L`FXF(#`"<B8@-`)V)B`X`GHF(#P"?AZ*+$(")B`$`D8 MF(`@"2B8@#`).)B`0`E(F(!0"5B8@&`):)B`<$%X>Z@[@*$$B$R0P`283*#` M!*A,L,`$N$S`P`3(3-#`!-A,X,`$Z$SPP`3X>Y18!`A,$,`$&$P@P`0H3##` M!#A,0,`$2$Q0P`183&#`!&A,<,`$>$R`P`2(3)#`!)A,H,`$J$RPP""X?-2= MP%`"R";08`+8)N!@`N@F\&`"^'Q*+`(()A!@`A@F(&`"*"8P8`(X)D!@`D@F M4&`"6"9@8`)H)G!@`G@F@&`"B":08`*8)J!@`J@FL&`"N";`8`+()M!@`M@F MX&`"Z";P?:#$?28/`?&*@`@)$)B`&`D@F(`H"3"8@#@)0)B`2`E0F(!8"6"8 M@&@)<)B`>`F`F("("9"8@)@)H)B`J`FPF("X"<"8@,@)T)B`V`G@F(#H"?"8 M@/A^F0`,")B`$`D8F(`@"2B8@#!_F3A_`8AAGX`!@@2&"8P0E!F>)*HQN$#( M4=ID[GD$D!RI-L12X7``D"&R1-9I_)`DN4[D>A&H0-AQ"J0^V700K$GFA"+! M8`"@0>*$)LEL$+19_J1*\9A`Z)$ZY(XYY)`\Z99$\J%0`+!A$L1V*=R01/FN M9!K1B$#XL6HDWIE4$,R)1@3"@4``P(%"!,:)3!#4F5XDZK%X0`C1FF0N^<20 M7"GVQ))A,`#0H7)$%NF\D&0Y#N2ZD6A`&/'*I'Y9-!#LR::$8D$@`.#!HH1F M22P0]-F^I(IQ6$`H$?KDSKFDD'QI5D0R(1``\.'2Q+:IG)"$>6YD6E%(0#@Q M*B0>&100#`D&!`+W_P`!`@0&"0P0%!D>)"HQ.$!(45ID;GF$D)RIML32X?`` M$"$R1%9I?)"DN<[D^A$H0%AQBJ2^V?00+$EFA*+!X``@06*$ILGL$#19?J3* M\1A`:)&ZY`XY9)"\Z19$<J'0`#!ADL3V*5R0Q/DN9)K1"$!XL>HD7IG4$$R) MQ@1"@<``0('"!$:)S!!4F=XD:K'X0(C1&F2N^420W"EVQ!)AL`!0H?)$END\ MD.0YCN0ZD>A`F/%*I/Y9M!!LR2:$XD&@`&#!(H3F2:P0=-D^I`IQV$"H$7KD M3KDDD/QIUD2R(9``<.%2Q#:I')`$>>YDVE'(0+@QJB2>&900C`F&!((!@$?^ M`1/];R(W15!:86AN<WA\@(2(BXZN]@]9G9^AHZ6GJ:JLKJ^QLK2UMKC*>B*\ MOK_`0HW$Q<;'R,G*2)@DS<XBE`C2BDL$,!$$F@AN(MS<XHG?W^#@4-.",!1! MIN;GY^CHZ>GJZNOK[.SM[>WN[N_O\/#P\?'R\O+S\_3T]/6%X[)Y?]G9VMK: MV]O;8H7<W=W=WM[>W]_?9(*PJB`$X@SCY.3D00;E3.;`".>,"!$,D"";0<#- M(``080`("`$`#P`"(7IF.CHC`3H5`CH.`SH,!#H)!3K0FC("!SH&"#()8`@* MY@LZ!0P-#0TZ!`X/#P\0$!`1$1$2$A(3$Q04%!45%A87%Q@8&1D:(,CW*0CX M5"`A(2(C(R0E)B8G*"DJ*RLL+2XO,#$R,S0U-C<X.3L\/3Y`U/%F"9AE3"C* M45)45EA96UU?86-E9VEK;6]R='9Y>WZ`@X6(BXTOKB29G)^95P,D`083"3`! M#!,/,`$2$Q4P`1@3&S`!'A,A,`$D$R<P`2H3+3`!,!,S,`$V$SDP`3P3/S`! M0A-%,`%($TLP`4X343`!5!-7,`%:$UT!"&"0'5P`@@)J_`!.`$Y4=#450\6L M='AA8"<^/CX@;75L=,5V<X-'3@5%A$!XH$A)1TB@0EE480Q&,RY9"")T99'H M0D4(/41T-UIP;(/8<&]S>7)P3U-)(Q&`H$]2MJ`_E!]LY"(V:88D2)`P5$A% M3I$G8605(S$V.),Y041$+*!!3D2@24:@<W1I;&R@3D5'051)5D4N+BXOCF-M M<'`1,@,1!V)C8R`Z;VL-(&QD82`C,#`@.W-%5*!43Z!:10$M'A!5"/\`[N[N M`+N[QP!`4%6[@0"`JA&J1"A@510`(`!5JA0`[MV[=Q`!@'>[W>X(`+M5[C2% M?D$!`O_;3IF]P]3!K1@$YY#%(``,`(D@``S_D`$@&.<@!`!&&-O,``!^O5," M!O]^`0EKH@0$0``P]^OW[]?O"#8`,"("6/O5J]\`5RW?J]7]/`@`_]^OW_OU M^_\!I'$ORZ&/U@%B'P+L!I[`J;Z]O+NZN+>UL[&OK:NIIJ2AGIN8EI.0C(F& M@X!]>G=T<&UJ:&5B7UQ:5U5344]-2TE(1D5$0T(;\X$!!4!!04)#1$5&2$E+ M34]14U576EQ?$/^H:FUP='=Z?8"#AHF,D).6F)N>H:2FJ:NMK[&SM;>XNKMH M?*B"H0H!`00:D.:!0,8@("`!"(!N``(#!08("0L,#@\0$A,4%1<8&1KNB!P= M2H@!0"`?'Q\>'AT<&QL:&1@7%103$A`/#@P+"0@&!0,"`/[]^_KX]_7T\O'P M[NWLZ^GHY^;GRB/DXRHA!@$'X.'AX>+BX^3EY>;GZ.GK[.WN\/'R]/7W^/K[ M_?Z0<0!\`P">`0#'`(`%`/]_/Q\/!P,!)#$`O@$`SP"`8P#``@"`P.#P^/P2 MV#8,F'^]U(`Z`X(&`""#0/0`O?7V]O;W]_?X^/GY^?KZ^OO[^_S\_/W]_?[^ M_MC%1;2P`04-(W``"$30`"((YB$`B#``!(2`__#_`00`_P`"`!0!%2,N-S]& M3%%66EYB96AL;G%T=GA[?7^!@X6&B(J+C8Z0D9.4E9>8F9J;G)Z?H*&BHZ2E MIJ>GJ*FJJZRMK:ZOL+"QLK.SM+6UMK>WN+FYNKN[O+R]OKZ_O\#`P<'"P\/$ MQ,7%QL;'Q\?(R,G)RLK+R\S,S,W-SL[/S\_0T-'1T=+2T]/3U-34U=75UM;7 MU]?8V-C9V9#F`;``@(03))0PO3'JI$?^2O.1\@[R4/(S\U?QRO'M]C[Q+_-F M_J7T[?4!L$6,`P"]`0$`O1H:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH: ,&AH:&AH:&AH:&AH: ` end ========================================================================= @(#): bottom |