home *** CD-ROM | disk | FTP | other *** search
/ Brotikasten / BROTCD01.iso / texte / cbmhack8.txt < prev    next >
Text File  |  1995-08-20  |  193KB  |  4,708 lines

  1.                    ########
  2.              ##################
  3.          ######            ######
  4.       #####
  5.     #####  ####  ####      ##      #####   ####  ####  ####  ####  ####   #####
  6.   #####    ##    ##      ####    ##   ##   ##  ###     ##    ####  ##   ##   ##
  7.  #####    ########     ##  ##   ##        #####       ##    ## ## ##   ##
  8. #####    ##    ##    ########  ##   ##   ##  ###     ##    ##  ####   ##   ##
  9. #####  ####  ####  ####  ####  #####   ####  ####  ####  ####  ####   ######
  10. #####                                                                     ##
  11.  ######            ######        Issue #8
  12.    ##################            Aug. '94
  13.        ########
  14.  
  15. ----------------------------------------------------------------------(v1.2)--
  16. Editor's Notes:
  17. by Craig Taylor (duck@pembvax1.pembroke.edu)
  18.  
  19.      Woe be to Commodore,
  20.      The marketer's have finally killed it,
  21.      With a little bit of spending here,
  22.      And not much over there,
  23.      You know that Commodore has finally died.
  24.   
  25.      And that's the way life should be,
  26.      The Commodore fanatics cried.
  27.      We'll probably be better off they yell,
  28.      Let Commodore go to hell.
  29.      So the question is who'll purchase Commodore?
  30.  
  31. Yes, for those of you who are unaware Commodore has declared bankruptcy.
  32. There are numerous rumours abound over whose interested in what divisions of
  33. Commodore and such - there's still no definate word on the net. Several
  34. factors can be blamed for Commodore's demise: Commodore _never_ was
  35. successful in marketing products. The engineers would often turn out miracle
  36. machines that the marketing department (I wonder if there even was one)
  37. promoted badly, if at all. What has put the nail in the coffin for Commodore
  38. was the lack of financial capital to keep the company in operation. A lot of
  39. this news has been discussed on GEnie, the newsgroup Comp.Sys.Cbm, and
  40. various magazines as well so I won't elaborate any further. 
  41.  
  42. Speaking of magazines, Creative Micro Designs has started a magazine for
  43. Commodore 8-bit's called, "Commodore World". The magazine is very well done. 
  44. There are other magazines that also deserve mention: DieHard, the Underground
  45. and many others. Commodore may be bankrupt but the Commodore will still live
  46. forever.
  47.  
  48. Speaking of living forever, Commodore Hacking is looking for articles on any
  49. subject dealing with any aspect of technical programming or hardware on the
  50. Commodore. If you've got an article already written, or an idea for one
  51. _please_ feel free to e-mail me via duck@pembvax1.pembroke.edu. Many thanks
  52. to the authors whose works make up this and previous issues. 
  53.  
  54. =============================================================================
  55.  
  56.   Please note that this issue and prior ones are available via anonymous
  57.   FTP from ccnga.uwaterloo.ca (among others) under pub/cbm/hacking.mag
  58.   and via a mailserver which documentation can be obtained by sending
  59.   mail to "duck@pembvax1.pembroke.edu" with a subject line of
  60.   "mailserver" and the lines of "help" and "catalog" in the body of the
  61.   message.
  62.  
  63. =============================================================================
  64.  
  65.   NOTICE: Permission is granted to re-distribute this "net-magazine", in
  66.   whole, freely for non-profit use. However, please contact individual
  67.   authors for permission to publish or re-distribute articles seperately.
  68.   A charge of no greater than 5 US dollars or equivlent may be charged
  69.   for library service / diskette costs for this "net-magazine".
  70.  
  71. =============================================================================
  72. In This Issue:
  73.  
  74. Commodore Trivia Corner
  75.  
  76. This section of C=Hacking contains questions that test your knwoledge of
  77. tricks and little known-information for the Commodore computers. Each issue
  78. they'll be answers to the previous issues questions and new questions. How
  79. much do you know?
  80.  
  81. RS232 Converter
  82.  
  83. This article, with a minimum of parts, details how to make your own RS-232
  84. converter. 
  85.  
  86. Programming the Commodore RAM Expansion Units (REUs)
  87.  
  88. The REC chip is a DMA (direct memory access) chip that allows for the
  89. Commodore 64 and 128 to use the Ram Expansion Units. This article examines
  90. how to access the chip in your own ML programs.
  91.  
  92. A Different Perspective: Three-Dimensional Graphics on the C64
  93.  
  94. In this article, co-written by Stephen Judd and George Taylor, is
  95. presented all the basic graphics tools and mathematical theory behind
  96. 3d graphics.  The basic tools are using a charset to make graphics,
  97. plotting a point, drawing a line, clearing the graphics, and double
  98. buffering.  The 3d tools are defining a 3d object, rotation of the
  99. object in 3d space, and perspective viewing on a 2d screen.
  100. Programs are presented in basic 2.0, basic 7.0, and assembly which
  101. show a rotating cube outline.
  102.  
  103. Design of a 'Real' Operating System for the 128: Part I
  104.  
  105. Written Craig Bruce this article examines a 'real' operating system for the
  106. Commdore 128.  It focuses on the OS being Multi-tasking, Distributed and based
  107. on a MicroKernal.  Why?  As he states, "Because I'm designing it, and that's
  108. what interests me.  The ease-of-construction thing is important too.  Another
  109. important question is 'can it be done?'.  The answer is 'yes.'  And it will
  110. be done, whenever I get around to it (one of these lifetimes)."
  111.  
  112. =============================================================================
  113. Commodore Trivia Corner
  114. by Jim Brain (brain@mail.msen.com)
  115.  
  116. It is time for another dose of trivia!  As some of you may know, The
  117. Commodore Trivia Editions are posted every month to the USENET newsgroups
  118. comp.sys.cbm, alt.folklore.computers, and comp.sys.amiga.advocacy.  This
  119. article is a compilation Trivia Editions 2-8, with only the questions
  120. appearing for Edition 8.  These are part of a Trivia Contest in which 
  121. anyone may enter.  If you wish to participate in the newest
  122. Trivia contest (Which is on Trivia 8 as I write this), please send your
  123. answers to me at 'brain@mail.msen.com'. 
  124.                     
  125. The following article contains the answers to the January edition of trivia
  126. ($00A - $01F), the questions and answers for Febrary ($020 - $02F), March 
  127. ($030 - $03F), April ($040 - $04F), May ($050 - $05F), June ($060 - $06F), 
  128. and the questions for the July edition ($070 - $07F).  Enjoy them!
  129.  
  130.  
  131. Here are the answers to the Commodore trivia questions for January, 1994.
  132.  
  133.  
  134. Q $00A) What was the Code-Name of the Amiga while in Development?
  135.  
  136. A $00A) Lorraine.  Amiga was the company name.  When Commodore bought the
  137.     company, they scrapped the model name and used the old company name.
  138.  
  139. Q $00B) What is Lord British's Real Name (The creator of the Ultima
  140.     Series)?
  141.  
  142. A $00B) Richard Garriott.  Scott Statton has met him and says that he is son
  143.     of astronaut Owen Garriott.
  144.  
  145. Q $00C) What is the POKE location and value that will fry an early model
  146.     PET?        
  147.     
  148. A $00C) 59458.  It is in the (Versatile Interface Adapter, 6522)
  149.     No, I won't tell you what to poke into it, but I will tell you
  150.     that it is not the only way to fry a PET.  here is a description from
  151.     none other than Jim Butterfield
  152.  
  153.     "The poke shopwn above is correct. Its intention was to speed up early
  154.     model PETs by masking the RETRACE line (by switching it to output)...
  155.  
  156.     however, Commodore subsequently REDESIGNED the interface in such a way
  157.     that making the VIA pin an output caused (now) two outputs to fight
  158.     each other ... result, VIA and/or video circuitry burnt out.
  159.  
  160.     LATER (Days of "fat 40" and 80-column PETs), the new CRT controller
  161.     chip could be fiddled with POKES so that it generated scan rates
  162.     completely out of the capacity of the CRT deflection circuits.  
  163.     Result: burnt out deflection circuitry ... and that was no YOKE!"
  164.  
  165.     Richard Bradley says that 59595 is the second poke that Jim is
  166.     referring to.
  167.  
  168.     I also have in on word from Ethan Dicks that 59409 is another
  169.     infamous poke, but I wouldn't try any of these!
  170.     
  171. Q $00D) On the Plus 4 and C-16, the VIC chip was replaced with the TED
  172.     chip.  What does TED stand for?
  173.  
  174. A $00D) TED = Text Editing Device.  It did not have as many capabilities
  175.     as the VIC II.
  176.     
  177. Q $00E) Commodore Produced a daisy-wheel letter quality printer in North
  178.     America (maybe elsewhere) for the Commodore Serial Line.  Name it.
  179.            
  180. A $00E) The Commodore DPS 1101.  The CBM 6400 was another earlier attempt
  181.     at a daisy-wheel printer, but it had an IEEE-488 interface.
  182.     
  183. Q $00F) What is the version of DOS in the 1541?
  184.  
  185. A $00F) 2.6
  186.  
  187. Q $010) What is the Version of BASIC in the Plus 4 and the C-16?
  188.  
  189. A $010) 3.5.
  190.  
  191. Q $011) What are the nicknames of the original three custom Amiga chips?
  192.  
  193. A $011) Daphne/Denise, Agnes/Agnus, and Paula/Portia, or Huey, Duey, and Louie.
  194.     Denise, Agnes, and Paula were the American names, but the the others
  195.     crept in from somwhere.  the ducks were always a joke, but caught on
  196.     as alternate names.
  197.  
  198. Q $012) Commodore produced a 64 in a PET case.  What is its name and model
  199.     number?
  200.  
  201. A $012) The Educator 64.  It was model number CBM 4064, and it was also called
  202.     the PET64.  Note that this version of the 64 was the second attempt.
  203.     Commodore first tried to sell the "Educator 64" to schools in the
  204.     regular 64 case, but administrators and teachers disliked the "homey"
  205.     look.  Thus, it was squeezed into a PET case and sold better, although
  206.     I don't think it was ever a killer seller.
  207.  
  208. Q $013) Commodore sold a 1 megabyte floppy disk drive in a 1541 case.
  209.     Give the model number.
  210.  
  211. A $013) The Commodore SFD 1001.  It was actually half of an CBM 8250 LP
  212.     with a slightly revised ROM.
  213.     
  214. Q $014) What does GCR stand for?
  215.  
  216. A $014) Group Code Recording.
  217.  
  218. Q $015) Commodore produced a drive to accompany the Plus 4 introduction that
  219.     was designed specifically for the Plus/4.  Give the model number.
  220.                          
  221. A $015) the CBM 1551 was the new, high-performance drive that was designed
  222.     specifically for the Commodore Plus/4 and C-16.  The 1542 was
  223.     actually just a repackaged 1541 in a grey case that was made available
  224.     for people who didn't want to spend the extra money for the 1551.  The
  225.     extra cost resulted from the 1551 sporting a new, parallel transfer
  226.     method that increased transfer rates 400%.
  227.  
  228. Q $016) What does SID stand for?
  229.  
  230. A $016) SID = Sound Interface Device
  231.  
  232. Q $017) What does the acronym KERNAL stand for?
  233.  
  234. A $017) KERNAL = Keyboard Entry Read, Network, And Link.  This is most likely
  235.     another "words after the letters" acronym, along the lines of the
  236.     PET acronym.
  237.  
  238. Q $018) What version of DOS does the 1571 have?
  239.  
  240. A $018) 3.0
  241.  
  242. Q $019) What other two Commdore Disk Drives share the same DOS version
  243.     number as the 1571?
  244.  
  245. A $019)    I got more than I bargained for on this question, since there
  246.            are four drives which have the same DOS version that I feel are
  247.            adequate responses to this question. 
  248.            
  249.     The CBM D9060 and D9090, although I doubt the code is the same.
  250.     The D series were hard drives. 
  251.                        
  252.     The 8280 Dual 8" Floppy Drive.
  253.     
  254.     The 1570, which was a single sided version of the 1571 in a 1541
  255.     case painted to match the 128.  The ROM is slightly different,
  256.     enough to make it unrecognizable as either a 1541 or a 1571 in some
  257.     cases.
  258.  
  259.     The 1571II and the 1571D, which is the drive in the C128D, also 
  260.     have this DOS revision, but that stands to reason, since they are 
  261.     in the 1571 line.
  262.  
  263. Q $01A) How many files will the 1571 hold?
  264.  
  265. A $01A) 144 in both modes.  I am surprised Commodore didn't add a track or
  266.     put another directory on the back.
  267.  
  268. Q $01B) How many files will the 1541 hold?
  269.  
  270. A $01B) 144. 
  271.          
  272. Q $01C) What did Commodore make right before entering the computer market?
  273.  
  274. A $01C) Calculators.  They also made office equipment, watches, adding 
  275.     machines, and thermostats, hence the name "Commodore Business 
  276.     Machines".        
  277.      
  278. Q $01D) Commodore introduced an ill-fated 4 color plotter.  Give the model
  279.     number.
  280.  
  281. A $01D) the Commodore 1520.  It used 4 inch wide paper and could use 4
  282.     colors.
  283.     
  284. Q $01E) Some formats of CP/M write disks using the MFM format.  What does
  285.     MFM stand for?
  286.  
  287. A $01E) MFM = Modified Frequency Modulation
  288.     
  289. Q $01F) On the Commdore 128, the user manual left three commands undocumented.
  290.     One works, and the other gives a not-implemented error.  Name the
  291.     commands and what each one does or does not do.              
  292.  
  293. A $01F) RREG reads the internal registers after a SYS command.
  294.            OFF gives an unimplemented command error. 
  295.     QUIT does too.
  296.  
  297.  
  298. Here are the answers to Commodore Trivia Edition #3 for February, 1994.
  299.  
  300.             
  301. Q $020) What does the letters IEEE in IEEE-488 stand for?
  302.  
  303. A $020) Institute of Electrical and Electronics Engineers.
  304.  
  305. Q $021) What was the logo of Batteries Included?
  306.  
  307. A $021) It was a the face and hands of a man with glasses inside a circle.
  308.         Early renditions of him were in black and white, while later ones had
  309.         him with blond hair a a red shirt.  Some views had him actually 
  310.         typing on the 64/VIC with one finger, but most just showed him, 
  311.         not the keyboard.
  312.  
  313. Q $022) The Commodore VIC-20, 64, and 128 computers emulate in software a very
  314.         important integrated circuit. What is its number, and why is it 
  315.         important?
  316.  
  317. A $022) The 6551 UART IC.  It is used for RS-232 communications.
  318.  
  319. Q $023) Commodore watches play a beautiful song for the alarm.  What is the
  320.         song's title?
  321.  
  322. A $023) Fleur-de-lis.  The "Godfather" theme.
  323.  
  324. Q $024) The C2N style Commodore tape decks are impressive in handling errors.
  325.         How many times is a single program stored onto tape?
  326.  
  327. A $024) Twice, second copy is placed right after the first.  That means, even
  328.         if you get a load error on load, you might be able to just run the 
  329.         program anyway, as a load puts the first copy in memory, and verifies
  330.         it against the second copy.
  331.         
  332. Q $025) What is a jiffy?
  333.  
  334. A $025) A jiffy is 1/60th of a second.  It is the same on PAL and NTSC
  335.         Commodore computers.
  336.  
  337. Q $026) What is the screen resolution of the Commodore VIC-20?
  338.  
  339. A $026) On the VIC-I IC, the text and graphics screens are definable within
  340.         limits.  Therefore, there are a number of answers that are correct:
  341.  
  342.         The default screen has (and the answers I was looking for):
  343.  
  344.         Text:     22H x 23V = 506 characters
  345.         Graphics: 176H x 184V = 32384 pixels
  346.         
  347.         However, on experimentation with a NTSC VIC-I (6560), I found that
  348.         it could support a resolution of:
  349.  
  350.         Text:     24H x 29V = 696 characters
  351.         Graphics: 192H x 232V = 44544 pixels
  352.  
  353.         Your mileage may vary, but these numbers remove all border area.
  354.         (I am not sure if you can use all the pixels, since the VIC-I only
  355.         allows 32768 to be used.  You might be able to flip the graphics
  356.         page in the middle of the screen, but I leave that as an exercise.)
  357.     
  358.         The VIC-I also supports a virtual screen, which can be "panned" so
  359.         that the physical screen becomes a "window" into the virtual screen.
  360.         The maximum "scrollable" virtual screen on NTSC is:
  361.  
  362.         Text:     28H x 32V? = 896 characters
  363.         Graphics: 224H x 256V? = 57344 pixels
  364.  
  365.         The VIC supports more resolution than 32V, but you can never see
  366.         it since you can't scroll it into view, so the point is moot.
  367.  
  368.         So, if I didn't thoroughly confuse you, email me and I will make
  369.         sure I do!
  370.      
  371. Q $027) Why is the VIC-20 named the VC-20 in Germany?
  372.  
  373. A $027) Because 'V" is pronounced 'F" in Germany, and the resulting
  374.         pronunciation was a naughty word. 
  375.    
  376.         Commodore put one over on many people.  The VIC-20 was designed in
  377.         the states and given that name due to the IC that did the graphics.
  378.         When the marketing started, CBM found out the name was no good in
  379.         Germany, so they quickly renamed it VC-20.  The after-the-fact
  380.         Volks-Computer conjured up images of the Volkswagon car (VW), which
  381.         was popular at the time for its dependability and price.  The rest is
  382.         history...
  383.          
  384. Q $028) Why was early Commodore equipment built into such heavy enclosures?
  385.  
  386. A $028) Simple.  Commodore made office furniture, which includes desks and
  387.         filing cabinets.  They simply used the facilities and parts on hand.
  388.         The fact that, at the time the PET came out, people equated physical
  389.         stability of a machine as an indication of its worth, served only to
  390.         reinforce the decision.  Also, the system had to hold up the built-in
  391.         monitor.
  392.                                 
  393.         Most people think it is due to FCC regulations.  FCC regulations had
  394.         not been determined at the time the PET came out, although the
  395.         engineers did know that the CRT produced many electrical hazards which
  396.         could be alleviated with a shielded metal case.  Commodore has always
  397.         been a "cheap" company, so the fact that they could get good
  398.         shielding in-house at almost no cost proved to be the overriding
  399.         factor. It might interest some to note that, even with the metal
  400.         case, early PETs had foil inside as a secondary shield.  The reason
  401.         has to do with the keyboard being mostly plastic, as the shield fit
  402.         directly underneath, but the reason for it remains a mystery to me.
  403.                                        
  404. Q $029) What two BASIC 2.0 commands might still work if mispelled?
  405.    
  406. A $029) The answers I was looking for are END and STOP, although someone
  407.         correctly pointed out that GO TO can be construed as a mispelling.
  408.         Also, print#, get#, and input# might work if the '#' was omitted and 
  409.         the program was getting data to screen or keyboard.
  410.  
  411.         Although the following aren't really the result of mispelled commands,
  412.         I put them in, since you could stretch the definition of mispelled to
  413.         include them.
  414.  
  415.         LET would work if it was left out, since LET was an optional 
  416.         keyword.  Commands of the form <keyword> <number or variable> would
  417.         work if letters were tacked onto the end. (example: RUNDY., prg has 
  418.         a valid line 0, and DY = 0).  Finally, LOAD"jim",8,1garbage would
  419.         work due to the way LOAD absolute worked, but that is a stretch!
  420.      
  421. Q $02A) What does CIA stand for? (not the U.S. CIA!)
  422.  
  423. A $02A) CIA = Complex Interface Adapter.  The german Magazine 64'er calls
  424.         it a Control Interface Adapter, but that is not its official
  425.         name.
  426.      
  427. Q $02B) (hard one) What is the key VIC capability that makes full-screen
  428.         hires graphics possible on the _VIC-20_?
  429.  
  430. A $02B) A lot of people answered redefinable characters, but that alone does
  431.         not provide FULL-SCREEN graphics. 256 8*8 cells gives you a little
  432.         over 1/2 of the screen in graphics, but the VIC has the ability to 
  433.         make each character cell be 8*16, which gives enough pixels to map
  434.         the entire default screen.
  435.      
  436. Q $02C) How many cassette ports does the CBM 8032 computer have?
  437.  
  438. A $02C) Two.  One on back, one on side near the back.
  439.      
  440. Q $02D) What 5 bytes must appear in every Commodore 64 autostart cartrdge and
  441.    what location in memory must they be placed at?
  442.  
  443. A $02D) CBM80 at $8004.  The letters must have bit 7 set. So, the actual
  444.         PETSCII codes are 195, 194, 205, 056, 048.
  445.                      $c3, $c2, $cd, $30, $30 in HEX
  446.  
  447. Q $02E) What is the correct Commodore technical term for "Sprites"?
  448.  
  449. A $02E) MOBs, or Movable Object Blocks.
  450.      
  451. Q $02F) (Three parter, all parts must be correct)  "Push-wrap-crash" is a
  452.         nickname for a condition that can lock up an old-style C=64. 
  453.         What causes it? 
  454.         How can it be avoided (besides not doing it)?
  455.         What is the only way out once it has occured (besides rebooting)?
  456.  
  457. A $02F) Wow, I got so many responses to this!  This question actually
  458.         dealt with a typical user, but people sent in descriptions of
  459.         what the code does and how to patch it. So, there are two sets
  460.         of answers to this:
  461.  
  462.     User Answer:
  463.  
  464.     1) If you put the cursor at the bottom of the screen and type 82 characters
  465.        (not 81) and then trying to delete back to the 78th one.  
  466.     2) Any of the following will work:
  467.     
  468.           Do not use the following colors for the cursor: red, blue, yellow, 
  469.           light red, dark grey, light blue, light gray.
  470.     
  471.           Some people devised a IRQ wedge that will recover from the lockup.
  472.     
  473.           Have the following lines as the first lines of a program:
  474.           10 open 15,8,15 20 input#15,a$.
  475.     3) There are actually two ways to recover.  They are:
  476.     
  477.           If you have a reset button installed on the 64, reset the machine,
  478.           then load and run an unnew program.  (I accepted this, but I figured
  479.           most people would assume this much)
  480.     
  481.           If you have a tape drive installed, press either Shift-3 or move a
  482.           joystick installed in Port 1 in the UP direction.  Then, respond to
  483.           the directions on the screen "PRESS PLAY ON TAPE". Next, press
  484.           RUN-STOP to stop the tape load. 
  485.     
  486.  
  487.     What really happens: (I can't prove this)
  488.     
  489.     1) The user types the line of text and the scroll code is invoked.
  490.        The first two lines become linked as one logical line, and the
  491.        third line is treated as a new line. 
  492.     
  493.        The user deletes the 82nd and the 81st character and then hits delete
  494.        while in the first column of the third line.  Since the delete will put
  495.        the cursor back up into the second line, which is linked with the first,
  496.        the KERNAL gets confused and thinks the second line is at the bottom of
  497.        the screen. Remember, the "cursor" is actually constructed by a
  498.        combinations of using reverse characters and changing the color RAM
  499.        nybble for that screen location.  Thus, when the cursor gets "erased"
  500.        from the first column of the last line, the KERNAL thinks the color
  501.        nyble for it is at $DC00, which is 40 bytes off from the actual
  502.        position.  $DC00 is actually Port A for CIA #1, which is where the
  503.        kernal writes the column of the keyboard it wishes to scan. Because the
  504.        KERNAl is messed up, it puts the color nybble for where it thinks the
  505.        cursor was into this location. (That is why there is a connection
  506.        between cursor color and this bug.  
  507.     
  508.        Now, the system integrity has been compromised, but it does not show
  509.        yet.  The user proceeds to delete the 80th character.  As the user
  510.        deletes the 79th character, the bad value in $DC00 goes to work and
  511.        fools the KERNAl into thinking SHIFT/RUN-STOP has been pressed.  It also
  512.        pretty much disables the keyboard.  
  513.     
  514.     2) Since the Color RAM is what the KERNAl gets confused about, the solution
  515.        was to not use certain bit patterns of colors:
  516.     
  517.           RED         0010
  518.           CYAN        0011
  519.           BLUE        0110
  520.           YELLOW      0111
  521.           LIGHT RED   1010
  522.           DARK GRAY   1011
  523.           LIGHT BLUE  1110
  524.           LIGT GRAY   1111
  525.     
  526.           OK Colors:
  527.     
  528.           BLACK       0000
  529.           WHITE       0001
  530.           PURPLE      0100
  531.           GREEN       0101
  532.           ORANGE      1000
  533.           BROWN       1001
  534.           MEDIUM GRAY 1100
  535.           LIGHT GREEN 1101
  536.  
  537.           All of the BAD colors have bit 1 set.  I have no idea what the
  538.           significance of that is.
  539.  
  540.     3) You needed to get out of the tape load code, but you only had so many
  541.        keys that were still active.  So, if you followed the directions on
  542.        the screen, you could break out.  Since the tape load code uses CIA #1
  543.        for its operations, it would take over the IC and then restore it
  544.        to a correct state when either the load was stopped or the load
  545.        completed.  Now, that is amazing!
  546.  
  547.        (Someone is free to check up on me concerning this, since I do not
  548.         have a Rev 1 ROM to try out.  If someone has one, I would like to
  549.         have a copy of it on disk or in email.  And if someone has the
  550.         information on this bug from either the May 1984 Gazette p108, or
  551.         from the COMPUTE! Toolkit Kernal VIC20/64, I would like a copy.)
  552.  
  553.  
  554. Here are the answers to Commodore Trivia Edition #4 for February, 1994.
  555.  
  556.  
  557. Q $030) On a Commodore 64, what is the amount of RAM available for BASIC
  558.         programs to reside in?
  559.  
  560. A $030) Some people over-answered this question.  The correct answer is
  561.         38911 bytes, which is what the BASIC screen says.  Now, it is true
  562.         that BASIC can use $C000-$CFFF, and some zero pages is easily used
  563.         by BASIC, but it is non-trivial to get BASIC to use these areas.
  564.         The math comes out to:  $0801 (2048) to $9FFF (40959) - 1 (0 in
  565.         location 2048).  Please note that this is not the maximum size of
  566.         a standard BASIC program, even if it does not use variables, since
  567.         BASIC steals 3 bytes at the end of the program to determine the end.
  568.  
  569. Q $031) Name one Commodore computer (pre-Amiga) that used two general purpose
  570.         microprocessors?
  571.  
  572. A $031) There are two (or more) answers to this question.  The obvious answer
  573.         is the Commodore 128, but the Commodore SuperPET (SP9000) had two,
  574.         also.  There was also an optional card to add another processor to
  575.         the B-series.  Note that some Commodore peripherals also had two
  576.         (or more) microprocessors, but that is another question.
  577.  
  578. Q $032) What are they?
  579.  
  580. A $032) Commodore 128: 8502(6510 clone) and Z80.  SuperPET: 6502 and 6809.
  581.         B-series: 6509 and 8088.
  582.  
  583. Q $033) Who was the Chief Executive Officer of CBM when the Commodore VIC-20
  584.         (VC-20) was introduced?
  585.  
  586. A $033) According to my sources, it is none other than Jack Tramiel.  While
  587.     some claim Irving Gould as the man-in-charge since he had
  588.         controlling interest at the time, the CEO was Jack.  Whether he was
  589.         in charge or not is left up to the reader.
  590.  
  591. Q $034) the Commodore 64 and 128 (among others) have a TOD feature.  What does
  592.         TOD stand for?
  593.  
  594. A $034) TOD = Time Of Day.  The 6526 Complex Interface Adapter is the holder
  595.     of the TOD clock, which can be used in lieu of the system jiffy
  596.     system clock to time things, as it does not suffer from interruptions
  597.         to service I/O and screen.  Note that the standard kernal uses the
  598.     system clock for TI and TI$, not the TOD clock.
  599.  
  600. Q $035) What location in the Commodore 64 Kernal holds the version number?
  601.  
  602. A $035) $ff80 (65408).
  603.  
  604. Q $036) The first computer Commdore sold was the KIM-1.  How much RAM was
  605.         available on the KIM-1?
  606.  
  607. A $036) 1.125K or 1024+128 = 1152 bytes.
  608.  
  609. Q $037) Who designed the architecture for the 6502 integrated circuit?
  610.  
  611. A $037) Chuck Peddle
  612.  
  613. Q $038) What was the original name of the company that produced the 6502?
  614.  
  615. A $038) MOS Technologies
  616.  
  617. Q $039) What did the name stand for?
  618.  
  619. A $039) MOS = Metal Oxide Semiconductor, which has three major families:
  620.         NMOS: Negative MOS, PMOS: Positive MOS, and CMOS: Complementary MOS.
  621.         MOS Technologies produced mainly NMOS ICs, hence the use of NMOS
  622.         technology for the 6502 and 6510.
  623.  
  624. Q $03A) Commodore acquired the company and renamed it to...?
  625.  
  626. A $03A) CSG = Commodore Semiconductor Group.  The renaming was not
  627.         instantaneous, happening a number of months(years) after the
  628.         acquisition.
  629.     
  630. Q $03B) The Commodore VIC-20 graphics were powered by the VIC-I (6560)
  631.         integrated circuit.  Was the chip designed for the computer, or was
  632.         the computer designed for the chip?
  633.  
  634. A $03B) The VIC-I 6560-61, was designed 2 years prior to the design of the
  635.         VIC-20 computer.  It was designed to be built into video games, but
  636.         no one wanted to use it, so Commodore made their own system
  637.         around it to recoup losses.
  638.  
  639. Q $03C) The VIC-20 had a Video Interface Chip (VIC) inside it, yet that was
  640.         not what the 'VIC' in the model name expanded to.  What did it
  641.         expand to?
  642.  
  643. A $03C) VIC-20 = Video Interface Computer-20.  The 20 was a rounding down
  644.         of the amount of memory in the VIC: ~22K.  Michael Tomczyk, who got
  645.         stuck with the job of deciding on the name, did the rounding.
  646.  
  647. Q $03D) The most widely known disk drive for Commodore computers is the 1541.
  648.         how much RAM does the 1541 have?
  649.  
  650. A $03D) 2048 bytes, or 2kB RAM. It is mapped at $0000-$07FF.
  651.  
  652. Q $03E) On every Commodore disk, the drive stores a copy of the BAM.  What
  653.         does BAM stand for?
  654.  
  655. A $03E) BAM = Block Allocation Map, or Block Availability Map.  I am checking
  656.     sources to figure out which one is the real McCoy.
  657.  
  658. Q $03F) Now, for those into 6502 machine language.  What instruction was not
  659.         available on the first 6502 chips?
  660.  
  661. A $03F) ROR (ROtate Right) was not available until after June, 1976.  However,
  662.         all Commodore VICs and C64s should have this instruction.  Some people
  663.         gave instructions that are found on the 65c02, designed by Western
  664.         Design Center, and licensed to many companies.  However, the 65c02
  665.         itself occurs in two flavors, and neither are used in any stock
  666.         Commodore product I know of.
  667.  
  668.  
  669. Here are the answers to Commodore Trivia Edition #5 for April, 1994.
  670.  
  671.  
  672. Q $040) The company that produces The Big Blue Reader, a program that allows
  673.         reading and writing of IBM formatted disk in 1571s and 1581s, is
  674.         called SOGWAP.  What does SOGWAP stand for?
  675.  
  676. A $040) Son Of God With All Power.  They also market the Bible on diskettes.
  677.  
  678. Q $041) What version of DOS does the Commodore 8280 8 inch dual drive have?
  679.  
  680. A $041) The 8280 has version 3.0.  Many have not ever seen this IEEE-488
  681.         compatible drive used on some PETs.  It has the same DOS version
  682.         that is in the D90XX hard drives, and could read 250kB and 500kB
  683.         IBM formatted disks, as well as some CP/M formats.  Note that although
  684.         this version number is used on the 1570/71 disk drives, the code is
  685.         different.
  686.  
  687. Q $042) What was the color of the original Commodore 64 case?
  688.  
  689. A $042) Some early versions of the Commodore 64 were housed in VIC-20 color
  690.         cases, so off-white is the correct answer.
  691.         
  692. Q $043) On an unexpanded Commodore 64, how does one read the RAM
  693.         locations $00 and $01?
  694.  
  695. A $043) Well, you cannot do so with the CPU directly, since it resolves these
  696.         locations into internal addresses.  However, the VIC II can see these
  697.         addresses as external memory.  So, just make one spritexs with the
  698.         first bit in the sprite set, and move it over the first two bytes, 
  699.         pretending they are part of a bitmap.  By checking the sprite-to-
  700.         background collision register, you can tell if the bit in the byte is
  701.         set.  Email me for a more complete description. 
  702.         
  703.         Sven Goldt and Marko Makela get credit for this answer and the next.
  704.  
  705. Q $044) On an unexpanded Commodore 64, how does one write the same locations?
  706.  
  707. A $044) It seems the 6510 generates a valid R/W signal any time it does an 
  708.         internal read or write.  This is to be expected, since the 6510
  709.         internal registers were grafted onto a 6502 core processor.  
  710.         Howevere, the address lines are also valid during any internal read
  711.         or write, since failure to do so may write the data on the data bus
  712.         to some invalid address.  The data on the bus, however, comes not from
  713.         the CPU, but from residual effects of the data last read of written by
  714.         the VIC chip.  Thus, by programming the VIC chip to read data from
  715.         some known location, and by placing relevant data in that location, a
  716.         write to location $00 or $01 will place the data from that last read
  717.         VIC location into $00 or $01.  This is usually accomplished by placing
  718.         the data to be written out into location $3fff, which the VIC fetches
  719.         during the time the border is being displayed.  By triggering a
  720.         routine when the raster hits the bottom border, you can copy location
  721.         $3fff to $00 or $01.
  722.  
  723. Q $045) What is 'CB2 Sound', and on what computers was it popular?
  724.  
  725. A $045) This is the sound made by sending square out of the 6522 IC on some
  726.         Commodore computers.  It is called 'CB2', since that is the name of
  727.         the pin on the 6522 that outputs the waveform.  I won't go into a
  728.         complete description, except to say that most models of the PET
  729.         had the capability, and most PET owners used it as the ONLY sound
  730.         source, since the PETs did not have a sound chip.  Although the VIC
  731.         did have some sound capabilities, by that time Commodore had 
  732.         realized its widespread use and included some information on it in
  733.         the Commodore VIC-20 Programmer's Reference Guide.  For more info,
  734.         reach for your nearest VIC PRG and look at page 232.
  735.  
  736. Q $046) in question $021, the Batteries Included logo description was asked
  737.         for.  Now, what is the name of the man in the logo?
  738.  
  739. A $046) "Herbie"  Jim Butterfield supplied me with this one.
  740.  
  741. Q $047) Why was the Commodore VIC-20 produced with so many 1K chips in it?
  742.         (Hint: it had little to do with the cost of SRAM at the time)
  743.  
  744. A $047) Jack (Tramiel) decreed that Commodore had a surplus of 1K chips,
  745.         so he didn't care how much memory it had, as long as the designers
  746.         used 1K SRAMs.
  747.  
  748. Q $048) What does ADSR stand for?
  749.  
  750. A $048) ADSR = Attack, Decay, Sustain, Release.  These are the four values
  751.         specified to define a SID waveform envelope.
  752.  
  753. Q $049) In question $035, it was learned that the Commodore 64 kernal
  754.         revision number is stored at $ff80 (65408).  Now, what is the number
  755.         stored there for:
  756.  
  757.         a) The first revision?
  758.         b) The PET64 (4064)?
  759.  
  760. A $049) a) 170. (Yep, this was prior to 0!)
  761.         b) 100. (The PET 64 uses this value to adjust the startup logo
  762.                  accordingly.)
  763.  
  764. Q $04A) Who was the mastermind behind the original Commodore Kernal?
  765.  
  766. A $04A) John Feagan.  He had intended it to provide upward compatibility
  767.         for future computer systems.  Unfortunately, the kernal was
  768.         modified enough with each new computer system, that the idea of
  769.         compatibility never really surfaced.  Still, it was a nice try.
  770.  
  771. Q $04B) Who designed the first VIC prototype?
  772.  
  773. A $04B) There are two answers to this question.  At the time, the VIC had no
  774.         name and was called the MicroPET or No Name Computer.  Jack Tramiel
  775.         wanted to show some prototypes of the VIC at the 1980 Comsumer
  776.         Electronics Show (CES).  The funny thing is, he got not one
  777.         prototype, but TWO.  Bob Yannes, working against time, had hacked
  778.         together a minimal working prototype using spare PET/CBM parts.
  779.         Another prototype, brought to the show by Bill Seiler and John
  780.         Feagans, had been put together after some preliminary discussions
  781.         with Yannes.
  782.  
  783. Q $04C) How many pins does a Commodore 1525 printhead have in it?
  784.  
  785. A $04C) Trick Question.  The two 1525 printers I have show that the 1525 
  786.         printhead has but one pin.  The seven dots are created by a revolving
  787.         7 sided star-wheel for the platen, which presses the paper against the
  788.         printhead in the seven different dot locations.
  789.  
  790. Q $04D) Why does mentioning a PET computer in France make people chuckle?
  791.  
  792. A $04D) PET means "FART" there.
  793.  
  794. Q $04E) What interface IC is used to drive the IEEE-488 bus in a PET computer?
  795.  
  796. A $04E) A 6520.  It is appropriately called a PIA (Peripheral Interface
  797.         Adapter).
  798.  
  799. Q $04F) What was the primary reason Commodore went to a serial bus with the
  800.         introduction of the VIC-20?
  801.  
  802. A $04F) Jim Butterfield supplied me with this one:
  803.  
  804.         As you know, the first Commodore computers used the IEEE bus to
  805.         connect to peripherals such as disk and printer.  I understand that
  806.         these were available only from one source:  Belden cables.  A
  807.         couple of years into Commodore's computer career, Belden went out
  808.         of stock on such cables (military contract? who knows?).  In any
  809.         case, Commodore were in quite a fix:  they made computers and disk
  810.         drives, but couldn't hook 'em together! So Tramiel issued the
  811.         order:  "On our next computer, get off that bus.  Make it a cable
  812.         anyone can manufacture".  And so, starting with the VIC-20 the
  813.         serial bus was born.  It was intended to be just as fast as the
  814.         IEEE-488 it replaced.  
  815.         
  816.         And it would have been, except dor one small glitch.  But that is
  817.         another trivia question.
  818.  
  819.  
  820. Here are the answers to Commodore Trivia Edition #6 for May, 1994.
  821.  
  822.  
  823. Q $050) The Commodore 1551 Disk Drive is a parallel device.  How did it
  824.         connect to the Commodore Plus/4 and C16?
  825.         
  826. A $050) The Commodore 1551 connected via the expansion port.  Therefore, it
  827.         was a parallel device, and could work at much faster speeds.
  828.  
  829. Q $051) How many could you attach?
  830.  
  831. A $051) Two, The second drive cable attached to the back of the first cable.
  832.         
  833. Q $052) What were the addresses they used? (Not device numbers)
  834.  
  835. A $052) The two drives were mapped into the Address space at $fec0 and $fef0
  836.         of the Plus/4 or C-16.  The 6523 Triple Interface Adaptor chip is
  837.         mapped in at these locations and has 8 registers each.
  838.         
  839. Q $053) What is the maximum number of sound octaves the VIC-20 sound generator
  840.         can reach?
  841.  
  842. A $053) This has two equally valid answers. On the Vic-20, each sound 
  843.         generator has a range of 3 octaves.  However, all the sound generators
  844.         together can range 5 octaves, since each sound generator is staggered
  845.         one octave apart.
  846.         
  847. Q $054) Who wrote the reference guide that was distributed with almost every
  848.         PET computer sold?
  849.  
  850. A $054) The infamous Adam Osborne, of Osborne I fame.
  851.         
  852. Q $055) The box that the C64 comes in has some propaganda on the side
  853.         describing the unit.  In the specifications section, it claims how
  854.         many sprites can be on screen at one time?
  855.  
  856. A $055) I neglected to note that the Commodore 64 packing box has underwent
  857.         many changes.  However, for quite a while, CBM used a blue box with
  858.         many views of the 64, and a specification list on on side of the box.
  859.         On that spec list, it claims that the the 64 can have "256 
  860.         independently controlled objects, 8 on one line."  Why is this
  861.         important?  It gives us a clue that the VIC-II designers figured people
  862.         would and could use the interrrupts on the VIC-II to change sprite
  863.         pointers.
  864.         
  865. Q $056) The Commodore Plus/4 computer contained the first integrated software
  866.         package to be placed in a personal computer.  What was the name of the
  867.         software package?
  868.  
  869. A $056) The package was called "3+1".
  870.         
  871. Q $057) What popular computer software did the software package parody?
  872.  
  873. A $057) Lotus 1-2-3.
  874.         
  875. Q $058) One familiar Commodore portable computer was called the SX-64.
  876.         What did SX really stand for?
  877.  
  878. A $058) Depending on whom you believe, the SX stands for two things.  If you
  879.         choose to believe Jack Tramiel, the SX stands for "sex", since Jack
  880.         has been quoted as saying, "Business is like sex, You have to be
  881.         involved".  This is a plausible answer, as Jack usually picked the
  882.         names of the computers.  However, if you don't buy that, here is the 
  883.         marketing version.  SX stands for Single Drive Executive, as the 
  884.         portable 64 was called the Executive 64.  There was to have been a DX
  885.         model, which would have had two drives.  You decide.
  886.         
  887. Q $059) Who (what person) invented the Sound Interface Device (SID) chip?
  888.  
  889. A $059) Bob Yannes, who also worked on one of the VIC prototypes, developed
  890.         this chip.
  891.         
  892. Q $05A) The ill-fated UltiMax (later called the MAX Machine) contained a
  893.         number of Commodore 64 features.  However, it did not share the 64's
  894.         feature of 64kB RAM.  How much RAM did the MAX have?
  895.  
  896. A $05A) A whopping 2 kilobytes.  If you plugged in the BASIC cartridge, 
  897.         memory dropped to .5 kilobyte or 512 bytes.  No wonder CBM scrapped
  898.         this one.
  899.         
  900. Q $05B) What famous person was featured in U.S. television advertising for
  901.         the VIC-20?
  902.  
  903. A $05B) William Shatner.  Yes, Captain James T. Kirk himself did the ads.
  904.         He was not, however, in uniform, since CBM did not have rights to
  905.         Star Trek of any sort.
  906.         
  907. Q $05C) What company designed the first VICModem?
  908.  
  909. A $05C) Anchor Automation.  Sometimes called the "Most Inexpensive Modem", 
  910.         the VICModem was designed to be sold for under $100 when most were
  911.         $400 or more.  The secret to the cost containment was the ability to 
  912.         use what we soetimes think of as a disadvantage of the User Port to
  913.         the modem's advantage.  The TTL level RS-232 signals did not need to
  914.         be buffered before driving the modem, and the +5 volt power available
  915.         through the User Port just was not available through normal RS-232
  916.         lines.  Not having the already TTL level signals would have meant 
  917.         extra components that would have increased case size and cost, and not
  918.         having the on-board power would have meant a power connector and power
  919.         supply would need to be bundled.  Being one of those people who used
  920.         the first VICModem, I can tell you it was worth the hassle.
  921.         
  922. Q $05D) Everyone has seen or heard of BYTE Magazine.  Known for technical
  923.         articles in the 80's, and coverage of PC products in the 90's, BYTE
  924.         was founded by Wayne Green.  What Commodore computer magazine did
  925.         Wayne Green later publish?
  926.  
  927. A $05D) RUN Magazine.  As of right now, CMD has purchased the rights to RUN.
  928.         
  929. Q $05E) (Three part question) What are the official names of the colors
  930.         used on the VIC-20:
  931.  
  932.         a)  case?
  933.         b)  regular typewriter keys?
  934.         c)  function keys?
  935.  
  936. A $05E) a)  ivory.
  937.         b)  chocolate brown.
  938.         c)  mustard.
  939.         
  940. Q $05F) Commodore is set up as a ___________ chartered company.  Name
  941.         the missing country.
  942.  
  943. A $05F) Bahamas.  Doing so gave CBM a great tax break.  With the tax rate in
  944.         the Bahamas as low as 1%, more money could be kept from the 
  945.         governments.
  946.  
  947.  
  948. Here are the answers to Commodore Trivia Edition #7 for May, 1994.
  949.  
  950.  
  951. Q $060) When you turn on stock Commodore 16, how many bytes free does it
  952.         report?
  953.  
  954. A $060) According to the initial power-up indication on the monitor, a stock
  955.         Commodore 16 has 12277 bytes free for BASIC program use. A number od
  956.         people have calculated 12287 bytes, so the power-on message may be in
  957.         error.  I guess it is time to dig out the C-16 and power it up.
  958.  
  959. Q $061) How many does a stock Plus/4 report?
  960.  
  961. A $061) According to its initial power-up message, the Plus/4 has 60671
  962.         bytes free.
  963.  
  964. Q $062) What was the VIC-20's subtitle?
  965.  
  966. A $062) "The Friendly Computer"
  967.  
  968. Q $063) What personality announced the birth of the Commodore 64 in
  969.         Christmas advertisements?
  970.  
  971. A $063) Though not well-known outside of the US, Henry Morgan introduced the
  972.         new Commodore 64 computer system in the US.  In other countries, the
  973.         answers differ, as countries like Finland had the Statue of Liberty
  974.         announce the C64 birth.
  975.  
  976. Q $064) What was the name of the monitor program included in the Plus/4?
  977.  
  978. A $064) TEDMon.  TED, as you know, stood for Text Editing Device.
  979.  
  980. Q $065) How many sectors per track are there for tracks 1-17 on a 1541?
  981.  
  982. A $065) 21.
  983.  
  984. Q $066) There are two programs running in the Commodore single-6502 drives
  985.         (1541,1571,1541 II,1581).  What is the interpreter program called?
  986.  
  987. A $066) The interpreter program is called the Interface Processor (IP).  It
  988.         handles the dispatching of all commands sent to the drive, as well
  989.         as corrdinating the flow of traffic between the disk and the computer.
  990.  
  991. Q $067) How do you do a hard reset on a Plus/4 ?
  992.  
  993. A $067) First, we need to define hard-reset.  A reset differs from a power-
  994.     cycle, since the latter does not retain the RAM contents.  In this
  995.     case, the answer is analogous to the RUN/STOP-RESTORE combination
  996.     found on the 64 and VIC-20.  Hold down RUN/STOP and CTRL and press the
  997.     recessed reset button on the side of the computer.  I believe this
  998.      works for the C-16 as well.
  999.                     
  1000. Q $068) Where did the name "Commodore" come from?
  1001.  
  1002. A $068) Rumor has it that Jack Tramiel always wante to use a naughtical term,
  1003.         but most had been already used.  However, one day he watched a moving
  1004.         company van pass by on the street with the name he decided to use as 
  1005.         soon as he saw it: Commodore.
  1006.  
  1007. Q $069) Chuck Peddle, designer of the 6502, left Commodore twice. Where did he
  1008.         go first?
  1009.  
  1010. A $069) He went to Apple Computer.  He stayed with them briefly, but it seems
  1011.         that Apple and Chuck got along even worse than Commodore and Chuck.
  1012.  
  1013. Q $06A) Where did he eventually go when he left for good?
  1014.  
  1015. A $06A) First, he went off to start a company called Sirius, which died almost
  1016.         before it started due to a lawsuit over the name.  Then, he and some
  1017.         former Commodore designers came up with the "Victor" computer, which
  1018.         did modestly, but never took off.
  1019.  
  1020. Q $06B) What does the Kernal routine at $FFD2 do in terms of function and what
  1021.         parameters get passed and returned?
  1022.  
  1023. A $06B) The KERNAL routine at $FFD2 on all Commodore 8 bit machines outputs the
  1024.         PETSCII character code contained in the .A register to the current
  1025.         output device.  The carry flag indicates the presence of an error on
  1026.         return.
  1027.  
  1028. Q $06C) What Commodore drive has a hidden message?
  1029.  
  1030. A $06C) The 1581 has a couple such hidden messages.  In the idle loop of the 
  1031.         IP, the text says "am i lazy???...no just wanted to save a few ms...".
  1032.         Also, in the same loop, the following can be found: "this is lazy!!!".
  1033.         Lastly, the credits in the 1581 roms are: "Software david siracusa.
  1034.         hardware greg berliNZDedicatedto my wife lisA".  (Note: the N in berliN
  1035.         and the A in lisA is typical of how strings are stored in the 1581, 
  1036.         last byte has bit 7 set.  The Z after berliN appears to have been a 
  1037.         typo, but I can't say for sure.  I have a program that displays these.
  1038.         (Email me for info.)
  1039.         
  1040.         The 1571 has the ROM authors' names hidden at the beginning of the
  1041.         ROM, but I don't have a 1571 to scan for them.
  1042.  
  1043. Q $06D) What computer was the first to have a hidden message?
  1044.  
  1045. A $06D) The PET 2001. Some said the 128 has a hidden message, but it wasn't
  1046.     the first.
  1047.  
  1048. Q $06E) What was it and how did you get it to come up?
  1049.  
  1050. A $06E) By typing:
  1051.         wait 6502,x  (where x was a number between 1 and 255)
  1052.         the computer printed Microsoft! x times on the screen.
  1053.  
  1054. Q $06F) What does NTSC stand for?
  1055.  
  1056. A $06F) Truthfully, NTSC can stand for different things.  In regards to the
  1057.         television standard for the US, the expansion is National Television
  1058.         Standard Code.  However, the body that formed the standard is also 
  1059.         called NTSC: National Television System Committee.
  1060.         
  1061.  
  1062. Commodore Trivia Edition #8
  1063.  
  1064.               
  1065. Q $070) On a PET series computer, what visual power-on indication will tell
  1066.     the user whether the computer has Revision 2 or Revision 3 ROMs?
  1067.  
  1068. Q $071) The IEEE-488 interface is sometimes called the GPIB interface.  
  1069.     What does GPIB stand for?
  1070.         
  1071. Q $072) Commodore manufactured at least two hard drives with IEEE-488
  1072.     interfaces.  Can you name them?
  1073.         
  1074. Q $073) Why didn't buyers like the original PET-64?
  1075.         
  1076. Q $074) On a PET Revision 2 ROM, what was the largest single array size that
  1077.     BASIC could handle?
  1078.         
  1079. Q $075) On the stock 1541, data is transmitted one bit at a time.  How many
  1080.     bits are transferred at a time on the Commodore 1551 disk drive? 
  1081.         
  1082. Q $076) On all Commodore floppy disk drives, how fast does the disk spin?
  1083.     
  1084. Q $077) Upon first reading the Commodore 1541 Error channel after turning
  1085.     on the disk drive, what error number and text is returned?
  1086.         
  1087. Q $078) What error number and text is returned on a 1551?
  1088.         
  1089. Q $079) Commodore printers are normally assigned to device #4, but they
  1090.         can be also used as device #?
  1091.         
  1092. Q $07A) What microprocessor is used in the Commodore 1551 disk drive?
  1093.         
  1094. Q $07B) When the VIC-20 was designed, the serial port throughput was roughly
  1095.     equivalent to the throughput of the IEEE-488 bus?  Why isn't it
  1096.     very fast in production VICs?
  1097.     
  1098. Q $07C) On Commodore computers, how much RAM is set aside as a tape buffer?
  1099.         
  1100. Q $07D) On Commodore computers, most every peripheral has a device number.
  1101.     What is the device number of the screen?
  1102.                        
  1103. Q $07E) What is the device number of the keyboard?
  1104.                         
  1105. Q $07F) Commodore computers use 2's-complement notation to represent integers.
  1106.     What is the 2's-complement hex representation of the signle byte -1? 
  1107.         
  1108. Some are easy, some are hard, try your hand at:
  1109.  
  1110.       Commodore Trivia Edition #8!
  1111.                 
  1112. Jim Brain
  1113. brain@mail.msen.com
  1114. 2306 B Hartland Road
  1115. Hartland, MI  48353
  1116. (810) 737-7300 x8528
  1117.  
  1118. =============================================================================
  1119. RS232 Converter
  1120. by Walter Wickersham (shadow@connected.com)
  1121.  
  1122. [Editor's note: I'm wary of there being no voltage translation but am including
  1123. it because I _do_ think you can get away with it... However, because this
  1124. magazine is free you get what you pay for... ]
  1125.  
  1126. Here's a modem interface schematic for the C=64/128, with it, and around
  1127. $5.00, you can use almost any hayes compat. external modem.  To the best of
  1128. my knowedge, the 64 has a maximum baud rate (through the user port) of 2400,
  1129. and the 128's is 9600.
  1130.  
  1131. I DO NOT know who the original author of this is, but i re-wrote it in my
  1132. own words, hoping it will help someone. I CLAIM NO RIGHTS TO THIS ARTICLE.
  1133.  
  1134. PARTS LIST:
  1135. -------------
  1136. 7404 Hex Inverter IC ($0.99 at Radio Shack)
  1137. Wires, solder, etc.
  1138. Commodore User port connector (I used one off a old 1650)
  1139.  
  1140. Here It is:
  1141. C64/128 USER PORT          RS232 ADAPTER                RS232C
  1142.  
  1143. A & N -----------------------GROUND---------------------- 1 & 7
  1144. B & C ---------------------2-7404
  1145.                              7404-1---------------------- 3
  1146. M -------------------------3-7404
  1147.                              7404-4---------------------- 2
  1148. H-------------------------------------------------------- 8
  1149. E-------------------------------------------------------- 20
  1150. K ------------------------------------------------------- 5
  1151. L ------------------------------------------------------- 6
  1152.  
  1153. Pin #2n the user port MUST be connected to pin 14 of the 7404.
  1154. Pins A&N (ground) MUST be connected to pin 7 of the 7404.
  1155.  
  1156. For those of you who don't have a pinout of the user port, here, have one.
  1157.          (TOP)
  1158.  1-2-3-4-5-6-7-8-9-10-11-12
  1159.  --------------------------
  1160.  A-B-C-D-E-F-G-H-I-J--K--L-
  1161.         (BOTTOM)
  1162.  
  1163. THIS DOES WORK, that's why i'm modeming at 2400. :->, but i sometimes
  1164. recieve line noise, so any upgrades to this would be appreciated (i know
  1165. it's not my phone line).
  1166.  
  1167. =============================================================================
  1168. Programming the Commodore RAM Expansion Units (REUs)
  1169. by Richard Hable (Richard.Hable@jk.uni-linz.ac.at)
  1170.  
  1171. The following article, initially written for a mailing list, describes
  1172. the Commodore REUs and explanes how to program them.
  1173.  
  1174. Contents:
  1175.  
  1176.  1) External RAM Access With REUs
  1177.  2) RAM Expansion Controller (REC) Registers
  1178.  3) How To Recognize The REU
  1179.  4) Simple RAM Transfer
  1180.  5) Additional Features
  1181.  6) Transfer Speed
  1182.  7) Interrupts
  1183.  8) Executing Code In Expanded Memory
  1184.  9) Other Useful Applications Of The REU
  1185. 10) Comparision Of Bank Switching and DMA
  1186.  
  1187.  
  1188. 1) _External RAM Access With REUs_
  1189.  
  1190. The REUs provide additional RAM for the C64/128.  Three types of REUs have
  1191. been produced by Commodore.  These are the 1700, 1764 and 1750 with 128, 256
  1192. and 512 KBytes built in RAM.  However, they can be extended up to several
  1193. MBytes.
  1194.  
  1195. The external memory can not be directly addressed by the C64 with its 16 bit
  1196. address space--it has to be transferred from and to the main memory of the
  1197. C64.  For that purpose, there is a built in RAM Expansion Controller (REC)
  1198. which transfers memory between the C64 and the REU using Direct Memory Access
  1199. (DMA).  It can also be used for other purposes.
  1200.  
  1201.  
  1202. 2) _RAM Expansion Controller (REC) Registers_
  1203.  
  1204. The REC is programmed by accessing its registers.  When a REU is connected
  1205. through the expansion port, these registers appear memory mapped in the
  1206. I/O-area between $DF00 and $DF0A.  They can be read and written to like VIC-
  1207. and SID-registers.
  1208.  
  1209. $DF00: STATUS REGISTER
  1210.     Various information can be obtained (read only).
  1211.  
  1212.   Bit 7:     INTERRUPT PENDING  (1 = interrupt waiting to be served)
  1213.                unnecessary
  1214.   Bit 6:     END OF BLOCK  (1 = transfer complete)
  1215.                unnecessary
  1216.   Bit 5:     FAULT  (1 = block verify error)
  1217.                set if a difference between C64 and REU memory areas
  1218.                was found during a compare command
  1219.   Bit 4:     SIZE  (1 = 256 KB)
  1220.                seems to indicate the size of the RAM-chips;
  1221.                set on 1764 and 1750, clear on 1700.
  1222.   Bits 3..0: VERSION
  1223.                contains 0 on my REU.
  1224.  
  1225. $DF01: COMMAND REGISTER
  1226.      By writing to this register, RAM transfer or comparision can be
  1227.      executed.
  1228.  
  1229.   Bit 7:     EXECUTE  (1 = transfer per current configuration)
  1230.                must be set to execute a command
  1231.   Bit 6:     reserved  (normally 0)
  1232.   Bit 5:     LOAD  (1 = enable autoload option)
  1233.                With autoload enabled, the address and length registers (see
  1234.                below) will be unchanged after a command execution.
  1235.                Otherwise, the address registers will be counted up to the
  1236.                address of the last accessed byte of a DMA + 1
  1237.                and the length register will be changed (normally to 1).
  1238.   Bit 4:     FF00
  1239.                If this bit is set, command execution starts immediately
  1240.                after setting the command register.
  1241.                Otherwise, command execution is delayed until write access to
  1242.                memory position $FF00.
  1243.   Bits 3..2: reserved  (normally 0)
  1244.   Bits 1..0: TRANSFER TYPE
  1245.                00 = transfer C64 -> REU
  1246.                01 = transfer REU -> C64
  1247.                10 = swap C64 <-> REU
  1248.                11 = compare C64 - REU
  1249.  
  1250. $DF02..$DF03: C64 BASE ADDRESS
  1251.     16-bit C64 base address in low/high order
  1252.  
  1253. $DF04..$DF06: REU BASE ADDRESS
  1254.     This is a three byte address, consisting of a low and
  1255.     high byte and an expansion bank number.
  1256.     Normally, only bits 2..0 of the expansion bank are valid
  1257.     (for a maximum of 512 KByte), the other bits are always
  1258.     set.
  1259.  
  1260. $DF07..$DF08: TRANSFER LENGTH
  1261.     This is a 16 bit value containing the number of bytes to
  1262.     transfer or compare.
  1263.     The value 0 stands for 64 KBytes.
  1264.     If the transfer length plus the C64 base address exceeds
  1265.     64K, the C64 address will overflow and cause C64 memory
  1266.     from 0 on to be accessed.
  1267.     If the transfer length plus the REU base address exceeds
  1268.     512K, the REU address will overflow and cause REU memory
  1269.     from 0 on to be accessed.
  1270.  
  1271. $DF09: INTERRUPT MASK REGISTER
  1272.     unnecessary
  1273.  
  1274.   Bit 7:     INTERRUPT ENABLE  (1 = interrupt enabled)
  1275.   Bit 6:     END OF BLOCK MASK  (1 = interrupt on end)
  1276.   Bit 5:     VERIFY ERROR  (1 = interrupt on verify error)
  1277.   Bits 4..0: unused (normally all set)
  1278.  
  1279. $DF0A: ADDRESS CONTROL REGISTER
  1280.     With this register, address counting during DMA can be controlled.
  1281.     If a base address is fixed, the same byte is used repeatedly.
  1282.  
  1283.   Bit 7:     C64 ADDRESS CONTROL  (1 = fix C64 address)
  1284.   Bit 6:     REU ADDRESS CONTROL  (1 = fix REU address)
  1285.   Bits 5..0: unused (normally all set)
  1286.  
  1287.  
  1288. In order to access the REU registers in assembly language, it is convenient
  1289. to define labels something like this:
  1290.  
  1291.   status   = $DF00
  1292.   command  = $DF01
  1293.   c64base  = $DF02
  1294.   reubase  = $DF04
  1295.   translen = $DF07
  1296.   irqmask  = $DF09
  1297.   control  = $DF0A
  1298.  
  1299.  
  1300. 3) _How To Recognize The REU_
  1301.  
  1302. Normally, the addresses between $DF02 and $DF05 are unused, values stored
  1303. there get lost.  Therefore, if e.g. the values 1,2,3,4 are written to
  1304. $DF02..$DF05 and do not stay there, no REU can be connected.  However, if the
  1305. values are there, it could be caused by another kind of module connected that
  1306. also uses these addresses.
  1307.  
  1308. Another problem is the recognition of the number of RAM banks (64 KByte
  1309. units) installed.  The SIZE bit only tells if there are at least 2 (1700) or
  1310. 4 (1764, 1750) banks installed.  By trying to access and verify bytes in as
  1311. many RAM banks as possible, the real size can be determined.  This can be
  1312. seen in the source to "Dynamic memory allocation for the 128" in Commodore
  1313. Hacking Issue 2.
  1314.  
  1315. In any way, the user of a program should be able to choose, if and which REU
  1316. banks are to be used.
  1317.  
  1318.  
  1319. 4) _Simple RAM Transfer_
  1320.  
  1321. Very little options of the REU are necessary for the main purposes of RAM
  1322. expanding.  Just set the base addresses, transfer length, and then the
  1323. command register.
  1324.  
  1325. The following code transfers one KByte containing the screen memory
  1326. ($0400..$07FF) to address 0 in the REU:
  1327.  
  1328.   lda #0
  1329.   sta control ; to make sure both addresses are counted up
  1330.   lda #<$0400
  1331.   sta c64base
  1332.   lda #>$0400
  1333.   sta c64base + 1
  1334.   lda #0
  1335.   sta reubase
  1336.   sta reubase + 1
  1337.   sta reubase + 2
  1338.   lda #<$0400
  1339.   sta translen
  1340.   lda #>$0400
  1341.   sta translen + 1
  1342.   lda #%10010000;  c64 -> REU with immediate execution
  1343.   sta command
  1344.  
  1345. In order to transfer the memory back to the C64, replace "lda #%10010000" by
  1346. "lda #%10010001".
  1347.  
  1348. I think, this subset of 17xx functions would be enough for a reasonable RAM
  1349. expansion.  However, if full compatibility with 17xx REUs is desired, also
  1350. the more complicated functions have to be implemented.
  1351.  
  1352. 5) _Additional Features_
  1353.  
  1354. Swapping Memory
  1355.  
  1356. With the swap-command, memory between 17xx and C64 can be exchanged. The
  1357. programming is the same as in simple RAM transfer.
  1358.  
  1359.  
  1360. Comparing Memory
  1361.  
  1362. No RAM is transferred. Instead, the number of bytes specified in the transfer
  1363. length register is compared.  If there are differences, the FAULT bit of the
  1364. status register is set.  In order to get valid information, this bit has to
  1365. be cleared before comparing.  This is possible by reading the status
  1366. register.
  1367.  
  1368.  
  1369. Using All C64 Memory
  1370.  
  1371. Normally, C64 memory is accessed in the memory configuration selected during
  1372. writing to the command register.  In order to be able to write to the command
  1373. register, the I/O-area has to be active.  If RAM between $D000 and $DFFF or
  1374. character ROM shall be used, it is possible to delay the execution of the
  1375. command by using a command byte with bit 4 ("FF00") cleared.  The command
  1376. will then be executed when an arbitrary value is written to address $FF00.
  1377.  
  1378. Example:
  1379.  
  1380.   < Set base addresses and transfer length >
  1381.   lda #%10000000 ; transfer C64 RAM -> REU delayed
  1382.   sta command
  1383.   sei
  1384.   lda $01
  1385.   and #$30
  1386.   sta $01 ; switch on 64 KByte RAM
  1387.   lda $FF00 ; do not change the contents of $FF00
  1388.   sta $FF00 ; execute DMA
  1389.   lda $01
  1390.   ora #$37
  1391.   sta $01 ; switch on normal configuration
  1392.   cli
  1393.  
  1394.  
  1395. 6) _Transfer Speed_
  1396.  
  1397. During DMA the CPU is halted--the memory access cycles normally available for
  1398. the CPU are now used to access one byte each cycle. Therefore, with screen
  1399. and sprites switched off, in every clock cycle (985248 per second on PAL
  1400. machines) one byte is transferred.  If screen is on or sprites are enabled,
  1401. transfer is a bit slower, as the VIC sometimes accesses RAM exclusively. 
  1402. Comparing memory areas is as fast as transfering.  (Comparison is stopped
  1403. once the first difference is found.)  Swapping memory is only half as fast,
  1404. because two C64 memory accesses per byte (read & write) are necessary.
  1405.  
  1406.  
  1407. 7) _Interrupts_
  1408.  
  1409. By setting certain bits in the interrupt mask register, IRQs at the end of a
  1410. DMA can be selected.  However, as the CPU is halted during DMA, a transfer or
  1411. comparision will always be finished after the store instruction into the
  1412. command register or $FF00.  Therefore, there is no need to check for an "END
  1413. OF BLOCK" (bit 6 of status register) or to enable an interrupt.
  1414.  
  1415.  
  1416. 8) _Executing Code In Expanded Memory_
  1417.  
  1418. Code in expanded memory has to be copied into C64 memory before execution. 
  1419. This is a disadvantage against bank switching systems. However, bank
  1420. switching can be simulated by the SWAP command.  This is done e.g. in RAMDOS. 
  1421. There, only 256 bytes of C64 memory are occupied, the 8 KByte RAM disk driver
  1422. is swapped in whenever needed.  Too much swapping is one reason for RAMDOS to
  1423. be relatively slow at sequential file access.
  1424.  
  1425.  
  1426. 9) _Other Useful Applications Of The REU_
  1427.  
  1428. The REC is not only useful for RAM transfer and comparison.
  1429.  
  1430. One other application (used in GEOS) is copying C64 RAM areas by first
  1431. transferring them to the REU and then transferring them back into the desired
  1432. position in C64 memory.  Due to the fast DMA, this is about 5 times faster
  1433. than copying memory with machine language instructions.
  1434.  
  1435. Interesting things can be done by fixing base addresses:  By fixing the REU
  1436. base address, large C64 areas can be fast filled with a single byte value. 
  1437. It is also possible to find the end of an area containing equal bytes very
  1438. fast, e.g. for data compression.
  1439.  
  1440. Fixing the C64 base address is interesting if it points to an I/O-port. 
  1441. Then, data can be written out faster than normally possible.  It would be
  1442. possible to use real bitmap graphics in the upper and lower screen border by
  1443. changing the "magic byte" (byte with the highest address accessable by the
  1444. VIC) in every clock cycle. Therefore, of course, the vertical border would
  1445. have to be switched off.
  1446.  
  1447. Generally the REC could be used as graphics accelerator, e.g. to copy bitmap
  1448. areas or other display data fast into the VIC-addressable 16 KByte area.
  1449.  
  1450.  
  1451. 10) _Comparision Of Bank Switching and DMA_
  1452.  
  1453. When comparing bank switching and DMA for memory expansion, I think, DMA is
  1454. the more comfortable method to program. It is also faster in most cases. 
  1455. The disadvantage of code execution not possible in external memory can be
  1456. minimized by always copying only the necessary parts into C64 memory. 
  1457. Executing the code will then take much more time than copying it into C64
  1458. memory.
  1459.  
  1460. =============================================================================
  1461. A Different Perspective: Three-Dimensional Graphics on the C64
  1462. by Stephen Judd (judd@merle.acns.nwu.edu) and
  1463.    George Taylor (yurik@io.org)
  1464.  
  1465. Introduction
  1466. ------------
  1467.  
  1468. We've all seen them: neat-looking three-dimensional graphics tumbling around
  1469. on a computer.  But how is it done?  In particular, how would you do it on a
  1470. Commodore-64?  Nowadays the typical answer to the first question is "Just
  1471. use the functions in 3dgrphcs.lib" (or "Beats me.").  The answer to the
  1472. second is either "Well an elite coder like me can't let secrets like that
  1473. out" or else "What, you mean people still use those things?"
  1474.  
  1475. So this is a little article which attempts to take some of the mystery out
  1476. of three dimensional graphics.  Most of the mathematics involved are very
  1477. simple, and the geometric concepts are very intuitive. Coding it up on a
  1478. C-64 is more of a challenge, especially when you want to make it fast, but
  1479. even then it's not too tough.  George and I wrote the code in about a week
  1480. (and talked about it for about a week before that).  Perhaps you will
  1481. appreciate this aspect more if you know that I haven't written 6510 code
  1482. since 1988, and until the last two days George had no computer on which to
  1483. test his ideas (and on the last day it died)!
  1484.  
  1485. The goal of this article is that by the time you reach the end of it you
  1486. will be able to do your own cool-looking 3d graphics on a C64. Some of you
  1487. may find it patronizing at times, but I hope that it is at a level that
  1488. everyone can enjoy and learn something from.  And feel free to write to us!
  1489.  
  1490. The first part explains some of the fundamental theoretical concepts
  1491. involved.  Mostly what is required is some geometric imagination, although
  1492. you need to know a little trigonometry, as well as how to multiply two
  1493. matrices together.
  1494.  
  1495. The second part deals with implementing the algorithms on a computer; since
  1496. this is C=Hacking, it is a good assumption that the implementation is on the
  1497. C-64!  Most of the code is designed for speed, and lots of it is also
  1498. designed so that it can be called from BASIC!
  1499.  
  1500. Finally, an example program which uses all of the techniques presented here
  1501. is included, including source.  The program rotates a cube in three
  1502. dimensions.
  1503.  
  1504. By itself the code is not the fastest in the world; what is important here
  1505. are the concepts.  With a little fiddling, and maybe some loop unrolling,
  1506. you can get these routines going quite fast; for instance, a 26 cycle line
  1507. drawing routine is not hard at all using more sophisticated versions of
  1508. these algorithms.  This time around the code is designed for clarity over
  1509. quality.
  1510.  
  1511. There are lots and lots of little details that are not specifically covered
  1512. by this article.  But if you understand all of the concepts here it
  1513. shouldn't be too hard to figure out the problem when something goes wrong.
  1514.  
  1515. This material is the result of a week's worth of discussions on comp.sys.cbm
  1516. between George, myself, and several other people.  So a big thank you to
  1517. everyone who helped us to knock these ideas out, and we hope you find this
  1518. to be a useful reference!
  1519.  
  1520. Incidentally, the ideas and techniques in this article aren't just for
  1521. drawing neat pictures; for example, a good application is the stabilization
  1522. of an orbiting satellite.  The mathematical ideas behind linear
  1523. transformations are important in, for instance, the study of dynamical
  1524. systems (which leads to Chaos and all sorts of advanced mathematical
  1525. subjects).
  1526.  
  1527. But it also makes you look really cool in front of your friends.
  1528.  
  1529. First Things First
  1530. ------------------
  1531.  
  1532. Before we begin, you are going to have to get a few ideas into your head. 
  1533. First and foremost is the coordinate system we will be using: a right-handed
  1534. coordinate system.  In our system, the x-axis is going to come out towards
  1535. you, the y-axis is going to go to your right, and the z-axis is going to go
  1536. "up".
  1537.  
  1538. Second, you need to know a little math.  You need to know about polar
  1539. coordinates, and you need to know how to multiply two matrices together. 
  1540. The ideas are all geometric, but the computations are all (of course)
  1541. mathematical.
  1542.  
  1543. Now, let us start thinking about a cube!
  1544.  
  1545. Let's first center our cube at the origin.  Not only does this make it easy
  1546. to visualize, but to make our cube do things (like rotate) the way we want
  1547. it to we are going to have to require this.  A cube has eight corners, all
  1548. connected to each other in a particular way.
  1549.  
  1550. There's no reason to make things complicated already, so let's put the
  1551. corners of the cube at x=+/-1, y=+/-1, and z=+/-1.  This gives us eight
  1552. points to work with: P1=[1 1 1] P2=[1 -1 1] P3=[-1 -1 1] etc.
  1553.  
  1554. Minimalists may disagree, but a cube all by itself isn't all that exciting. 
  1555. So how do we do stuff to it?  For that matter, what kinds of stuff can we do
  1556. to it?
  1557.  
  1558. Rotations in the Plane
  1559. ----------------------
  1560.  
  1561. One of the cool things to do with a three-dimensional object is of course to
  1562. rotate it.  To understand how to do this, we need to first look at rotations
  1563. in the plane.  A little later on, this article is going to assume you know
  1564. how to multiply two matrices together.
  1565.  
  1566. Before starting, we need to know some important trig formulas (of course,
  1567. everyone knows important formulas like these, but let me just remind you of
  1568. them):
  1569.  
  1570.     cos(A+B) = cos(A)cos(B) - sin(A)sin(B)
  1571.     sin(A+B) = cos(A)sin(B) + sin(A)cos(B)
  1572.  
  1573. Let us take a look at rotations in the plane; that is, in two dimensions. 
  1574. Think of the typical x-y axis.  Let's say that we have a point at [x1 y1]
  1575. and want to rotate it by an angle B, about the origin, so that we end up at
  1576. the rotated coordinate [x2 y2].  What are x2 and y2?  The easiest way to
  1577. find them is to use polar coordinates.
  1578.  
  1579. We can write the point [x1 y1] as the point (r,t), where r is the distance
  1580. from the origin to the point, and t is the angle from the x-axis, measured
  1581. counter-clockwise.  Therefore, x1 = r*cos(t) and y1=r*sin(t). If we then
  1582. rotate this vector by an amount B,
  1583.     
  1584.     x2 = r*cos(t+B)    
  1585.        = r*(cos(t)cos(B) - sin(t)sin(B))
  1586.        = x1*cos(B) - y1*sin(B).
  1587.  
  1588. Similarly,
  1589.  
  1590.     y2 = r*sin(t+B) = x1*sin(B) + y1*cos(B).
  1591.  
  1592. In matrix form, this can be written as
  1593.  
  1594.     [x2] = [cos(B)  -sin(B)] [x1]
  1595.     [y2]   [sin(B)   cos(B)] [y1]
  1596.  
  1597. How do we extend this to three dimensions?  Easy.  The key thing to realize
  1598. here is that, in three dimensions, the above rotations are really rotations
  1599. about the z-axis.  At any point along the z-axis we could take a thin slice
  1600. of the three-dimensional space (so that our slice is parallel to the x-y
  1601. axis) and pretend that we are really in two-dimensional space.  Therefore,
  1602. to rotate a point about the z-axis the x- and y-equations are the same as
  1603. above, and the z-coordinate stays fixed.  In matrix form this is
  1604.  
  1605.     [x2]   [cos(B)  -sin(B)  0] [x1]
  1606.     [y2] = [sin(B)   cos(B)  0] [y1]
  1607.     [z2]   [  0        0     1] [z1]
  1608.  
  1609. Similarly, it is easy to see that
  1610.  
  1611.     [x2]   [  1        0        0   ] [x1]
  1612.     [y2] = [  0      cos(B)  -sin(B)] [y1]
  1613.     [z2]   [  0      sin(B)   cos(B)] [z1]
  1614.  
  1615. is a rotation about the x-axis, and that
  1616.  
  1617.     [x2]   [cos(B)     0      sin(B)] [x1]
  1618.     [y2] = [  0        1        0   ] [y1]
  1619.     [z2]   [-sin(B)    0      cos(B)] [z1]
  1620.  
  1621. is a rotation about the y-axis.  You may have noticed that the signs of
  1622. sin(B) have been reversed; this is because in our right-handed coordinate
  1623. system the z-x plane is "backwards": in the z-x plane x increases to the
  1624. left, while z increases "up".
  1625.  
  1626. You may be wondering why we write this all in matrix form.  The above matrix
  1627. equations are called linear transformations of the vector [x1 y1 z1].  There
  1628. are lots of deep mathematical concepts sitting right behind what looks to be
  1629. an easy way of writing several equations.  Entire books are written on the
  1630. subject, and that is as good a reason as any for me not to go into detail.
  1631.  
  1632. But writing things in this way also offers us several _computational_
  1633. advantages.  Rotations aren't the only linear transformations; let's say
  1634. that I want to rotate a point about the x-axis, shear it in the y-direction,
  1635. reflect it through the line theta=pi/5, and rotate it through the z-axis. 
  1636. You could have one subroutine which did the rotation, and one that did the
  1637. shear, etc.  But by writing it in matrix form, the entire process is simply
  1638. a series of matrix multiplications.
  1639.  
  1640. If you think about it you might realize that it really is the same thing no
  1641. matter which way you do it, but there is a fundamental difference in the
  1642. viewpoint of each method: one views it as a series of unrelated mathematical
  1643. operations each with it's own individual function, while the other method
  1644. views it as a series of matrix multiplications so that it's basically the
  1645. same thing, over and over.
  1646.  
  1647. What this means for you is that if you want to rotate a point around the
  1648. x-axis, the y-axis, and the z-axis, you can take the matrix for each
  1649. transformation and multiply them all together, and then apply this one big
  1650. matrix to the point.  One thing to be very aware of: in general, matrix
  1651. multiplication is not commutative.  That is, if X is a rotation matrix about
  1652. the x-axis and Y is a rotation about the y-axis, it will almost never be
  1653. true that XY = YX.  What this means geometrically is that if you take a
  1654. point, rotate it around the x-axis by an amount A, then rotate it around the
  1655. y-axis by an amount B, you will usually end up at a different point than if
  1656. you first rotate it around the y-axis.
  1657.  
  1658. If you are interested in learning more about rotations and their uses, a
  1659. good place to start is almost any book on mechanics, for instance "Classical
  1660. Mechanics" by Goldstein.  If you want to learn more about linear
  1661. transformations you can find it in any decent book on linear algebra, as
  1662. well as in a lot of physics texts.  There is a good introduction in Margenau
  1663. and Murphy "The Mathematics of Physics and Chemistry", and there is a
  1664. semi-OK book on linear algebra by Goldberg.
  1665.  
  1666. Now we know the geometric and mathematical principles behind rotations in
  1667. three dimensions.  But we want to visualize this on a computer, on a
  1668. two-dimensional screen: we need some way of taking a point in
  1669. three-dimensions and bringing it down to two dimensions, but in a way that
  1670. fools us into thinking that it really is three-dimensional.
  1671.  
  1672. What we need are projections.
  1673.  
  1674. Projections
  1675. -----------
  1676.  
  1677. Now, we could just do a simple projection and set the z-coordinate equal to
  1678. zero, but in doing so we have eliminated some of the information, and it
  1679. won't look very three-dimensional to our eyes.  So we need to think of a
  1680. better method.
  1681.  
  1682. Sit back in your chair and imagine for a minute or two.  Imagine the three
  1683. coordinate axes.  Now imagine that there is a pinhole camera, with  it's
  1684. pinhole lens at the origin, and it's film at the plane at z=1 parallel to
  1685. the x-y plane.  Now we are going to take a snapshot of something.
  1686.  
  1687. Maybe a little picture would help:                       
  1688.  
  1689.                   |
  1690.                   |
  1691.                  /|
  1692.            lens / |film
  1693.           -----*--|------------ z-axis
  1694.               /   |
  1695.              /    |
  1696.             /    z=1
  1697.    object :-)                (then again, maybe it won't!)
  1698.  
  1699.     What does this object look like on the film?
  1700.  
  1701. Let's say one of the points of this something is [x y z].  Where does this
  1702. point come out on the film?  Since the lens is at the origin, we want to
  1703. draw the line from [x y z] through the origin (since that's where our lens
  1704. is) and find the point [x1 y1 1] where it hits the film.  The parametric
  1705. equation of this line is
  1706.  
  1707.         t * [x y z]
  1708.  
  1709. so that we want to find the intersection of this line and the film:
  1710.  
  1711.         t * [x y z] = [x1 y1 1].
  1712.  
  1713. The z-coordinate tells us that t*z=1, or t=1/z.  If we then substitute this
  1714. in the above equation, we find that
  1715.  
  1716.         x1 = x/z    y1 = y/z
  1717.  
  1718. If, instead of placing the film at z=1 we place it at z=d, we get
  1719.  
  1720.         x1 = d*x/z    y1 = d*y/z
  1721.  
  1722. These then are the projection equations.  Geometrically you can see that by
  1723. changing d all you will do is to "magnify" the object on the film. Anyone
  1724. who has watched an eclipse with a little pinhole camera has seen this.
  1725.  
  1726. By the way, if you stare at the above picture for a while, you may realize
  1727. that, in that geometric model, the object gets turned upside-down on the
  1728. film.
  1729.  
  1730. Now that we have a physical model of the equations that have been thrown
  1731. around, let's look at what we've been doing.
  1732.  
  1733. Consider a cube centered at the origin.  Already there is a problem above if
  1734. z=0.  What if one side of the cube has part of it's face below the x-y plane
  1735. (negative z) and part above the x-y plane?  If you draw another picture and
  1736. trace rays through the origin, you'll see one part of the face at one end of
  1737. the film (negative z, say), and the other part way the heck out at the other
  1738. end!  And the two parts don't touch, either!
  1739.  
  1740. So we need to be careful.  In the geometric picture above, we assumed the
  1741. object was a fair distance away from the lens.  Currently we have our lens
  1742. at the center of our cube, so something needs to move! Since rotations are
  1743. defined about the origin we can't just redefine the cube so that the
  1744. vertices are out at, say, z=2 and z=3.  So what we need to do is to move the
  1745. camera away from the cube.  Or, if you want to think of it another way, we
  1746. need to move the cube away from the camera before we take a picture of it.
  1747.  
  1748. In this case the translation needs to be done in the z-direction. The new
  1749. projection equations are then
  1750.  
  1751.         x1 = d*x/(z-z0)    y1 = d*y/(z-z0)
  1752.  
  1753. Where z0 is a translation amount that at the very least makes sure that
  1754. z-z0 < 0.
  1755.  
  1756. Now not only have we eliminated possible problems with dividing by zero, but
  1757. the mathematics now match the physical model.
  1758.  
  1759. Some of you might want to think about the less-physical situation of putting
  1760. the object _behind_ the film, i.e. to the right of the film in the above
  1761. picture.
  1762.  
  1763. As usual, there are some deeper mathematics lurking behind these equations,
  1764. called projective geometry.  Walter Taylor has written a book with a fine
  1765. introduction to the subject (at least, I think the book was published; my
  1766. copy is an old preprint).
  1767.  
  1768. Implementation
  1769. --------------
  1770.  
  1771. Now that we've got the theory under our belt, we need to think about
  1772. implementing it on the computer.  As a concession to all the programmers who
  1773. immediately skipped to this section, most of the discussion will be at a
  1774. reasonably high level.
  1775.  
  1776. One thing you need to understand is 8-bit signed and unsigned numbers.  Here
  1777. is a quick review: an 8-bit unsigned number ranges from 0..255.  An 8-bit
  1778. signed number ranges from -128..127 and is written in two's-complement form. 
  1779. In an 8-bit two's-complement number bits zero through six work like they
  1780. usually do, but the seventh (high) bit represents the sign of the number in
  1781. a special way.  To find the 8-bit two's-complement of a number subtract it
  1782. from 256.  Example: what is -21 in two's complement notation?  It is 256-21
  1783. = 235 = $EB.  What is the complement of -21?  It is 256-235 = 21 -- like
  1784. magic.  Another way to think about it is like a tape counter: 2 is $02, 1 is
  1785. $01, 0 is $00, -1 is $FF, -2 is $FE, etc.  And what is 24-21 in two's
  1786. complement? It is: 24 + -21 = $EE + $EB = $0103.  Throw away the carry
  1787. (subtract 256) and we come out with... $03!
  1788.  
  1789. Onwards!
  1790.  
  1791. First, we need to decide what language to use.  You and I both know the
  1792. answer here: BASIC!  Or maybe not.  We need speed here, and speed on a
  1793. Commodore 64 is spelled a-s-s-e-m-b-l-y.
  1794.  
  1795. Next, we need to decide what kind of math we want to use, signed or
  1796. unsigned.  Since the cosines and sines are going to generate negative and
  1797. positive numbers in funny ways, we definitely want to use signed numbers. 
  1798. The alternative is to have lots of code and overhead to handle all the
  1799. cases, and if we put it in two's-complement form the computer does most of
  1800. the work for us.
  1801.  
  1802. How big should the numbers be?  Since we are going for speed here, the
  1803. obvious choice is 8-bits.  But this restricts us to numbers between
  1804. -128..127, is that OK?  The size of our grid is 0..127 x 0..127, so this is
  1805. perfect!  But it does mean that we need to be very careful. For instance,
  1806. consider the expression (a+b)/2.  What happens if a=b=64? These are two
  1807. numbers within our range of numbers, and the expression evaluates to 64,
  1808. which is also in our range, BUT: if you evaluate the above in two's
  1809. complement form, you will find different answers depending on how you
  1810. evaluate it (i.e. (a+b)/2 will not give the same answer as a/2 + b/2, which
  1811. will give the correct answer).
  1812.  
  1813. Now we've got another problem: sine and cosine range between negative one
  1814. and one.  To represent these floating point numbers as 8-bit signed integers
  1815. the idea will be to multiply all floating point numbers by a fixed amount. 
  1816. That is, instead of dealing with the number 0.2, we use the number 64*0.2 =
  1817. 12.8 = 13, and divide the end result by 64.  As usual, we are trading
  1818. accuracy for speed, although it will turn out to make little difference
  1819. here.
  1820.  
  1821. Why did I pick 64?  Obviously we want to pick some factor of two to make the
  1822. division at the end simple (just an LSR).  128 is too big.  32 doesn't give
  1823. us much accuracy.  We also have to consider problems in expression
  1824. evaluation (see the above example of (a+b)/2), but as we shall see 64 will
  1825. work out nicely.
  1826.  
  1827. Now that we have accomplished the difficult task of decision making, we now
  1828. need to move on to the simple task of implementation, starting with
  1829. rotations.
  1830.  
  1831. Implementation: Rotations
  1832. -------------------------
  1833.  
  1834. We've got some more heavy-duty decision making ahead of us. We could
  1835. implement this is several ways.  We could apply each rotation individually,
  1836. that is, we could rotate around the z-axis, then use these rotated points
  1837. and rotate them around the y-axis, etc.
  1838.  
  1839. Well, yes, that would work, but... each rotation is nine multiplications. 
  1840. Each multiplication involves a lot of work, plus we have to shift the result
  1841. by our fixed amount each time.  We would not only be using huge amounts of
  1842. time, but we would lose a lot of accuracy in the process.  Computationally
  1843. speaking, this is called a "bad idea".
  1844.  
  1845. Once again, mathematics saves the day: here is where we get the payoff for
  1846. writing the equations as an algebraic system (a matrix).  If X is the
  1847. transformation around the x-axis, Y the transformation around the y-axis,
  1848. and Z the transformation around the z-axis, then this is the equation to
  1849. transform a vector v by rotating the point first around the z-axis, then the
  1850. y-axis, then the x-axis:
  1851.  
  1852.     XYZv = v'
  1853.  
  1854. where v' is the new point after all the rotation transformations. (You might
  1855. call it a conflagration of rotation transformations). Now the magic of
  1856. linear algebra begins to work: operations are associative, which is a fancy
  1857. way of saying that (AB)C = A(BC); For us this means that I can multiply all
  1858. three matrices X Y and Z together to get a single new matrix M:
  1859.  
  1860.     M = XYZ
  1861.     Mv= v'
  1862.  
  1863. "But," you may say, "we have to do the same number of multiplications to get
  1864. M as we do to apply each rotation separately!  How is this supposed to
  1865. help?"  This is how it is supposed to help:
  1866.  
  1867.     1) We now have a single matrix which describes ALL the rotations.
  1868.        For a single point we haven't gained much, but if we have
  1869.        a lot of points (and a cube has eight), transforming every
  1870.        point is now a single matrix multiplication.  In other words,
  1871.        if we have a lot of points to transform we get a HUGE savings
  1872.        computationally.
  1873.  
  1874.     2) We can take advantage of trigonometric identities and in so
  1875.        doing make the computation of M very simple.
  1876.  
  1877. Computationally speaking, this is known as a "good idea".
  1878.  
  1879. To multiply the three rotation matrices together, we need to take advantage
  1880. of a few trigonometric properties.  We need the two identites mentioned
  1881. earlier:
  1882.  
  1883.     sin(a+b) = sin(a)cos(b) + cos(a)sin(b)
  1884.     cos(a+b) = cos(a)cos(b) - sin(a)sin(b)
  1885.  
  1886. We will also use the fact that cosine is even and sine is odd, that is
  1887.  
  1888.     cos(-a) = cos(a)
  1889.     sin(-a) = -sin(a)
  1890.  
  1891. Using the above identities it is easy to see that
  1892.  
  1893.     sin(a)sin(b) = (cos(a-b) - cos(a+b))/2
  1894.     cos(a)cos(b) = (cos(a+b) + cos(a-b))/2
  1895.     sin(a)cos(b) = (sin(a+b) + sin(a-b))/2
  1896.  
  1897. We are going to rotate first around the z-axis by an amount sz, then the
  1898. y-axis by an amount sy, then the x-axis by an amount sx.  Why rotate in that
  1899. order?  Why not.
  1900.  
  1901.     M = XYZ
  1902.  
  1903. If you multiply everything out (and I encourage you to do so, not only for
  1904. practice, but also as a double-check of my work), and use the above trig
  1905. identities, the result is:
  1906.  
  1907.         [A B C]
  1908.     M = [D E F]
  1909.         [G H I]
  1910.  
  1911. Where
  1912.     A = (cos(t1)+cos(t2))/2
  1913.     B = (sin(t1)-sin(t2))/2
  1914.     C = sin(sy)
  1915.     D = (sin(t3)-sin(t4))/2 + (cos(t6)-cos(t5)+cos(t8)-cos(t7))/4
  1916.     E = (cos(t3)+cos(t4))/2 + (sin(t5)-sin(t6)-sin(t7)-sin(t8))/4
  1917.     F = (sin(t9)-sin(t10))/2
  1918.     G = (cos(t4)-cos(t3))/2 + (sin(t6)-sin(t5)-sin(t8)-sin(t7))/4
  1919.     H = (sin(t3)+sin(t4))/2 + (cos(t6)-cos(t5)+cos(t7)-cos(t8))/4
  1920.     I = (cos(t9)+cos(t10))/2
  1921.  
  1922. with
  1923.     t1 = sy-sz
  1924.     t2 = sy+sz
  1925.     t3 = sx+sz
  1926.     t4 = sx-sz
  1927.     t5 = sx+sy+sz = sx+t2
  1928.     t6 = sx-sy+sz = sx-t1
  1929.     t7 = sx+sy-sz = sx+t1
  1930.     t8 = sy+sz-sx = t2-sx
  1931.     t9 = sy-sx
  1932.     t10= sy+sx
  1933.  
  1934. How is this supposed to be the "simplified" version?  If you look closely,
  1935. there are no multiplies.  We can calculate the entire rotation matrix M in
  1936. about the same time as it would take to do two multiplications. This also
  1937. means that the associated problem with multiplications, loss of accuracy, is
  1938. now gone.
  1939.  
  1940. Here is also where we need to be extremely careful.  The first entry in the
  1941. matrix M is the example I gave earlier about evaluating signed numbers.  How
  1942. do we overcome this?
  1943.  
  1944. Easy!  Notice in the matrix M that, apart from element C, every term is a
  1945. sine or a cosine divided by two.  This is the only part of the program which
  1946. uses sines and cosines, so why not use the offset floating-point values
  1947. divided by two?  This will make more sense in a minute.
  1948.  
  1949. The question arises: the above is all well and good, but how do we take the
  1950. sine of a number and make it fast?  The answer of course is to use a table. 
  1951. We used a BASIC routine to calculate the table for us (and to store the
  1952. numbers in two's-complement form).  Calculate the sine and cosine of every
  1953. angle you want ahead of time, and then just look up the number.
  1954.  
  1955. The tables contain the values of sine and cosine multiplied by 64 (our
  1956. floating-point offset) and then divided by 2.  Since the value is already
  1957. divided by two, the above calculation becomes at the same time faster and
  1958. safer: faster because I don't have to keep dividing by two, and safer
  1959. because I don't have to worry so much about overflow.  (It can still happen,
  1960. but it won't if you're careful).
  1961.  
  1962. Here is an example of how to calculate elements A and B above:
  1963.  
  1964.     LDA sy
  1965.     SEC
  1966.     SBC sz
  1967.     ...
  1968.     STA t1        ;t1=sy-sz
  1969.     LDA sy
  1970.     CLC
  1971.     ADC sz
  1972.     ...
  1973.     STA t2        ;t2=sy+sz
  1974.     ...
  1975.     LDX t1
  1976.     LDA COS,t1    ;COS is a table of cosines*offset/2
  1977.     LDX t2
  1978.     CLC
  1979.     ADC COS,t2
  1980.     STA A        ;A=(cos(t1)+cos(t2))/2
  1981.     LDX t1
  1982.     LDA SIN,t1
  1983.     LDX t2
  1984.     SEC
  1985.     SBC SIN,t2
  1986.     STA B        ;B=(sin(t1)-sin(t2))/2
  1987.     ...        ;Result is offset by a certain amount
  1988.  
  1989. Note that the elements D E G and H involve a division by four, which means
  1990. that the code does need to perform a division by two during the calculation
  1991. of those elements.
  1992.  
  1993. That's all there is to calculating the rotation matrix.  Next we have to
  1994. actually rotate the points.  We have another decision to make: do we take
  1995. the rotated object and rotate it by a little amount, or do we take the
  1996. original object and rotate it by a big amount?  Because of the way we have
  1997. set things up, the answer is clear: we want to increment the angle at each
  1998. step, and rotate the original object by this large angle (besides,
  1999. geometrically you can see that it will look much nicer this way).
  2000.  
  2001.     For a cube this is easy.  The points are P1=[1 1 1] P2=[1 -1 1]
  2002. P3=[-1 -1 1] P4=[-1 1 1] P5=[1 1 -1] P6=[1 -1 -1] P7=[-1 -1 -1] P8=[-1 1 -1].
  2003. This means that the rotations are just a series of additions and/or
  2004. subtractions of A,B,C,...,I!  The code implements this in a funny way,
  2005. partly to make these procedures easy to see, but mostly to make debugging
  2006. the code much easier.  It is much faster to do each rotation separately,
  2007. i.e.
  2008.  
  2009. :P1    LDA A
  2010.     ADC B
  2011.     ADC C
  2012.     STA P1.X
  2013.     ...
  2014.  
  2015. :P2    LDA A
  2016.     SBC B
  2017.     ADC C
  2018.     STA P2.X
  2019.     ...
  2020. :P3    LDA C
  2021.     SBC A
  2022.     SBC B
  2023.     STA P3.X
  2024.  
  2025. You get the idea.  Of course, the code needs to remember that it is dealing
  2026. with signed numbers, and to watch carry flags carefully (something the above
  2027. fragment does not do).
  2028.  
  2029. Still worried about overflow?  If you think about it geometrically, you will
  2030. see that the maximum value any part of a rotated coordinate can have is
  2031. sqrt(3).  Since we have offset our numbers by 64, this means that, for
  2032. instance, the maximum possible value for A+B+C is 64*sqrt(3) which is about
  2033. 111 -- in range of a signed 8-bit number with a little cushion for
  2034. additions.  In other words, we ought to be safe from overflow.
  2035.  
  2036. So far we have managed to rotate all the coordinates -- a complicated series
  2037. of matrix operations involving trigonometric functions -- by just using a
  2038. bunch of additions and a bunch of table lookups!  Not too bad! Now we just
  2039. need to project the point.
  2040.  
  2041. Implementation: Projections
  2042. ---------------------------
  2043.  
  2044. Recall that the projection equation is
  2045.             
  2046.             x' = d*x/(z-z0)
  2047.             y' = d*y/(z-z0)
  2048.  
  2049. It looks as if we have gone from a bunch of sneaky additions to 
  2050. multiplications and divisions!  Yuck.
  2051.  
  2052. Well, wait a minute, maybe we can do something.  How about using a table for
  2053. 1/(z-z0), and then just use a multiply?  Oh yeah, that's a really small
  2054. number.  As long as we're using a table, why not incorporate the d into it? 
  2055. Come to think of it, if the number weren't multiplied by the offset 64 it
  2056. would be a pretty reasonable number!
  2057.  
  2058. So, what we want to do is to construct a table of numbers such that when the
  2059. program calls
  2060.     
  2061.     LDX z
  2062.     LDA table,z
  2063.  
  2064. it gets the absolute (i.e. non-offset) value A=d/(z-z0).  What if we want to
  2065. change d?  You could put a little piece of code into your program which
  2066. multiplies by a number less than one, and let d represent the maximum value
  2067. for d which makes the code work.  But for the moment we won't bother with
  2068. that -- one thing at a time!
  2069.  
  2070. Since z is a signed number, we ought to add 128 to it to convert it into an
  2071. index.  Does this have any meaning in two's-complement arithmetic?  Yup.  We
  2072. also need to remember that floats are offset by 64, and that the highest
  2073. value a signed number can have is 127.
  2074.  
  2075. Here is how the table is generated:
  2076.  
  2077.     10 bz=whatever
  2078.     20 d=45:z0=3:z=-128:dz=1
  2079.     30 for i=0 to 255
  2080.     40 q%=64*d/(64*z0-z):if q%>127 then q%=127
  2081.     50 poke bz+i,q%:z=z+dz
  2082.     60 next
  2083.  
  2084. Note that the offset chosen forces q% to always be positive.  This fact can
  2085. be made use of in the multiplication routine (but isn't in the source code).
  2086.  
  2087. You may have noticed that z0-z is used, and not z-z0 like in the projection
  2088. equation.  If you put on your geometric thinking cap for a moment, you will
  2089. realize that the way the projection equations were set up causes the image
  2090. to become inverted.  To uninvert it, we need to multiply by negative one. 
  2091. So we just add that step into the table.
  2092.  
  2093. But we still need to do a multiplication!
  2094.  
  2095. Fast Signed 8-bit Multiply
  2096. --------------------------
  2097.  
  2098. A binary number looks like the following:
  2099.  
  2100.     P = 1*128 + 0*64 + 0*32 + 1*16 + 1*8 + 0*4 + 0*2 + 0*1
  2101.  
  2102. Therefore, if we want to multiply P by another number, 13 say, we find that
  2103.     
  2104.     13*P = 13*128 + 0*64 + 0*32 + 13*16 + ...
  2105.  
  2106. that is to say, if there is a one in bit position N, then the new number
  2107. will have 13*2^N in it.  So, to multiply two numbers we find out what bit
  2108. positions are high, and then add the other number*2^N to the result. This
  2109. doesn't seem too fast.  Here is a trick: we can write 2^N as 256/2^(8-N). 
  2110.  
  2111. So, let's say we want to multiply the number P by the number R.  If P has a
  2112. high bit in position N, we can start out with 256*R, and bit-shift it to the
  2113. right 8-N times.  Why in the world would we do this? Because we can
  2114. _pipeline_ the process in a way somewhat similar to the way a Cray
  2115. supercomputer multiplies two vectors together -- yes, I'm comparing your
  2116. C-64 to a Cray!  Watch:
  2117.  
  2118. *
  2119. * 8-bit multiply -> 16-bit result
  2120. *
  2121. * ACC*AUX -> [AUX,EXT]  lo,hi
  2122.  
  2123. MULT    LDA #$00
  2124.         LDY #$09
  2125. ]LOOP    LSR
  2126.     ROR ACC
  2127.     BCC MULT2
  2128.     CLC
  2129.     ADC AUX
  2130. MULT2    DEY
  2131.     BNE ]LOOP
  2132.     STA EXT
  2133.  
  2134. Pretty slick.  Now we need to modify it for signed numbers.  All we need to
  2135. do is check to see if the result is positive or negative. If it's positive,
  2136. we check one number (they are either both positive or both negative), and if
  2137. it's negative we fix them both to be positive, and use the above process. 
  2138. If the result is going to be negative, we need to find the negative number,
  2139. make it positive, multiply the two numbers together, and make the final
  2140. result negative (take the two's-complement of the result).
  2141.  
  2142. See the source code for an implementation of this.
  2143.  
  2144. Note that we could do a divide in a similar fashion, except shifting left
  2145. instead of right.  Since we don't need a divide routine for our calculations
  2146. we don't need to worry about this.
  2147.  
  2148. Now we have all the tools we need to implement the mathematics. There is
  2149. still one part of the program left: drawing the thing!
  2150.  
  2151. Drawing a line
  2152. --------------
  2153.  
  2154. The geometric idea is: given an initial point [x1 y1], we want to draw a
  2155. line to the point [x2 y2]!  Now we want to do this on a computer by taking
  2156. one step at a time, from point to point.  The idea is to make it fast, and
  2157. since we're on a C64 there aren't any MUL or DIV instructions.
  2158.  
  2159. To do this, we first need to find out which is larger:
  2160.  
  2161.     dx = |x2-x1|
  2162.     dy = |y2-y1|
  2163.  
  2164. where | | denotes absolute value.  Let's assume that it is dx, and that the
  2165. variable x is going to run from x1 to x2.  Therefore, we want to increase x
  2166. by one at each step, and we want to increase y by some fractional amount (If
  2167. dy were larger we would want to take big steps in the y-direction). But we
  2168. don't want to calculate this fractional number.  We do, however, want to
  2169. take a certain amount of steps in the x-direction before taking a step in
  2170. the y-direction.
  2171.  
  2172. If we take k steps in x before taking a step in y, then we want to chose k
  2173. such that
  2174.  
  2175.     dx/k = dy
  2176.  
  2177. which gives
  2178.  
  2179.     k = dx/dy
  2180.  
  2181. where dx and dy are as above, the total number of steps to be taken in the
  2182. x- and y-directions respectively.  What is dx/dy?  We don't care.  Instead,
  2183. every time we step in x, we need to increase a counter by the amount dy. As
  2184. soon as this counter is larger than dx, we have successfully divided dy into
  2185. dx, and so simply reset the counter (in a special way, so that we keep any
  2186. remainder from the division) and take a step in y.
  2187.  
  2188. Of course, if dy were larger than dx, the idea would be the same, but now k
  2189. = dy/dx.  k is never smaller than one.
  2190.  
  2191. In the code fragment which follows it is assumed that x2>x1,  y2>y1, and
  2192. dx>dy.  Obviously, then, any self-respecting line drawing routine needs to
  2193. handle all of these cases.  One way is to have eight different routines, one
  2194. for each case.  Another way (the way used by the program), is to force
  2195. x2>x1, so that there are only four cases to deal with.  For the plotting
  2196. routine which we use, this turns out to be necessary.  If you think about
  2197. it, you can come up with some more clever ways to deal with this.
  2198.  
  2199. Note that you also need to figure out what column the first point is in:
  2200. this algorithm knows how to walk forwards, but it doesn't know where it
  2201. should start.
  2202.  
  2203. The code is next to some similar BASIC7.0 code to make it easier to
  2204. understand.
  2205.  
  2206. The code can be sped up in a lot of ways.  For one thing it could be made
  2207. self-modifying.  All variables could be stored in zero page. In fact, the
  2208. entire routine could be stored in zero page!  Also, with a little change in
  2209. the logic (and a subsequent change in the plotting routine) you can
  2210. eliminate the branching instruction.  For the sake of clarity we don't do
  2211. that here; maybe in another paper ;-).
  2212.  
  2213. Also note that the largest value x can take on in this routine is 255.  For
  2214. the way we are going to plot things, this won't matter. But a more general
  2215. routine needs a way to overcome this.  One way would be to draw two separate
  2216. lines.
  2217.  
  2218. 10 REM All of the above comments ;-)
  2219. 20 REM Input x1,x2,y1,y2
  2220. 30 GRAPHIC1,1:DRAW1,x1,y1:DRAW1,x2,y2
  2221. 31 :REM above is a double-check        ;Drawin' a line
  2222. 39 REM Set up variables            ;v1.3 SLJ 7/2/94
  2223. 40 DX = X2-X1                LDA    $(X2)    ;X2 in zero page
  2224.                     SBC    $(X1)
  2225.                     STA    DX    ;For speed, store
  2226. 50 DY = Y2-Y1                LDA    $(Y2)   ;directly into code
  2227.                     SBC    $(Y1)   ;below
  2228.                     STY    DY
  2229. 60 X=X1:Y=Y1                LDX    $(X1)    ;Plotting coordinates
  2230.                     LDY    $(Y1)    ;in X and Y
  2231. 64 REM A counts steps in x
  2232. 65 REM Below you might want to
  2233. 66 REM change to A=1 or A=DY
  2234. 67 REM Otherwise the line always
  2235. 68 REM takes only one step in y
  2236. 69 REM before the last point (x=x2-1)
  2237. 70 A=256-DX:REM A=0            LDA    #00    ;Saves us a CMP
  2238.                     SEC
  2239.                     SBC     DX
  2240. 80 DRAW1,X,Y                PPLOT        ;Mystery plotter
  2241. 90 REM Main routine                     CLC
  2242. 100 X=X+1                          LOOP INX        ;Step in x
  2243. 110 A=A+DY                    ADC    DY    ;Add DY
  2244. 120 IF A>=256 THEN Y=Y+1:A=A-DX         BCC     NOPE    ;Time to step in y?
  2245. 121 REM IF A>=DX THEN...        INY        ;Step in y
  2246.                     SBC    DX    ;Reset counter
  2247. 130 DRAW1,X,Y               NOPE PPLOT        ;Plot the point
  2248. 140 IF X<>X2 THEN GOTO 100            CPX    X2    ;At the endpoint yet?
  2249.                     BNE    LOOP
  2250. 150 PRINT"All done!":REM Yay!
  2251.  
  2252.                     Cycle count:
  2253.                           LOOP: 2 3 2 2 3 3 3 = 18
  2254.                             (worst case)
  2255.                           + dx PPLOTs (one for each point)
  2256.  
  2257. The point here is that it's fast.  If you use self-modifying code, you can
  2258. get this down to 15 cycles per point.  If you are clever, you can get it
  2259. down to 13 cycles per point, excluding plot, worst case. Not too bad!  We
  2260. won't be clever right now, but maybe you'll get to see it later...
  2261.  
  2262. Note also that this could easily be used in a BASIC program; even a BASIC2.0
  2263. program.  (If you would like the DATA statements to do this just drop us a
  2264. line, er... contact us).
  2265.  
  2266. Now, this routine works fine, but for drawing a line on a computer it
  2267. doesn't always look great.  For instance, what happens if we draw a point
  2268. from 1,1 to 11,3?  k=dx/dy=5, so se will take five steps in x and then a
  2269. step in y, then five more steps and... a step in y at the very last point! 
  2270. So our line doesn't look so good -- we have a little square edge at the
  2271. endpoint.
  2272.  
  2273. One way to fix this is to trick the computer into thinking it needs to take
  2274. an extra step in y by letting k=dx/(dy+1), and being careful in keeping
  2275. track of our counter.  The big problem with this method is that it produces
  2276. the square end-pixels when dx and dy are nearly the same (slope ~= 1).
  2277.  
  2278. A better way to fix this is to initialize the counter not to 0 (in our case,
  2279. 256-dx), but instead to DX/2 (256-DX/2 in our case). This has the effect of
  2280. splitting one of the line segments between the two endpoints, and looks good
  2281. for all slopes.  This is what the program does.  In fact, as far as I can
  2282. tell, this is what BASIC7.0 does too!
  2283.  
  2284. There is still a part of our routine missing, however...
  2285.  
  2286. Plotting a point
  2287. ----------------
  2288.  
  2289. In the line routine presented earlier, the nebulous statement PPLOT was
  2290. written.  Now we come to plotting a point in all its gory detail.
  2291.  
  2292. For this project, speed is the name of the game, and for speed we don't want
  2293. to use normal bitmapped graphics.  Instead, we want to use character
  2294. graphics.  The advantages of using a custom character set are:
  2295.  
  2296.     - Less memory
  2297.     - Speed of plotting
  2298.     - Double buffering
  2299.     - Convenient organization
  2300.  
  2301. The first advantage, less memory, should be clear.  A custom character set
  2302. takes up 2k.  A bitmap, on the other hand, takes up 8k.
  2303.  
  2304. For the second advantage, it is much faster to poke a character into screen
  2305. memory than it is to calculate and plot all 64 bits in a character.  This
  2306. way, VIC does all the hard work for us.  Also, if we are clever, we can
  2307. exploit several aspects of our cleverness to make plotting a single point
  2308. much easier.
  2309.  
  2310. Character graphics also give us a very simple means of double buffering: we
  2311. can just plot into two different character sets and tell VIC-II to move
  2312. between them.  No raster interrupts here!  If the two character sets were at
  2313. $3000 and $3800, here is how to switch between them:
  2314.  
  2315.     LDA VMCSB    ;VMCSB=$D018
  2316.     EOR #%00000010    ;Flip the bit
  2317.     STA VMCSB
  2318.  
  2319. True, clearing the buffer each time is a bit slow, but for our purposes it
  2320. will do just fine.
  2321.  
  2322. The last is less obvious.  A normal hires bitmap is organized like the
  2323. following:
  2324.  
  2325.     00  08 ...
  2326.     01  09
  2327.     02  0A
  2328.     ... ...
  2329.     07  0F
  2330.  
  2331. where the number represents the offset of the byte.  This is fine for some
  2332. things, but calculating the position of a pixel is tricky.  With a character
  2333. map, we can represent our data any way we want.  In particular, we can
  2334. organize our bitmap to look like the following:
  2335.  
  2336.     00  80    ...
  2337.     01  81
  2338.     02  82
  2339.     ... ...
  2340.     7D  FD
  2341.     7E  FE
  2342.     7F  FF    ...
  2343.  
  2344. Or, in graphic form
  2345.  
  2346.     @P... etc.
  2347.     AQ
  2348.     BR
  2349.     CS 
  2350.     ..
  2351.     O<-  (the back-arrow)
  2352.  
  2353. What we have done is, instead of putting characters side-by-side like a
  2354. hires bitmap does, we put them on top of each other.  The above represents a
  2355. 16x16 character array, which is a 128x128 pixel array. Now the y-coordinate
  2356. is a direct index into the row we are in.  That is, base+Y = memory location
  2357. of point.
  2358.  
  2359. This brings us to the primary disadvantage of using a character set: our
  2360. pictures are pretty small.  TANSSAAFL.
  2361.  
  2362. Now we could just go merrily plotting into our character bitmap, but as
  2363. usual a little thought can yield some impressive return.  The first thing to
  2364. notice is that the maximum value for y is 127; the only thing that sets the
  2365. high bit is the x-coordinate, and then only when it crosses a column (just
  2366. look at the above memory map if you don't see it).
  2367.  
  2368. Therefore, if we could keep track of the bit position of x, we could tell
  2369. when x crossed a column, and just add 128 to the base address.  Not only
  2370. that, but we also know to increase the high byte of the pointer by one when
  2371. we have crossed two columns.
  2372.  
  2373. The logic is as follows:
  2374.     - Find the bit pattern for a given x (for speed, use a table)
  2375.     - If it is 10000000 then we have jumped a column
  2376.     - If the column we are in doesn't have the high bit set
  2377.       in the low byte of the pointer to the base of the column,
  2378.       then set the high bit (add 128)
  2379.     - Otherwise, set the high bit to zero (add 128), and increase
  2380.       the high byte of the column pointer (step into the next page).
  2381.  
  2382. Here is (more or less) the code:
  2383.  
  2384. In BASIC:
  2385.     2000 rem bp(x) contains bit position for x
  2386.     2010 if int(x/8) = x/8 then base=base+128
  2387.     2020 poke base+y, (peek(base+y) or bp(x))
  2388.  
  2389. In assembly:
  2390.     LDA    BITP,X    4    ;Load the bit pattern from a table
  2391.     BPL    CONT    3  2    ;Still in the same column?
  2392.     EOR    $LO       3    ;If not, add 128 to the low byte
  2393.     STA    $LO       3
  2394.     BMI    CONT       3  2    ;If the high bit is set, stay in the same page
  2395.     INC    $HI          5    ;Otherwise point to the next page
  2396.     LDA    #$128          2    ;We still need the bit pattern for x!
  2397.    CONT ORA    ($LO),Y 5
  2398.     STA    ($LO),Y    6    ;Plot the point
  2399.             --------
  2400.        Cycle count: 18 26 32
  2401.  
  2402. Therefore, it takes 18 cycles to plot a point, 26 cycles to jump a column,
  2403. and 32 cycles to jump a page.  Over 16 points, this averages 19.375 cycles.
  2404.  
  2405. When combined with the earlier line drawing routine, this gives an average
  2406. time of 38 cycles or so (with a best time of 34 cycles); six of those cycles
  2407. are for PHA and PLA, since the line drawing routine uses A for other things.
  2408.  
  2409. Like most of the code, you can improve on this method if you think about it
  2410. a little.  Most of the time is spent checking the special cases, so how can
  2411. you avoid them?  Maybe if we do another article, we'll show you our
  2412. solution(s).
  2413.  
  2414. Now, this method has a few subtleties about it.  First, what happens if the
  2415. first point to be plotted is x=0, or x=8?  The above routine will increase
  2416. the base pointer right off the bat.  This case needs to be taken care of.
  2417.  
  2418. Second, the above assumes that you always take a step in x.  What happens if
  2419. we are taking a big step in y?  Let's say that we take ten steps in y for
  2420. every step in x.  What will the above plotter do if x takes a step across a
  2421. column, and then doesn't change for a while? Look to the source code for one
  2422. solution to this problem.
  2423.  
  2424. So that's all there is to it!
  2425.  
  2426. Post Script
  2427. -----------
  2428.  
  2429. That's all there is to it.  Well, OK, there are a few details we left out,
  2430. but you can figure them out on your own.  You can always look to the source
  2431. code to see how we overcame the same problem.  The program is set up in a
  2432. way that you can experiment around with the projection parameters d and z0,
  2433. to see what changing them does to the math.
  2434.  
  2435. What's next?  In the future you will undoubtably see lots of things from
  2436. George and myself, both the written word and the coded byte.  Maybe we will
  2437. see something from you as well?
  2438.  
  2439. Da Code
  2440. -------
  2441.  
  2442. ********************************
  2443. *..............................*
  2444. *.Stephen.Judd.................*
  2445. *.George.Taylor................*
  2446. *.Started:.7/11/94.............*
  2447. *.Finished:.7/19/94............*
  2448. *..............................*
  2449. *.Well,.if.all.goes.well.this..*
  2450. *.program.will.rotate.a.cube...*
  2451. *..............................*
  2452. *.This.program.is.intended.to..*
  2453. *.accompany.the.article.in.....*
  2454. *.C=Hacking,.July.94.issue.....*
  2455. *.For.details.on.this.program,.*
  2456. *.read.the.article!............*
  2457. *..............................*
  2458. *.Write.to.us!.................*
  2459. *..............................*
  2460. *.un(bee)mo....................*
  2461. *..............................*
  2462. *.vi...........................*
  2463. *.n(in)g.......................*
  2464. *.are(th.......................*
  2465. *.e)you(o......................*
  2466. *.nly).........................*
  2467. *..............................*
  2468. *.asl(rose)eep.................*
  2469. *..............e.e.cummings....*
  2470. *..............................*
  2471. *.P.S..This.was.written.using..*
  2472. *......Merlin.128...With.a.....*
  2473. *......little.modification.it..*
  2474. *......will.work.fine.with.....*
  2475. *......Merlin.64...If.you......*
  2476. *......don't.have.either.......*
  2477. *......well,.we.all.have.our...*
  2478. *......little.faults...........*
  2479. ********************************
  2480.  
  2481.  ORG $1000
  2482.  
  2483. *.Constants
  2484.  
  2485. BUFF1 EQU $3000 ;First.character.set
  2486. BUFF2 EQU $3800 ;Second.character.set
  2487. BUFFER EQU $A3 ;Presumably.the.tape.won't.be.running
  2488. X1 EQU $FB ;Points.for.drawing.a.line
  2489. Y1 EQU $FC ;These.zero.page.addresses
  2490. X2 EQU $FD ;don't.conflict.with.BASIC
  2491. Y2 EQU $FE
  2492. DX EQU $F9
  2493. DY EQU $FA
  2494. TEMP1 EQU $FB ;Of.course,.could.conflict.with.x1
  2495. TEMP2 EQU $FC ;Temporary.variables
  2496. ACC EQU $FB ;These.four.variables.are.used
  2497. AUX EQU $FC ;by.the.multiplication.routine
  2498. EXT EQU $FD
  2499. REM EQU $FE
  2500. ZTEMP EQU $02 ;Used.for.buffer.swap...Don't.touch.
  2501.  
  2502. ANGMAX EQU 120 ;There.are.2*pi/angmax.angles
  2503. OFFSET EQU 6 ;Float.offset:.x=xactual*2^offset
  2504.  
  2505. *.VIC
  2506.  
  2507. VMCSB EQU $D018
  2508. BKGND EQU $D020
  2509. BORDER EQU $D021
  2510. SSTART EQU 1344 ;row.9.in.screen.memory.at.1024
  2511.  
  2512.  
  2513. *.Kernal
  2514.  
  2515. CHROUT EQU $FFD2
  2516. GETIN EQU $FFE4
  2517.  
  2518. ***.Macros
  2519.  
  2520. MOVE MAC
  2521.  LDA ]1
  2522.  STA ]2
  2523.  <<<
  2524.  
  2525. GETKEY MAC  ;Wait.for.a.keypress
  2526. WAIT JSR GETIN
  2527.  CMP #00
  2528.  BEQ WAIT
  2529.  <<<
  2530.  
  2531. DEBUG MAC  ;Print.a.character
  2532. . DO.0  ;Don't.assemble
  2533.  
  2534.  LDA #]1
  2535.  JSR CHROUT
  2536.  >>> GETKEY ;And.wait.to.continue
  2537.  CMP #'s' ;My.secrect.switch.key
  2538.  BNE L1
  2539.  JSR CLEANUP
  2540.  JMP DONE
  2541. L1 CMP #'x' ;My.secret.abort.key
  2542.  BNE DONE
  2543.  JMP CLEANUP
  2544.  FIN
  2545. DONE <<<
  2546.  
  2547. DEBUGA MAC
  2548.  DO.0
  2549.  LDA ]1
  2550.  STA 1024
  2551.  FIN
  2552. DONEA <<<
  2553.  
  2554. SETBUF MAC  ;Put.buffers.where.they.can.be.hurt
  2555.  LDA #00
  2556.  STA BUFFER
  2557.  LDA ZTEMP ;ztemp.contains.the.high.byte.here
  2558.  STA BUFFER+1
  2559.  <<<
  2560.  
  2561. *-------------------------------
  2562.  
  2563.  LDA #$00
  2564.  STA BKGND
  2565.  STA BORDER
  2566.  LDA VMCSB
  2567.  AND #%00001111 ;Screen.memory.to.1024
  2568.  ORA #%00010000
  2569.  STA VMCSB
  2570.  
  2571.  LDY #00
  2572.  LDA #<TTEXT
  2573.  STA TEMP1
  2574.  LDA #>TTEXT
  2575.  STA TEMP2
  2576.  JMP TITLE
  2577. TTEXT HEX 9305111111 ;clear.screen,.white,.crsr.dn
  2578.  TXT '...............cube3d',0d,0d
  2579.  TXT '.................by',0d
  2580.  HEX 9F ;cyan
  2581.  TXT '....stephen.judd'
  2582.  HEX 99
  2583.  TXT '....george.taylor',0d,0d
  2584.  HEX 9B
  2585.  TXT '..check.out.the.july.94.issue.of',0d
  2586.  HEX 96
  2587.  TXT '..c=hacking'
  2588.  HEX 9B
  2589.  TXT '.for.more.details!',0d
  2590.  HEX 0D1D1D9E12
  2591.  TXT 'f1/f2',92
  2592.  TXT '.-.inc/dec.x-rotation',0d
  2593.  HEX 1D1D12
  2594.  TXT 'f3/f4',92
  2595.  TXT '.-.inc/dec.y-rotation',0d
  2596.  HEX 1D1D12
  2597.  TXT 'f5/f6',92
  2598.  TXT '.-.inc/dec.z-rotation',0d
  2599.  HEX 1D1D12
  2600.  TXT 'f7',92
  2601.  TXT '.resets',0d
  2602.  TXT '..press.q.to.quit',0d
  2603.  HEX 0D05
  2604.  TXT '......press.any.key.to.begin',0d
  2605.  HEX 00
  2606. TITLE LDA (TEMP1),Y
  2607.  BEQ :CONT
  2608.  JSR CHROUT
  2609.  INY
  2610.  BNE TITLE
  2611.  INC TEMP2
  2612.  JMP TITLE
  2613. :CONT >>> GETKEY
  2614.  
  2615. ****.Set.up.tables(?)
  2616.  
  2617. *.Tables.are.currently.set.up.in.BASIC
  2618. *.and.by.the.assembler.
  2619.  
  2620. TABLES
  2621.  
  2622. ****.Clear.screen.and.set.up."bitmap"
  2623.  
  2624. SETUP LDA #147
  2625.  JSR CHROUT
  2626.  LDA #<SSTART
  2627.  ADC #12 ;The.goal.is.to.center.the.graphics
  2628.  STA TEMP1 ;Column.12
  2629.  LDA #>SSTART ;Row.9
  2630.  STA TEMP1+1 ;SSTART.points.to.row.9
  2631.  LDA #00
  2632.  LDY #00
  2633.  LDX #00 ;x.will.count.16.rows.for.us
  2634.  CLC
  2635.  
  2636. :LOOP STA (TEMP1),Y
  2637.  INY
  2638.  ADC #16
  2639.  BCC :LOOP
  2640.  CLC
  2641.  LDA TEMP1
  2642.  ADC #40 ;Need.to.add.40.to.the.base.pointer
  2643.  STA TEMP1 ;To.jump.to.the.next.row
  2644.  LDA TEMP1+1
  2645.  ADC #00 ;Take.care.of.carries
  2646.  STA TEMP1+1
  2647.  LDY #00
  2648.  INX
  2649.  TXA  ;X.is.also.an.index.into.the.character.number
  2650.  CPX #16
  2651.  BNE :LOOP ;Need.to.do.it.16.times
  2652.  
  2653.  >>> DEBUG,'2'
  2654. ****.Set.up.buffers
  2655.  
  2656.  LDA #<BUFF1
  2657.  STA BUFFER
  2658.  LDA #>BUFF1
  2659.  STA BUFFER+1
  2660.  STA ZTEMP ;ztemp.will.make.life.simple.for.us
  2661.  LDA VMCSB
  2662.  AND #%11110001 ;Start.here.so.that.swap.buffers.will.work.right
  2663.  ORA #%00001110
  2664.  STA VMCSB
  2665.  
  2666.  
  2667. ****.Set.up.initial.values
  2668.  
  2669. INIT LDA #00
  2670.  STA DSX
  2671.  STA DSY
  2672.  STA DSZ
  2673.  STA SX
  2674.  STA SY
  2675.  STA SZ
  2676.  
  2677.  >>> DEBUG,'4'
  2678.  
  2679. *-------------------------------
  2680. *.Main.loop
  2681.  
  2682. ****.Get.keypress
  2683.  
  2684. MAIN
  2685. KPRESS JSR GETIN
  2686.  CMP #133 ;F1?
  2687.  BNE :F2
  2688.  LDA DSX
  2689.  CMP #ANGMAX/2 ;No.more.than.pi
  2690.  BEQ :CONT
  2691.  INC DSX ;otherwise.increase.x-rotation
  2692.  JMP :CONT
  2693. :F2 CMP #137 ;F2?
  2694.  BNE :F3
  2695.  LDA DSX
  2696.  BEQ :CONT
  2697.  DEC DSX
  2698.  JMP :CONT
  2699. :F3 CMP #134
  2700.  BNE :F4
  2701.  LDA DSY
  2702.  CMP #ANGMAX/2
  2703.  BEQ :CONT
  2704.  INC DSY ;Increase.y-rotation
  2705.  JMP :CONT
  2706. :F4 CMP #138
  2707.  BNE :F5
  2708.  LDA DSY
  2709.  BEQ :CONT
  2710.  DEC DSY
  2711.  JMP :CONT
  2712. :F5 CMP #135
  2713.  BNE :F6
  2714.  LDA DSZ
  2715.  CMP #ANGMAX/2
  2716.  BEQ :CONT
  2717.  INC DSZ ;z-rotation
  2718.  JMP :CONT
  2719. :F6 CMP #139
  2720.  BNE :F7
  2721.  LDA DSZ
  2722.  BEQ :CONT
  2723.  DEC DSZ
  2724.  JMP :CONT
  2725. :F7 CMP #136
  2726.  BNE :Q
  2727.  JMP INIT
  2728. :Q CMP #'q' ;q.quits
  2729.  BNE :CONT
  2730.  JMP CLEANUP
  2731.  
  2732. :CONT
  2733. *.>>>.DEBUG,'5'
  2734.  
  2735. ****.Update.angles
  2736.  
  2737. UPDATE CLC
  2738.  LDA SX
  2739.  ADC DSX
  2740.  CMP #ANGMAX ;Are.we.>=.maximum.angle?
  2741.  BCC :CONT1
  2742.  SBC #ANGMAX :If so, reset
  2743. :CONT1 STA SX
  2744.  CLC
  2745.  LDA SY
  2746.  ADC DSY
  2747.  CMP #ANGMAX
  2748.  BCC :CONT2
  2749.  SBC #ANGMAX ;Same.deal
  2750. :CONT2 STA SY
  2751.  CLC
  2752.  LDA SZ
  2753.  ADC DSZ
  2754.  CMP #ANGMAX
  2755.  BCC :CONT3
  2756.  SBC #ANGMAX
  2757. :CONT3 STA SZ
  2758.  
  2759.  
  2760. ****.Rotate.coordinates
  2761.  
  2762. ROTATE
  2763.  
  2764. ***.First,.calculate.t1,t2,...,t10
  2765.  
  2766. **.Two.macros.to.simplify.our.life
  2767. ADDA MAC  ;Add.two.angles.together
  2768.  CLC
  2769.  LDA ]1
  2770.  ADC ]2
  2771.  CMP #ANGMAX ;Is.the.sum.>.2*pi?
  2772.  BCC DONE
  2773.  SBC #ANGMAX ;If.so,.subtract.2*pi
  2774. DONE <<<
  2775.  
  2776. SUBA MAC  ;Subtract.two.angles
  2777.  SEC
  2778.  LDA ]1
  2779.  SBC ]2
  2780.  BCS DONE
  2781.  ADC #ANGMAX ;Oops,.we.need.to.add.2*pi
  2782. DONE <<<
  2783.  
  2784. **.Now.calculate.t1,t2,etc.
  2785.  
  2786.  >>> SUBA,SY;SZ
  2787.  STA T1 ;t1=sy-sz
  2788.  >>> ADDA,SY;SZ
  2789.  STA T2 ;t2=sy+sz
  2790.  >>> ADDA,SX;SZ
  2791.  STA T3 ;t3=sx+sz
  2792.  >>> SUBA,SX;SZ
  2793.  STA T4 ;t4=sx-sz
  2794.  >>> ADDA,SX;T2
  2795.  STA T5 ;t5=sx+t2
  2796.  >>> SUBA,SX;T1
  2797.  STA T6 ;t6=sx-t1
  2798.  >>> ADDA,SX;T1
  2799.  STA T7 ;t7=sx+t1
  2800.  >>> SUBA,T2;SX
  2801.  STA T8 ;t8=t2-sx
  2802.  >>> SUBA,SY;SX
  2803.  STA T9 ;t9=sy-sx
  2804.  >>> ADDA,SX;SY
  2805.  STA T10 ;t10=sx+sy
  2806.  
  2807. *.Et.voila!
  2808.  
  2809. ***.Next,.calculate.A,B,C,...,I
  2810.  
  2811. **.Another.useful.little.macro
  2812. DIV2 MAC  ;Divide.a.signed.number.by.2
  2813. ;It.is.assumed.that.the.number
  2814.  BPL POS ;is.in.the.accumulator
  2815.  CLC
  2816.  EOR #$FF ;We.need.to.un-negative.the.number
  2817.  ADC #01 ;by.taking.it's.complement
  2818.  LSR  ;divide.by.two
  2819.  CLC
  2820.  EOR #$FF
  2821.  ADC #01 ;Make.it.negative.again
  2822.  JMP DONEDIV
  2823. POS LSR  ;Number.is.positive
  2824. DONEDIV <<<
  2825.  
  2826. MUL2 MAC  ;Multiply.a.signed.number.by.2
  2827.  BPL POSM
  2828.  CLC
  2829.  EOR #$FF
  2830.  ADC #$01
  2831.  ASL
  2832.  CLC
  2833.  EOR #$FF
  2834.  ADC #$01
  2835.  JMP DONEMUL
  2836. POSM ASL
  2837. DONEMUL <<<
  2838.  
  2839. **.Note.that.we.are.currently.making.a.minor.leap
  2840. **.of.faith.that.no.overflows.will.occur.
  2841.  
  2842. :CALCA CLC
  2843.  LDX T1
  2844.  LDA COS,X
  2845.  LDX T2
  2846.  ADC COS,X
  2847.  STA A11 ;A=(cos(t1)+cos(t2))/2
  2848. :CALCB LDX T1
  2849.  LDA SIN,X
  2850.  SEC
  2851.  LDX T2
  2852.  SBC SIN,X
  2853.  STA B12 ;B=(sin(t1)-sin(t2))/2
  2854. :CALCC LDX SY
  2855.  LDA SIN,X
  2856.  >>> MUL2
  2857.  STA C13 ;C=sin(sy)
  2858. :CALCD SEC
  2859.  LDX T8
  2860.  LDA COS,X
  2861.  LDX T7
  2862.  SBC COS,X
  2863.  SEC
  2864.  LDX T5
  2865.  SBC COS,X
  2866.  CLC
  2867.  LDX T6
  2868.  ADC COS,X ;Di=(cos(t8)-cos(t7)+cos(t6)-cos(t5))/2
  2869.  >>> DIV2
  2870.  CLC
  2871.  LDX T3
  2872.  ADC SIN,X
  2873.  SEC
  2874.  LDX T4
  2875.  SBC SIN,X
  2876.  STA D21 ;D=(sin(t3)-sin(t4)+Di)/2
  2877. :CALCE SEC
  2878.  LDX T5
  2879.  LDA SIN,X
  2880.  LDX T6
  2881.  SBC SIN,X
  2882.  SEC
  2883.  LDX T7
  2884.  SBC SIN,X
  2885.  SEC
  2886.  LDX T8
  2887.  SBC SIN,X ;Ei=(sin(t5)-sin(t6)-sin(t7)-sin(t8))/2
  2888.  >>> DIV2
  2889.  CLC
  2890.  LDX T3
  2891.  ADC COS,X
  2892.  CLC
  2893.  LDX T4
  2894.  ADC COS,X
  2895.  STA E22 ;E=(cos(t3)+cos(t4)+Ei)/2
  2896. :CALCF LDX T9
  2897.  LDA SIN,X
  2898.  SEC
  2899.  LDX T10
  2900.  SBC SIN,X
  2901.  STA F23 ;F=(sin(t9)-sin(t10))/2
  2902. :CALCG LDX T6
  2903.  LDA SIN,X
  2904.  SEC
  2905.  LDX T8
  2906.  SBC SIN,X
  2907.  SEC
  2908.  LDX T7
  2909.  SBC SIN,X
  2910.  SEC
  2911.  LDX T5
  2912.  SBC SIN,X ;Gi=(sin(t6)-sin(t8)-sin(t7)-sin(t5))/2
  2913.  >>> DIV2
  2914.  CLC
  2915.  LDX T4
  2916.  ADC COS,X
  2917.  SEC
  2918.  LDX T3
  2919.  SBC COS,X
  2920.  STA G31 ;G=(cos(t4)-cos(t3)+Gi)/2
  2921.  >>> DEBUGA,G31
  2922.  >>> DEBUG,'g'
  2923. :CALCH CLC
  2924.  LDX T6
  2925.  LDA COS,X
  2926.  LDX T7
  2927.  ADC COS,X
  2928.  SEC
  2929.  LDX T5
  2930.  SBC COS,X
  2931.  SEC
  2932.  LDX T8
  2933.  SBC COS,X ;Hi=(cos(t6)+cos(t7)-cos(t5)-cos(t8))/2
  2934.  >>> DIV2
  2935.  CLC
  2936.  LDX T3
  2937.  ADC SIN,X
  2938.  CLC
  2939.  LDX T4
  2940.  ADC SIN,X
  2941.  STA H32 ;H=(sin(t3)+sin(t4)+Hi)/2
  2942. :WHEW CLC
  2943.  LDX T9
  2944.  LDA COS,X
  2945.  LDX T10
  2946.  ADC COS,X
  2947.  STA I33 ;I=(cos(t9)+cos(t10))/2
  2948.  
  2949. **.It's.all.downhill.from.here.
  2950.  
  2951. **.Rotate,.project,.and.store.the.points
  2952. DOWNHILL LDA A11 ;This.is.getting.to.be.a.real.mess
  2953.  STA TA
  2954.  LDA B12 ;The.reason.this.is.done
  2955.  STA TB ;is.to.make.the.code.a.little
  2956.  LDA C13 ;easier.to.read.(and.debug!)
  2957.  STA TC
  2958.  LDA D21 ;These.are.all.temporary.locations
  2959.  STA TD ;Used.by.the.projection.subroutine.
  2960.  LDA E22
  2961.  STA TE ;Otherwise,.there.would.be.eight
  2962.  LDA F23 ;long.routines.here.
  2963.  STA TF
  2964.  LDA G31 ;But.it.would.be.significantly.faster
  2965.  STA TG
  2966.  LDA H32
  2967.  STA TH
  2968.  LDA I33
  2969.  STA TI
  2970.  
  2971. *.A.neat.macro
  2972. NEG MAC  ;Change.the.sign.of.a.two's.complement
  2973.  CLC
  2974.  LDA ]1 ;number.
  2975.  EOR #$FF
  2976.  ADC #$01
  2977.  <<<
  2978.  
  2979. *.P1=[1.1.1]
  2980.  JSR PROJECT ;Unroll.this.whole.thing
  2981.  LDX TX1 ;(sorry.about.these.two.lines)
  2982.  LDY TY1 ;(see.PROJECT.for.reason.why)
  2983.  STX P1X ;For.a.pretty.big.speed.increase!
  2984.  STY P1Y
  2985. *.P2=[1.-1.1]
  2986.  >>> NEG,B12 ;Change.these.elements
  2987.  STA TB
  2988.  >>> NEG,E22 ;Since.y.is.now.-1
  2989.  STA TE
  2990.  >>> NEG,H32
  2991.  STA TH
  2992.  JSR PROJECT
  2993.  LDX TX1
  2994.  LDY TY1
  2995.  STX P2X
  2996.  STY P2Y
  2997. *.P3=[-1.-1.1]
  2998.  >>> NEG,A11
  2999.  STA TA
  3000.  >>> NEG,D21
  3001.  STA TD
  3002.  >>> NEG,G31
  3003.  STA TG
  3004.  JSR PROJECT
  3005.  LDX TX1
  3006.  LDY TY1
  3007.  STX P3X
  3008.  STY P3Y
  3009. *.P4=[-1.1.1]
  3010.  LDA B12
  3011.  STA TB
  3012.  LDA E22
  3013.  STA TE
  3014.  LDA H32
  3015.  STA TH
  3016.  JSR PROJECT
  3017.  LDX TX1
  3018.  LDY TY1
  3019.  STX P4X
  3020.  STY P4Y
  3021. *.P8=[-1.1.-1]
  3022.  >>> NEG,C13
  3023.  STA TC
  3024.  >>> NEG,F23
  3025.  STA TF
  3026.  >>> NEG,I33
  3027.  STA TI
  3028.  JSR PROJECT
  3029.  LDX TX1
  3030.  LDY TY1
  3031.  STX P8X
  3032.  STY P8Y
  3033. *.P7=[-1.-1.-1]
  3034.  >>> NEG,B12
  3035.  STA TB
  3036.  >>> NEG,E22
  3037.  STA TE
  3038.  >>> NEG,H32
  3039.  STA TH
  3040.  JSR PROJECT
  3041.  LDX TX1
  3042.  LDY TY1
  3043.  STX P7X
  3044.  STY P7Y
  3045. *.P6=[1.-1.-1]
  3046.  LDA A11
  3047.  STA TA
  3048.  LDA D21
  3049.  STA TD
  3050.  LDA G31
  3051.  STA TG
  3052.  JSR PROJECT
  3053.  LDX TX1
  3054.  LDY TY1
  3055.  STX P6X
  3056.  STY P6Y
  3057. *.P5=[1.1.-1]
  3058.  LDA B12
  3059.  STA TB
  3060.  LDA E22
  3061.  STA TE
  3062.  LDA H32
  3063.  STA TH
  3064.  JSR PROJECT
  3065.  LDX TX1
  3066.  LDY TY1
  3067.  STX P5X
  3068.  STY P5Y
  3069.  
  3070. ****.Clear.buffer
  3071.  
  3072.  >>> SETBUF
  3073. CLRBUF LDA #$00 ;Pretty.straightforward,
  3074.  LDX #$08 ;I.think
  3075.  LDY #$00
  3076. :LOOP STA (BUFFER),Y
  3077.  INY
  3078.  BNE :LOOP
  3079.  INC BUFFER+1
  3080.  DEX
  3081.  BNE :LOOP
  3082.  LDA BUFFER+1
  3083.  
  3084. ****.Finally,.draw.the.lines.
  3085.  
  3086.  LDA P1X ;[1.1.1]
  3087.  STA TX1
  3088.  LDA P1Y
  3089.  STA TY1
  3090.  LDA P2X ;[1.-1.1]
  3091.  STA TX2
  3092.  LDA P2Y
  3093.  STA TY2
  3094.  JSR DRAW ;First.line
  3095.  
  3096.  LDA P3X ;[-1.-1.1]
  3097.  STA TX1
  3098.  LDA P3Y
  3099.  STA TY1
  3100.  JSR DRAW ;Second.line
  3101.  
  3102.  LDA P4X ;[-1.1.1]
  3103.  STA TX2
  3104.  LDA P4Y
  3105.  STA TY2
  3106.  JSR DRAW ;Third.line
  3107.  
  3108.  LDA P1X ;[1.1.1]
  3109.  STA TX1
  3110.  LDA P1Y
  3111.  STA TY1
  3112.  JSR DRAW ;Fourth.line...One.face.done.
  3113.  
  3114.  LDA P5X ;[1.1.-1]
  3115.  STA TX2
  3116.  LDA P5Y
  3117.  STA TY2
  3118.  JSR DRAW ;Five
  3119.  
  3120.  LDA P6X ;[1.-1.-1]
  3121.  STA TX1
  3122.  LDA P6Y
  3123.  STA TY1
  3124.  JSR DRAW ;Six
  3125.  
  3126.  LDA P2X ;[1.-1.1]
  3127.  STA TX2
  3128.  LDA P2Y
  3129.  STA TY2
  3130.  JSR DRAW ;Seven
  3131.  
  3132.  LDA P7X ;[-1.-1.-1]
  3133.  STA TX2
  3134.  LDA P7Y
  3135.  STA TY2
  3136.  JSR DRAW ;Eight
  3137.  
  3138.  LDA P3X ;[-1.-1.1]
  3139.  STA TX1
  3140.  LDA P3Y
  3141.  STA TY1
  3142.  JSR DRAW ;Nine
  3143.  
  3144.  LDA P8X ;[-1.1.-1]
  3145.  STA TX1
  3146.  LDA P8Y
  3147.  STA TY1
  3148.  JSR DRAW ;Ten
  3149.  
  3150.  LDA P4X ;[-1.1.1]
  3151.  STA TX2
  3152.  LDA P4Y
  3153.  STA TY2
  3154.  JSR DRAW ;Eleven
  3155.  
  3156.  LDA P5X ;[1.1.-1]
  3157.  STA TX2
  3158.  LDA P5Y
  3159.  STA TY2
  3160.  JSR DRAW ;Twelve!
  3161.  
  3162. ****.Swap.buffers
  3163.  
  3164. SWAPBUF LDA VMCSB
  3165.  EOR #$02 ;Pretty.tricky,.eh?
  3166.  STA VMCSB
  3167.  LDA #$08
  3168.  EOR ZTEMP ;ztemp=high.byte.just.flips
  3169.  STA ZTEMP ;between.$30.and.$38
  3170.  
  3171.  JMP MAIN ;Around.and.around.we.go...
  3172.  
  3173.  
  3174. *-------------------------------
  3175. *.This.subroutine.calculates.the.projection.of.X.and.Y
  3176.  
  3177. PROJECT CLC
  3178.  LDA TG
  3179.  ADC TH
  3180.  CLC
  3181.  ADC TI ;This.is.rotated.Z
  3182.  CLC
  3183.  ADC #128 ;We.are.going.to.take.128+z
  3184.  TAX  ;Now.it.is.ready.for.indexing
  3185.  LDA ZDIV,X ;Table.of.-d/z
  3186.  STA AUX ;This.is.for.the.projection
  3187.  STA REM ;Multiply.can.clobber.AUX
  3188.  
  3189.  CLC
  3190.  LDA TA
  3191.  ADC TB
  3192.  CLC
  3193.  ADC TC
  3194.  STA ACC ;This.is.rotated.x
  3195.  JSR SMULT ;Signed.multiply.ACC*AUX/2^OFFSET
  3196.  CLC
  3197.  LDA ACC
  3198. :CONT1 ADC #64 ;Offset.the.coordinate
  3199. *.See.below.for.the.reason.why.this
  3200. *.next.instruction.is.commented.out
  3201. *.TAX..;Now.X.is.x!
  3202.  STA TX1
  3203.  CLC  ;Do.the.whole.thing.again.for.Y
  3204.  LDA REM
  3205.  STA AUX
  3206.  LDA TD
  3207.  ADC TE
  3208.  CLC
  3209.  ADC TF
  3210.  STA ACC ;This.is.rotated.y
  3211.  JSR SMULT ;Signed.multiply.ACC*AUX/2^OFFSET
  3212.  CLC
  3213.  LDA ACC
  3214. :CONT2 ADC #64 ;Offset.the.coordinate
  3215. *.For.some.completely.unknown.reason.to.me
  3216. *.the.instruction.below.doesn't.work...Somehow
  3217. *.the.RTS.is.modifying.X.and.Y???
  3218. *.TAY..;Store.in.Y
  3219.  STA TY1
  3220.  RTS  ;I.hope.to.heck.this.works.
  3221.  
  3222. *-------------------------------
  3223. *.SMULT:.8-bit.signed.(sort-of).multiply
  3224. *
  3225. *.ACC*AUX/2^OFFSET.->.[ACC,.EXT]..16-bit.result..lo,hi
  3226. *
  3227. *.Note.that.this.routine.divides.the.end.result.by.2^OFFSET
  3228.  
  3229. *.Yup,.another.macro.
  3230. DIVOFF MAC  ;Divide.by.the.float.offset
  3231.  LUP OFFSET ;Repeat.offset.times
  3232.  LSR  ;A.contains.high.byte
  3233.  ROR ACC ;ACC.is.low.byte
  3234.  --^
  3235.  <<<
  3236.  
  3237.  
  3238. SMULT CLC
  3239.  LDA ACC ;First,.is.the.result.positive.or.negative?
  3240.  EOR AUX
  3241.  BMI :NEG
  3242.  
  3243.  LDA ACC ;They.are.either.both.negative.or
  3244.  BPL :CONT1 ;both.positive
  3245.  EOR #$FF ;In.this.case,.make.them
  3246.  ADC #$01 ;both.positive!
  3247.  STA ACC
  3248.  >>> NEG,AUX ;Little.macro.used.earlier.
  3249. :CONT1 LDA #00 ;Multiply.the.two.numbers
  3250.  LDY #$09
  3251. ]LOOP LSR  ;Read.the.article.for.details.
  3252.  ROR ACC
  3253.  BCC :MULT1 ;Or.figure.it.out.yourself!
  3254.  CLC
  3255.  ADC AUX
  3256. :MULT1 DEY
  3257.  BNE ]LOOP
  3258.  >>> DIVOFF ;Remove.this.line.for.a.general.multiply
  3259.  STA EXT
  3260.  RTS
  3261.  
  3262. :NEG LDA ACC ;One.of.the.two.is.negative
  3263.  BMI :CONT2
  3264.  >>> NEG,AUX ;Otherwise.it's.AUX
  3265.  JMP :CONT3
  3266. :CONT2 EOR #$FF ;Take.two's.complement
  3267.  ADC #$01
  3268.  STA ACC
  3269. :CONT3 LDA #00 ;Multiply
  3270.  LDY #$09
  3271. ]LOOP2 LSR
  3272.  ROR ACC
  3273.  BCC :MULT2
  3274.  CLC
  3275.  ADC AUX
  3276. :MULT2 DEY
  3277.  BNE ]LOOP2
  3278.  >>> DIVOFF ;Again,.divide.by.the.offset
  3279.  STA EXT
  3280.  LDA ACC
  3281.  BPL :OK ;Something.is.really.wrong.if.this.is.negative.
  3282.  JSR CHOKE
  3283. :OK EOR #$FF ;Otherise,.everything.relevant.should
  3284.  ADC #$01 ;be.completely.in.the.low.byte.
  3285.  STA ACC
  3286.  RTS  ;I.hope...
  3287.  
  3288. *-------------------------------
  3289. *.General.questionable-value.error.procedure
  3290.  
  3291. CHOKE LDX #00
  3292. :LOOP LDA :CTEXT,X
  3293.  BEQ :DONE
  3294.  JSR CHROUT
  3295.  INX
  3296.  JMP :LOOP
  3297. :DONE RTS
  3298. :CTEXT HEX 0D ;CR
  3299.  TXT 'something.choked.:('
  3300.  HEX 0D00
  3301.  
  3302. *-------------------------------
  3303. *.Drawin'.a.line...A.fahn.lahn.
  3304.  
  3305. ***.Some.useful.macros
  3306.  
  3307. PLOTPX MAC  ;plot.a.point.in.x
  3308.  PHA  ;Use.this.one.every.time
  3309.  LDA BITP,X ;X.is.increased
  3310.  BPL C1
  3311.  EOR BUFFER
  3312.  STA BUFFER
  3313.  BMI C2
  3314.  INC BUFFER+1
  3315. C2 LDA #%10000000
  3316. C1 ORA (BUFFER),Y
  3317.  STA (BUFFER),Y
  3318.  PLA  ;Need.to.save.A!
  3319.  <<<
  3320.  
  3321. PLOTPY MAC  ;Plot.a.point.in.y:.simpler.and.necessary!
  3322.  PHA  ;Use.this.one.when.you.just.increase.Y
  3323.  LDA BITP,X ;but.X.doesn't.change
  3324.  ORA (BUFFER),Y
  3325.  STA (BUFFER),Y
  3326.  PLA
  3327.  <<<
  3328.  
  3329. CINIT MAC  ;Macro.to.initialize.the.counter
  3330.  LDA ]1 ;dx.or.dy
  3331.  LSR
  3332.  EOR #$FF ;(Not.really.two's.complement)
  3333.  ADC #$01 ;A.=.256-dx/2.or.256-dy/2
  3334.  <<<  ;The.dx/2.makes.a.nicer.looking.line
  3335.  
  3336. XSTEP MAC  ;Macro.to.take.a.step.in.X
  3337. XLOOP INX
  3338.  ADC DY
  3339.  BCC L1
  3340. *.Do.we.use.INY.or.DEY.here?
  3341.  IF I,]1 ;If.the.first.character.is.an.'I'
  3342.  INY
  3343.  ELSE
  3344.  DEY
  3345.  FIN
  3346.  SBC DX
  3347. L1 >>> PLOTPX ;Always.take.a.step.in.X
  3348.  CPX X2
  3349.  BNE XLOOP
  3350.  <<<
  3351.  
  3352. YSTEP MAC  ;Same.thing,.but.for.Y
  3353. YLOOP IF I,]1
  3354.  INY
  3355.  ELSE
  3356.  DEY
  3357.  CLC  ;Very.important!
  3358.  FIN
  3359.  ADC DX
  3360.  BCC L2
  3361.  INX  ;Always.increase.X
  3362.  SBC DY
  3363.  >>> PLOTPX
  3364.  JMP L3
  3365. L2 >>> PLOTPY ;We.only.increased.Y
  3366. L3 CPY Y2
  3367.  BNE YLOOP
  3368.  <<<
  3369.  
  3370. ****.Initial.line.setup
  3371.  
  3372. DRAW >>> MOVE,TX1;X1  ;Move.stuff.into.zero.page
  3373.  >>> MOVE,TX2;X2  ;Where.it.can.be.modified
  3374.  >>> MOVE,TY1;Y1
  3375.  >>> MOVE,TY2;Y2
  3376.  >>> SETBUF ;Now.we.can.clobber.the.buffer
  3377.  
  3378.  SEC  ;Make.sure.x1<x2
  3379.  LDA X2
  3380.  SBC X1
  3381.  BCS :CONT
  3382.  LDA Y2 ;If.not,.swap.P1.and.P2
  3383.  LDY Y1
  3384.  STA Y1
  3385.  STY Y2
  3386.  LDA X1
  3387.  LDY X2
  3388.  STY X1
  3389.  STA X2
  3390.  
  3391.  SBC X1 ;Now.A=dx
  3392. :CONT STA DX
  3393.  LDX X1 ;Put.x1.into.X,.now.we.can.trash.X1
  3394.  
  3395. COLUMN LDA X1 ;Find.the.first.column.for.X
  3396.  LSR  ;(This.can.be.made.much.faster!)
  3397.  LSR  ;There.are.x1/8.128.byte.blocks
  3398.  LSR  ;Which.means.x1/16.256.byte.blocks
  3399.  LSR
  3400.  BCC :EVEN ;With.a.possible.extra.128.byte.block
  3401.  LDY #$80 ;if.so,.set.the.high.bit
  3402.  STY BUFFER
  3403.  CLC
  3404. :EVEN ADC BUFFER+1 ;Add.in.the.number.of.256.byte.blocks
  3405.  STA BUFFER+1 ;And.store.it!
  3406.  
  3407.  SEC
  3408.  LDA Y2 ;Calculate.dy
  3409.  SBC Y1
  3410.  BCS :CONT2 ;Is.y2>y1?
  3411.  LDA Y1 ;Otherwise.dy=y1-y2
  3412.  SBC Y2
  3413. :CONT2 STA DY
  3414.  CMP DX ;Who's.bigger:.dy.or.dx?
  3415.  BCS STEPINY ;If.dy,.we.need.to.take.big.steps.in.y
  3416.  
  3417. STEPINX LDY Y1 ;X.is.already.set.to.x1
  3418.  LDA BITP,X ;Plot.the.first.point
  3419.  ORA (BUFFER),Y
  3420.  STA (BUFFER),Y
  3421.  >>> CINIT,DX ;Initialize.the.counter
  3422.  CPY Y2
  3423.  BCS XDECY ;Do.we.step.forwards.or.backwards.in.Y?
  3424.  
  3425. XINCY >>> XSTEP,INY
  3426.  RTS
  3427.  
  3428. XDECY >>> XSTEP,DEY
  3429.  RTS
  3430.  
  3431. STEPINY LDY Y1 ;Well,.a.little.repetition.never.hurt.anyone
  3432.  LDA BITP,X
  3433.  ORA (BUFFER),Y
  3434.  STA (BUFFER),Y
  3435.  >>> CINIT,DY
  3436.  CPY Y2
  3437.  BCS YDECY
  3438.  
  3439. YINCY >>> YSTEP,INY
  3440.  RTS
  3441.  
  3442. YDECY >>> YSTEP,DEY
  3443.  RTS
  3444.  
  3445.  
  3446. *-------------------------------
  3447. *.Clean.up
  3448.  
  3449. CLEANUP LDA VMCSB ;Switch.char.rom.back.in
  3450.  AND #%11110101 ;default
  3451.  STA VMCSB
  3452.  
  3453.  RTS  ;bye!
  3454.  
  3455. *-------------------------------
  3456. *.Some.variables
  3457.  
  3458. TX1 DS 1
  3459. TY1 DS 1
  3460. TX2 DS 1
  3461. TY2 DS 1
  3462. P1X DS 1 ;These.are.temporary.storage
  3463. P1Y DS 1 ;Used.in.plotting.the.projection
  3464. P2X DS 1
  3465. P2Y DS 1 ;They.are.here.so.that.we
  3466. P3X DS 1 ;don't.have.to.recalculate.them.
  3467. P3Y DS 1
  3468. P4X DS 1 ;They.make.life.easy.
  3469. P4Y DS 1
  3470. P5X DS 1 ;Why.are.you.looking.at.me.like.that?
  3471. P5Y DS 1 ;Don't.you.trust.me?
  3472. P6X DS 1
  3473. P6Y DS 1 ;Having.another.child.wasn't.my.idea.
  3474. P7X DS 1
  3475. P7Y DS 1
  3476. P8X DS 1
  3477. P8Y DS 1
  3478. DSX DS 1 ;DSX.is.the.increment.for.rotating.around.x
  3479. DSY DS 1 ;Similar.for.DSY,.DSZ
  3480. DSZ DS 1
  3481. SX DS 1 ;These.are.the.actual.angles.in.x.y.and.z
  3482. SY DS 1
  3483. SZ DS 1
  3484. T1 DS 1 ;These.are.used.in.the.rotation
  3485. T2 DS 1
  3486. T3 DS 1 ;See.the.article.for.more.details
  3487. T4 DS 1
  3488. T5 DS 1
  3489. T6 DS 1
  3490. T7 DS 1
  3491. T8 DS 1
  3492. T9 DS 1
  3493. T10 DS 1
  3494. A11 DS 1 ;These.are.the.elements.of.the.rotation.matrix
  3495. B12 DS 1 ;XYZ
  3496. C13 DS 1
  3497. D21 DS 1 ;The.number.denotes.(row,column)
  3498. E22 DS 1
  3499. F23 DS 1
  3500. G31 DS 1
  3501. H32 DS 1
  3502. I33 DS 1
  3503. TA DS 1 ;These.are.temporary.locations
  3504. TB DS 1 ;for.use.by.the.projection.routine
  3505. TC DS 1
  3506. TD DS 1
  3507. TE DS 1
  3508. TF DS 1
  3509. TG DS 1
  3510. TH DS 1
  3511. TI DS 1
  3512.  
  3513. *-------------------------------
  3514. *.Set.up.bit.table
  3515.  
  3516.  DS ^ ;Clear.to.end.of.page
  3517.    ;So.that.tables.start.on.a.page.boundary
  3518. BITP LUP 16 ;128.Entries.for.X
  3519.  DFB %10000000
  3520.  DFB %01000000
  3521.  DFB %00100000
  3522.  DFB %00010000
  3523.  DFB %00001000
  3524.  DFB %00000100
  3525.  DFB %00000010
  3526.  DFB %00000001
  3527.  --^
  3528. SIN   ;Table.of.sines,.120.bytes
  3529. COS EQU SIN+128 ;Table.of.cosines
  3530.    ;Both.of.these.trig.tables.are
  3531.    ;currently.set.up.from.BASIC
  3532. ZDIV EQU COS+128 ;Division.table
  3533.  
  3534. UUencoded Binaries
  3535. ------------------
  3536. begin 666 runme3d
  3537. M 0@>" H BT&R,*=!LC$ZDR)#54)%,T0N3R(L."PY "X(% "3(DE.250S1"(L
  3538. M.    !H:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:
  3539. F&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:
  3540.  
  3541. end
  3542.  
  3543. begin 666 init3d
  3544. M 0@D" H CR!04D]'4D%-(%1/($E.251)04Q)6D4@0U5"13-$ $8(% "/(%-4
  3545. M15!(14X@2E5$1"P@1T5/4D=%(%1!64Q/4@!7"!D F2(%5T]22TE.1R([ ',(
  3546. M'@!"4[(V-3(X.D)#LC8V-38Z0EJR-C<X- "#""@ 0;(P.D1!LO^M-C  LP@R
  3547. M (%)LC"D,3(P.E,ELC,RK+\H02FJ+C4Z0R6R,S*LOBA!*:HN-3I!LD&J1$$ 
  3548. MO0@S )DB+B([ -0(-P"+(%,ELS @IR!3);(R-3:J4R4 ZP@X (L@0R6S,""G
  3549. M($,ELC(U-JI#)0 !"3H ET)3JDDL4R4ZET)#JDDL0R4 !PD[ (( (0D\ $2R
  3550. M.# Z6C"R,SI:LJLQ,C@Z1%JR,0 N"48 @4JR,*0R-34 . E' )DB(2([ $X)
  3551. M4 !1);(V-*Q$K2@V-*Q:,*M:*0!D"5$ BR!1);$Q,C<@IR!1);(Q,C< ? E2
  3552. M (L@426SJS$R-R"G(%$ELJLQ,C< DPE3 (L@426S,""G(%$ELC(U-JI1)0"@
  3553. M"54 ET):JDHL424 K0E: %JR6JI$6CJ" ,4)9 ">-# Y-CJ9(DY%050L($A5
  3554. M2#\B    &AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:
  3555. 1&AH:&AH:&AH:&AH:&AH:&AH:
  3556.  
  3557. end
  3558.  
  3559. begin 666 listme3d
  3560. M 0@8" H CR!.3U1%4R!&3U(@0U5"13-$ !X("P"/ $4(# "/(%1(15)%($%2
  3561. M12!35$E,3"!!($9%5R!-24Y/4B!"54=3 &D(#0"/(%1(12!-3U1)3TX@25,@
  3562. M2D522UD@1D]2(%--04Q, (T(#@"/($E.0U)%345.5%,Z(%!23T)!0DQ9(%)/
  3563. M54Y$3T9& ),(#P"/ +@($ "/($9%14P@1E)%12!43R!-3T1)1ED@5$A%(%!!
  3564. M4DU3+@#>"!$ CR!*55-4(%%5250@5$A%(%!23T=204T@04Y$($Q)4U0N  ,)
  3565. M$@"/(%1262!#2$%.1TE.1R!$($%.1"!:," H64]5($-!3@ C"1, CR!%5D5.
  3566. M($U!2T4@6BU:,"!.14=!5$E612DN $8)% "/($)%($-!4D5&54P@04)/550@
  3567. M4D535$%25$E.1R$ ;0D5 (\@248@64]5(%=!3E0@5$\@4T5%(%E/55(@0T]-
  3568. M4%5415( D@D6 (\@1$E%($%.($%-05I)3D<@1$5!5$@@2E535"!465!% +@)
  3569. M%P"/("=254X@-C G+B!!3%=!65,@4E5.(%1(12!%3E1)4D4 QPD8 (\@4%)/
  3570. M1U)!32X S0D9 (\ \PD: (\@4T]-151)3453(%1(12!%6453($=%5"!#3TY&
  3571. M55-%1  8"AL CR!!0D]55"!42$4@4$524U!%0U1)5D4L($%.1"!42$4 .PH<
  3572. M (\@0U5"12!724Q,($Q/3TL@4D5!3$Q9(%=%25)$+@!?"AT CR!*55-4($),
  3573. M24Y+($]2(%1262!43R!&24Y$(%1(10"#"AX CR!224=(5"!015)34$5#5$E6
  3574. M12X@($5615(@4T5%3@"H"A\ CR!42$4@)T-205I9($-2051%)S\@(%-!344@
  3575. M241%02X N@H@ (\@4TQ*(#<O,3DO.30    :&AH:&AH:&AH:&AH:&AH:&AH:
  3576. M&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:&AH:
  3577. #&AH:
  3578.  
  3579. end
  3580.  
  3581. begin 666 cube3d.o
  3582. M !"I (T@T(TAT*T8T"D/"1"-&-"@ *D?A?NI$(7\3%41DP41$1$@(" @(" @
  3583. M(" @(" @("!#54)%,T0-#2 @(" @(" @(" @(" @(" @0ED-GR @("!35$50
  3584. M2$5.($I51$29(" @($=%3U)'12!405E,3U(-#9L@($-(14-+($]55"!42$4@
  3585. M2E5,62 Y-"!)4U-512!/1@V6("!#/4A!0TM)3D>;($9/4B!-3U)%($1%5$%)
  3586. M3%,A#0T='9X21C$O1C*2("T@24Y#+T1%0R!8+5)/5$%424].#1T=$D8S+T8T
  3587. MDB M($E.0R]$14,@62U23U1!5$E/3@T='1)&-2]&-I(@+2!)3D,O1$5#(%HM
  3588. M4D]4051)3TX-'1T21C>2(%)%4T544PT@(%!215-3(%$@5$\@455)5 T-!2 @
  3589. M(" @(%!215-3($%.62!+15D@5$\@0D5'24X- +'[\ L@TO_(T/;F_$Q5$2#D
  3590. M_\D \/FIDR#2_ZE :0R%^ZD%A?RI *  H@ 8D?O(:1"0^1BE^VDHA?NE_&D 
  3591. MA?R@ .B*X!#0Y*D A:.I,(6DA0*M&- I\0D.C1C0J0"-SQB-T!B-T1B-TAB-
  3592. MTQB-U!@@Y/_)A= -K<\8R3SP8^[/&$PV$LF)T NMSQCP5,[/&$PV$LF&T VM
  3593. MT!C)//!#[M 83#82R8K0"ZW0&/ TSM 83#82R8?0#:W1&,D\\"/NT1A,-A+)
  3594. MB] +K=$8\!3.T1A,-A+)B- #3+$1R5'0 TRR&!BMTAAMSQC)>) "Z7B-TA@8
  3595. MK=,8;= 8R7B0 NEXC=,8&*W4&&W1&,EXD +I>(W4&#BMTQCMU!BP FEXC=48
  3596. M&*W3&&W4&,EXD +I>(W6&!BMTAAMU!C)>) "Z7B-UQ@XK=(8[=08L )I>(W8
  3597. M&!BMTAAMUAC)>) "Z7B-V1@XK=(8[=48L )I>(W:&!BMTAAMU1C)>) "Z7B-
  3598. MVQ@XK=88[=(8L )I>(W<&#BMTQCMTABP FEXC=T8&*W2&&W3&,EXD +I>(W>
  3599. M&!BNU1B] !JNUAA] !J-WQBNU1B]@!DXKM88_8 9C> 8KM,8O8 9$ X82?]I
  3600. M 0H82?]I 4PS$PJ-X1@XKMP8O0 :KML8_0 :.*[9&/T &ABNVAA] !H0#AA)
  3601. M_VD!2AA)_VD!3&(32ABNUQA]@!DXKM@8_8 9C>(8.*[9&+V &:[:&/V &3BN
  3602. MVQC]@!DXKMP8_8 9$ X82?]I 4H82?]I 4R?$TH8KM<8?0 :&*[8&'T &HWC
  3603. M&*[=&+V &3BNWAC]@!F-Y!BNVAB]@!DXKMP8_8 9.*[;&/V &3BNV1C]@!D0
  3604. M#AA)_VD!2AA)_VD!3.P32ABNV!A] !HXKM<8_0 :C>48&*[:&+T &J[;&'T 
  3605. M&CBNV1C] !HXKMP8_0 :$ X82?]I 4H82?]I 4PI%$H8KM<8?8 9&*[8&'V 
  3606. M&8WF&!BNW1B] !JNWAA] !J-YQBMWQB-Z!BMX!B-Z1BMX1B-ZABMXAB-ZQBM
  3607. MXQB-[!BMY!B-[1BMY1B-[ABMYAB-[QBMYQB-\!@@G1:NNQBLO!B.OQB,P!@8
  3608. MK> 82?]I 8WI&!BMXQA)_VD!C>P8&*WF&$G_:0&-[Q@@G1:NNQBLO!B.P1B,
  3609. MPA@8K=\82?]I 8WH&!BMXAA)_VD!C>L8&*WE&$G_:0&-[A@@G1:NNQBLO!B.
  3610. MPQB,Q!BMX!B-Z1BMXQB-[!BMYAB-[Q@@G1:NNQBLO!B.Q1B,QA@8K>$82?]I
  3611. M 8WJ&!BMY!A)_VD!C>T8&*WG&$G_:0&-\!@@G1:NNQBLO!B.S1B,SA@8K> 8
  3612. M2?]I 8WI&!BMXQA)_VD!C>P8&*WF&$G_:0&-[Q@@G1:NNQBLO!B.RQB,S!BM
  3613. MWQB-Z!BMXAB-ZQBMY1B-[A@@G1:NNQBLO!B.R1B,RABMX!B-Z1BMXQB-[!BM
  3614. MYAB-[Q@@G1:NNQBLO!B.QQB,R!BI (6CI0*%I*D H@B@ )&CR-#[YJ3*T/:E
  3615. MI*V_&(V[&*W &(V\&*W!&(V]&*W"&(V^&"".%ZW#&(V[&*W$&(V\&"".%ZW%
  3616. M&(V]&*W&&(V^&"".%ZV_&(V[&*W &(V\&"".%ZW'&(V]&*W(&(V^&"".%ZW)
  3617. M&(V[&*W*&(V\&"".%ZW!&(V]&*W"&(V^&"".%ZW+&(V]&*W,&(V^&"".%ZW#
  3618. M&(V[&*W$&(V\&"".%ZW-&(V[&*W.&(V\&"".%ZW%&(V]&*W&&(V^&"".%ZW'
  3619. M&(V]&*W(&(V^&"".%ZT8T$D"C1C0J0A% H4"3,41&*WN&&WO&!AM\!@8:8"J
  3620. MO8 :A?R%_ABMZ!AMZ1@8;>H8A?L@Z!88I?MI0(V[&!BE_H7\K>L8;>P8&&WM
  3621. M&(7[(.@6&*7[:4"-O!A@&*7[1?PP-:7[$ U)_VD!A?L8I?Q)_VD!J0"@"4IF
  3622. M^Y #&&7\B-#U2F;[2F;[2F;[2F;[2F;[2F;[A?U@I?LP"ABE_$G_:0%,.!=)
  3623. M_VD!A?NI * )2F;[D ,89?R(T/5*9OM*9OM*9OM*9OM*9OM*9ON%_:7[$ ,@
  3624. M:1=)_VD!A?M@H@"]>!?P!R#2_^A,:Q=@#5-/34542$E.1R!#2$]+140@.B@-
  3625. M *V[&(7[K;T8A?VMO!B%_*V^&(7^J0"%HZ4"A:0XI?WE^[ 2I?ZD_(7\A/ZE
  3626. M^Z3]A/N%_>7[A?FF^Z7[2DI*2I %H("$HQAEI(6D.*7^Y?RP!*7\Y?Z%^L7Y
  3627. ML%BD_+T &1&CD:.E^4I)_VD!Q/ZP(NAE^I #R.7Y2+T &1 *1:.%HS "YJ2I
  3628. M@!&CD:-HY/W0WV#H9?J0 XCE^4B] !D0"D6CA:,P N:DJ8 1HY&C:.3]T-]@
  3629. MI/R] !D1HY&CI?I*2?]I <3^L"[(9?F0&^CE^DB] !D0"D6CA:,P N:DJ8 1
  3630. MHY&C:$Q^&$B] !D1HY&C:,3^T--@B!AE^9 ;Z.7Z2+T &1 *1:.%HS "YJ2I
  3631. M@!&CD:-H3*T82+T &1&CD:-HQ/[0TF"M&- I]8T8T&                  
  3632. M                                                            
  3633. M              " 0" 0" 0" 8! (! (! (!@$ @$ @$ @& 0" 0" 0" 8! 
  3634. M(! (! (!@$ @$ @$ @& 0" 0" 0" 8! (! (! (!@$ @$ @$ @& 0" 0" 0"
  3635. M 8! (! (! (!@$ @$ @$ @& 0" 0" 0" 8! (! (! (!@$ @$ @$ @& 0" 0
  3636. M" 0" 0                                                      
  3637. M                                                            
  3638. H                                                        
  3639.  
  3640. end
  3641.  
  3642. begin 666 cube3d.s
  3643. M ' J*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*@TJH*"@H*"@H*"@
  3644. MH*"@H*"@H*"@H*"@H*"@H*"@H*"@*@TJH'-415!(14Z@:E5$1*"@H*"@H*"@
  3645. MH*"@H*"@H*"@*@TJH&=%3U)'1:!T05E,3U*@H*"@H*"@H*"@H*"@H*"@*@TJ
  3646. MH'-405)4140ZH#<O,3$O.32@H*"@H*"@H*"@H*"@*@TJH&9)3DE32$5$.J W
  3647. M+S$Y+SDTH*"@H*"@H*"@H*"@*@TJH*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@
  3648. MH*"@H*"@*@TJH'=%3$PLH$E&H$%,3*!'3T53H%=%3$R@5$A)4Z"@*@TJH%!2
  3649. M3T=204V@5TE,3*!23U1!5$6@0:!#54)%+J"@*@TJH*"@H*"@H*"@H*"@H*"@
  3650. MH*"@H*"@H*"@H*"@H*"@*@TJH'1(25.@4%)/1U)!3:!)4Z!)3E1%3D1%1*!4
  3651. M3Z"@*@TJH$%#0T]-4$%.6:!42$6@05)424-,1:!)3J"@H*"@*@TJH&,]:$%#
  3652. M2TE.1RR@:E5,6: Y-*!)4U-512Z@H*"@*@TJH&9/4J!$151!24Q3H$].H%1(
  3653. M25.@4%)/1U)!32R@*@TJH%)%042@5$A%H$%25$E#3$4AH*"@H*"@H*"@H*"@
  3654. M*@TJH*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@*@TJH'=2251%H%1/
  3655. MH%53(:"@H*"@H*"@H*"@H*"@H*"@*@TJH*"@H*"@H*"@H*"@H*"@H*"@H*"@
  3656. MH*"@H*"@H*"@*@TJH%5.*$)%12E-3Z"@H*"@H*"@H*"@H*"@H*"@H*"@*@TJ
  3657. MH*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@*@TJH%9)H*"@H*"@H*"@
  3658. MH*"@H*"@H*"@H*"@H*"@H*"@*@TJH$XH24XI1Z"@H*"@H*"@H*"@H*"@H*"@
  3659. MH*"@H*"@*@TJH$%212A42*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@*@TJH$4I
  3660. M64]5*$^@H*"@H*"@H*"@H*"@H*"@H*"@H*"@*@TJH$Y,62F@H*"@H*"@H*"@
  3661. MH*"@H*"@H*"@H*"@H*"@*@TJH*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@H*"@
  3662. MH*"@*@TJH$%33"A23U-%*45%4*"@H*"@H*"@H*"@H*"@H*"@*@TJH*"@H*"@
  3663. MH*"@H*"@H*!%+D4N0U5-34E.1U.@H*"@*@TJH*"@H*"@H*"@H*"@H*"@H*"@
  3664. MH*"@H*"@H*"@H*"@*@TJH' N<RZ@=$A)4Z!705.@5U))5%1%3J!54TE.1Z"@
  3665. M*@TJH*"@H*"@;4523$E.H#$R."Z@H'=)5$B@0:"@H*"@*@TJH*"@H*"@3$E4
  3666. M5$Q%H$U/1$E&24-!5$E/3J!)5*"@*@TJH*"@H*"@5TE,3*!73U)+H$9)3D6@
  3667. M5TE42*"@H*"@*@TJH*"@H*"@;4523$E.H#8T+J"@:4:@64]5H*"@H*"@*@TJ
  3668. MH*"@H*"@1$].)U2@2$%61:!%251(15(N+BZ@H*"@*@TJH*"@H*"@5T5,3"R@
  3669. M5T6@04Q,H$A!5D6@3U52H*"@*@TJH*"@H*"@3$E45$Q%H$9!54Q44RZ@H*"@
  3670. MH*"@H*"@*@TJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*BHJ*@T-(&]R
  3671. M9R D,3 P, T-*J!C3TY35$%.5%,-#6)U9F8Q(&5Q=2 D,S P," [9DE24U2@
  3672. M0TA!4D%#5$52H%-%5 UB=69F,B!E<74@)#,X,# @.W-%0T].1*!#2$%204-4
  3673. M15*@4T54#6)U9F9E<B!E<74@)&$S(#MP4D5354U!0DQ9H%1(1:!405!%H%=/
  3674. M3B=4H$)%H%)53DY)3D<->#$@97%U("1F8B [<$])3E13H$9/4J!$4D%724Y'
  3675. MH$&@3$E.10UY,2!E<74@)&9C(#MT2$531:!:15)/H%!!1T6@041$4D534T53
  3676. M#7@R(&5Q=2 D9F0@.T1/3B=4H$-/3D9,24-4H%=)5$B@8F%S:6,->3(@97%U
  3677. M("1F90UD>"!E<74@)&8Y#61Y(&5Q=2 D9F$-=&5M<#$@97%U("1F8B [;T:@
  3678. M0T]54E-%+*!#3U5,1*!#3TY&3$E#5*!7251(H%@Q#71E;7 R(&5Q=2 D9F,@
  3679. M.W1%35!/4D%26:!605))04),15,-86-C(&5Q=2 D9F(@.W1(15-%H$9/55*@
  3680. M5D%224%"3$53H$%21:!54T5$#6%U>"!E<74@)&9C(#M"6:!42$6@355,5$E0
  3681. M3$E#051)3TZ@4D]55$E.10UE>'0@97%U("1F9 UR96T@97%U("1F90UZ=&5M
  3682. M<"!E<74@)# R(#MU4T5$H$9/4J!"549&15*@4U=!4"Z@H&1/3B=4H%1/54-(
  3683. M+@T-86YG;6%X(&5Q=2 Q,C @.W1(15)%H$%21: R*E!)+T%.1TU!6*!!3D=,
  3684. M15,-;V9F<V5T(&5Q=2 V(#MF3$]!5*!/1D93150ZH%@]6$%#5%5!3"HR7D]&
  3685. M1E-%5 T-*J!V:6,-#79M8W-B(&5Q=2 D9# Q. UB:V=N9"!E<74@)&0P,C -
  3686. M8F]R9&5R(&5Q=2 D9# R,0US<W1A<G0@97%U(#$S-#0@.U)/5Z YH$E.H%-#
  3687. M4D5%3J!-14U/4EF@052@,3 R- T-#2J@:T523D%,#0UC:')O=70@97%U("1F
  3688. M9F0R#6=E=&EN(&5Q=2 D9F9E- T-*BHJH&U!0U)/4PT-;6]V92!M86,-(&QD
  3689. M82!=,0T@<W1A(%TR#2 \/#P-#6=E=&ME>2!M86,@(#MW04E4H$9/4J!!H$M%
  3690. M65!215-3#7=A:70@:G-R(&=E=&EN#2!C;7 @(S P#2!B97$@=V%I= T@/#P\
  3691. M#0UD96)U9R!M86,@(#MP4DE.5*!!H$-(05)!0U1%4@V@(&1OH# @(#MD3TXG
  3692. M5*!!4U-%34),10T-(&QD82 C73$-(&IS<B!C:')O=70-(#X^/B!G971K97D@
  3693. M.V%.1*!704E4H%1/H$-/3E1)3E5%#2!C;7 @(R=3)R [;5F@4T5#4D5#5*!3
  3694. M5TE40TB@2T59#2!B;F4@;#$-(&IS<B!C;&5A;G5P#2!J;7 @9&]N90UL,2!C
  3695. M;7 @(R=8)R [;5F@4T5#4D54H$%"3U)4H$M%60T@8FYE(&1O;F4-(&IM<"!C
  3696. M;&5A;G5P#2!F:6X-9&]N92 \/#P-#61E8G5G82!M86,-(&1OH# -(&QD82!=
  3697. M,0T@<W1A(#$P,C0-(&9I;@UD;VYE82 \/#P-#7-E=&)U9B!M86,@(#MP552@
  3698. M0E5&1D524Z!72$521:!42$59H$-!3J!"1:!(55)4#2!L9&$@(S P#2!S=&$@
  3699. M8G5F9F5R#2!L9&$@>G1E;7 @.UI414U0H$-/3E1!24Y3H%1(1:!(24=(H$)9
  3700. M5$6@2$5210T@<W1A(&)U9F9E<BLQ#2 \/#P-#2HM+2TM+2TM+2TM+2TM+2TM
  3701. M+2TM+2TM+2TM+2TM+2TM#0T@;&1A(",D,# -('-T82!B:V=N9 T@<W1A(&)O
  3702. M<F1E<@T@;&1A('9M8W-B#2!A;F0@(R4P,# P,3$Q,2 [<T-2145.H$U%34]2
  3703. M6:!43Z Q,#(T#2!O<F$@(R4P,# Q,# P, T@<W1A('9M8W-B#0T@;&1Y(",P
  3704. M, T@;&1A(",\='1E>'0-('-T82!T96UP,0T@;&1A(",^='1E>'0-('-T82!T
  3705. M96UP,@T@:FUP('1I=&QE#71T97AT(&AE>" Y,S U,3$Q,3$Q(#M#3$5!4J!3
  3706. M0U)%14XLH%=(251%+*!#4E-2H$1.#2!T>'0@)Z"@H*"@H*"@H*"@H*"@H$-5
  3707. M0D4S1"<L,$0L,$0-('1X=" GH*"@H*"@H*"@H*"@H*"@H*!"62<L,$0-(&AE
  3708. M>" Y9B [0UE!3@T@='AT(">@H*"@4U1%4$A%3J!*541$)PT@:&5X(#DY#2!T
  3709. M>'0@)Z"@H*!'14]21T6@5$%93$]2)RPP1"PP1 T@:&5X(#EB#2!T>'0@)Z"@
  3710. M0TA%0TN@3U54H%1(1:!*54Q9H#DTH$E34U5%H$]&)RPP1 T@:&5X(#DV#2!T
  3711. M>'0@)Z"@0SU(04-+24Y')PT@:&5X(#EB#2!T>'0@)Z!&3U*@34]21:!$151!
  3712. M24Q3(2<L,$0-(&AE>" P9#%D,60Y93$R#2!T>'0@)T8Q+T8R)RPY,@T@='AT
  3713. M(">@+:!)3D,O1$5#H%@M4D]4051)3TXG+#!$#2!H97@@,60Q9#$R#2!T>'0@
  3714. M)T8S+T8T)RPY,@T@='AT(">@+:!)3D,O1$5#H%DM4D]4051)3TXG+#!$#2!H
  3715. M97@@,60Q9#$R#2!T>'0@)T8U+T8V)RPY,@T@='AT(">@+:!)3D,O1$5#H%HM
  3716. M4D]4051)3TXG+#!$#2!H97@@,60Q9#$R#2!T>'0@)T8W)RPY,@T@='AT(">@
  3717. M4D531513)RPP1 T@='AT(">@H%!215-3H%&@5$^@455)5"<L,$0-(&AE>" P
  3718. M9# U#2!T>'0@)Z"@H*"@H%!215-3H$%.6:!+15F@5$^@0D5'24XG+#!$#2!H
  3719. M97@@,# -=&ET;&4@;&1A("AT96UP,2DL>0T@8F5Q(#IC;VYT#2!J<W(@8VAR
  3720. M;W5T#2!I;GD-(&)N92!T:71L90T@:6YC('1E;7 R#2!J;7 @=&ET;&4-.F-O
  3721. M;G0@/CX^(&=E=&ME>0T-*BHJ*J!S152@55"@5$%"3$53*#\I#0TJH'1!0DQ%
  3722. M4Z!!4D6@0U524D5.5$Q9H%-%5*!54*!)3J!B87-I8PTJH$%.1*!"6:!42$6@
  3723. M05-314U"3$52+@T-=&%B;&5S#0TJ*BHJH&-,14%2H%-#4D5%3J!!3D2@4T54
  3724. MH%50H")"251-05 B#0US971U<"!L9&$@(S$T-PT@:G-R(&-H<F]U= T@;&1A
  3725. M(",\<W-T87)T#2!A9&,@(S$R(#MT2$6@1T]!3*!)4Z!43Z!#14Y415*@5$A%
  3726. MH$=205!(24-3#2!S=&$@=&5M<#$@.V-/3%5-3J Q,@T@;&1A(",^<W-T87)T
  3727. M(#MR3U>@.0T@<W1A('1E;7 Q*S$@.W-S=&%R=*!03TE.5%.@5$^@4D]7H#D-
  3728. M(&QD82 C,# -(&QD>2 C,# -(&QD>" C,# @.UB@5TE,3*!#3U5.5* Q-J!2
  3729. M3U=3H$9/4J!54PT@8VQC#0TZ;&]O<"!S=&$@*'1E;7 Q*2QY#2!I;GD-(&%D
  3730. M8R C,38-(&)C8R Z;&]O< T@8VQC#2!L9&$@=&5M<#$-(&%D8R C-# @.VY%
  3731. M142@5$^@041$H#0PH%1/H%1(1:!"05-%H%!/24Y415(-('-T82!T96UP,2 [
  3732. M=$^@2E5-4*!43Z!42$6@3D585*!23U<-(&QD82!T96UP,2LQ#2!A9&,@(S P
  3733. M(#MT04M%H$-!4D6@3T:@0T%24DE%4PT@<W1A('1E;7 Q*S$-(&QD>2 C,# -
  3734. M(&EN> T@='AA(" [>*!)4Z!!3%-/H$%.H$E.1$58H$E.5$^@5$A%H$-(05)!
  3735. M0U1%4J!.54U"15(-(&-P>" C,38-(&)N92 Z;&]O<" [;D5%1*!43Z!$3Z!)
  3736. M5* Q-J!424U%4PT-(#X^/B!D96)U9RPG,B<-*BHJ*J!S152@55"@0E5&1D52
  3737. M4PT-(&QD82 C/&)U9F8Q#2!S=&$@8G5F9F5R#2!L9&$@(SYB=69F,0T@<W1A
  3738. M(&)U9F9E<BLQ#2!S=&$@>G1E;7 @.UI414U0H%=)3$R@34%+1:!,249%H%-)
  3739. M35!,1:!&3U*@55,-(&QD82!V;6-S8@T@86YD(",E,3$Q,3 P,#$@.W-405)4
  3740. MH$A%4D6@4T^@5$A!5*!35T%0H$)51D9%4E.@5TE,3*!73U)+H%))1TA4#2!O
  3741. M<F$@(R4P,# P,3$Q, T@<W1A('9M8W-B#0T-*BHJ*J!S152@55"@24Y)5$E!
  3742. M3*!604Q515,-#6EN:70@;&1A(",P, T@<W1A(&1S> T@<W1A(&1S>0T@<W1A
  3743. M(&1S>@T@<W1A('-X#2!S=&$@<WD-('-T82!S>@T-(#X^/B!D96)U9RPG-"<-
  3744. M#2HM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM#2J@;4%)3J!,3T]0
  3745. M#0TJ*BHJH&=%5*!+15E04D534PT-;6%I;@UK<')E<W,@:G-R(&=E=&EN#2!C
  3746. M;7 @(S$S,R [9C$_#2!B;F4@.F8R#2!L9&$@9'-X#2!C;7 @(V%N9VUA>"\R
  3747. M(#MN3Z!-3U)%H%1(04Z@4$D-(&)E<2 Z8V]N= T@:6YC(&1S>" [3U1(15)7
  3748. M25-%H$E.0U)%05-%H%@M4D]4051)3TX-(&IM<" Z8V]N= TZ9C(@8VUP(",Q
  3749. M,S<@.V8R/PT@8FYE(#IF,PT@;&1A(&1S> T@8F5Q(#IC;VYT#2!D96,@9'-X
  3750. M#2!J;7 @.F-O;G0-.F8S(&-M<" C,3,T#2!B;F4@.F8T#2!L9&$@9'-Y#2!C
  3751. M;7 @(V%N9VUA>"\R#2!B97$@.F-O;G0-(&EN8R!D<WD@.VE.0U)%05-%H%DM
  3752. M4D]4051)3TX-(&IM<" Z8V]N= TZ9C0@8VUP(",Q,S@-(&)N92 Z9C4-(&QD
  3753. M82!D<WD-(&)E<2 Z8V]N= T@9&5C(&1S>0T@:FUP(#IC;VYT#3IF-2!C;7 @
  3754. M(S$S-0T@8FYE(#IF-@T@;&1A(&1S>@T@8VUP("-A;F=M87@O,@T@8F5Q(#IC
  3755. M;VYT#2!I;F,@9'-Z(#M:+5)/5$%424].#2!J;7 @.F-O;G0-.F8V(&-M<" C
  3756. M,3,Y#2!B;F4@.F8W#2!L9&$@9'-Z#2!B97$@.F-O;G0-(&1E8R!D<WH-(&IM
  3757. M<" Z8V]N= TZ9C<@8VUP(",Q,S8-(&)N92 Z<0T@:FUP(&EN:70-.G$@8VUP
  3758. M(",G42<@.U&@455)5%,-(&)N92 Z8V]N= T@:FUP(&-L96%N=7 -#3IC;VYT
  3759. M#2J@/CX^H&1E8G5G+"<U)PT-*BHJ*J!U4$1!5$6@04Y'3$53#0UU<&1A=&4@
  3760. M8VQC#2!L9&$@<W@-(&%D8R!D<W@-(&-M<" C86YG;6%X(#MA4D6@5T6@/CV@
  3761. M34%824U53:!!3D=,13\-(&)C8R Z8V]N=#$-('-B8R C86YG;6%X(#II1B!3
  3762. M3RP@4D53150-.F-O;G0Q('-T82!S> T@8VQC#2!L9&$@<WD-(&%D8R!D<WD-
  3763. M(&-M<" C86YG;6%X#2!B8V,@.F-O;G0R#2!S8F,@(V%N9VUA>" [<T%-1:!$
  3764. M14%,#3IC;VYT,B!S=&$@<WD-(&-L8PT@;&1A('-Z#2!A9&,@9'-Z#2!C;7 @
  3765. M(V%N9VUA> T@8F-C(#IC;VYT,PT@<V)C("-A;F=M87@-.F-O;G0S('-T82!S
  3766. M>@T-#2HJ*BJ@<D]4051%H$-/3U)$24Y!5$53#0UR;W1A=&4-#2HJ*J!F25)3
  3767. M5"R@0T%,0U5,051%H%0Q+%0R+"XN+BQ4,3 -#2HJH'173Z!-04-23U.@5$^@
  3768. M4TE-4$Q)1EF@3U52H$Q)1D4-861D82!M86,@(#MA1$2@5%=/H$%.1TQ%4Z!4
  3769. M3T=%5$A%4@T@8VQC#2!L9&$@73$-(&%D8R!=,@T@8VUP("-A;F=M87@@.VE3
  3770. MH%1(1:!354V@/J R*E!)/PT@8F-C(&1O;F4-('-B8R C86YG;6%X(#MI1J!3
  3771. M3RR@4U5"5%)!0U2@,BI020UD;VYE(#P\/ T-<W5B82!M86,@(#MS54)44D%#
  3772. M5*!45T^@04Y'3$53#2!S96,-(&QD82!=,0T@<V)C(%TR#2!B8W,@9&]N90T@
  3773. M861C("-A;F=M87@@.V]/4%,LH%=%H$Y%142@5$^@041$H#(J4$D-9&]N92 \
  3774. M/#P-#2HJH&Y/5Z!#04Q#54Q!5$6@5#$L5#(L151#+@T-(#X^/B!S=6)A+'-Y
  3775. M.W-Z#2!S=&$@=#$@.U0Q/5-9+5-:#2 ^/CX@861D82QS>3MS>@T@<W1A('0R
  3776. M(#M4,CU362M36@T@/CX^(&%D9&$L<W@[<WH-('-T82!T,R [5#,]4U@K4UH-
  3777. M(#X^/B!S=6)A+'-X.W-Z#2!S=&$@=#0@.U0T/5-8+5-:#2 ^/CX@861D82QS
  3778. M>#MT,@T@<W1A('0U(#M4-3U36"M4,@T@/CX^('-U8F$L<W@[=#$-('-T82!T
  3779. M-B [5#8]4U@M5#$-(#X^/B!A9&1A+'-X.W0Q#2!S=&$@=#<@.U0W/5-8*U0Q
  3780. M#2 ^/CX@<W5B82QT,CMS> T@<W1A('0X(#M4.#U4,BU36 T@/CX^('-U8F$L
  3781. M<WD[<W@-('-T82!T.2 [5#D]4UDM4U@-(#X^/B!A9&1A+'-X.W-Y#2!S=&$@
  3782. M=#$P(#M4,3 ]4U@K4UD-#2J@952@5D])3$$A#0TJ*BJ@;D585"R@0T%,0U5,
  3783. M051%H&$L8BQC+"XN+BQI#0TJ*J!A3D]42$52H%5314953*!,25143$6@34%#
  3784. M4D\-9&EV,B!M86,@(#MD259)1$6@0:!324=.142@3E5-0D52H$)9H#(-.VE4
  3785. MH$E3H$%34U5-142@5$A!5*!42$6@3E5-0D52#2!B<&P@<&]S(#M)4Z!)3J!4
  3786. M2$6@04-#54U53$%43U(-(&-L8PT@96]R(",D9F8@.W=%H$Y%142@5$^@54XM
  3787. M3D5'051)5D6@5$A%H$Y534)%4@T@861C(",P,2 [0EF@5$%+24Y'H$E4)U.@
  3788. M0T]-4$Q%345.5 T@;'-R(" [1$E6241%H$)9H%173PT@8VQC#2!E;W(@(R1F
  3789. M9@T@861C(",P,2 [;4%+1:!)5*!.14=!5$E61:!!1T%)3@T@:FUP(&1O;F5D
  3790. M:78-<&]S(&QS<B @.VY534)%4J!)4Z!03U-)5$E610UD;VYE9&EV(#P\/ T-
  3791. M;75L,B!M86,@(#MM54Q425!,6:!!H%-)1TY%1*!.54U"15*@0EF@,@T@8G!L
  3792. M('!O<VT-(&-L8PT@96]R(",D9F8-(&%D8R C)# Q#2!A<VP-(&-L8PT@96]R
  3793. M(",D9F8-(&%D8R C)# Q#2!J;7 @9&]N96UU; UP;W-M(&%S; UD;VYE;75L
  3794. M(#P\/ T-*BJ@;D]41:!42$%4H%=%H$%21:!#55)214Y43%F@34%+24Y'H$&@
  3795. M34E.3U*@3$5!4 TJ*J!/1J!&04E42*!42$%4H$Y/H$]615)&3$]74Z!724Q,
  3796. MH$]#0U52+@T-.F-A;&-A(&-L8PT@;&1X('0Q#2!L9&$@8V]S+'@-(&QD>"!T
  3797. M,@T@861C(&-O<RQX#2!S=&$@83$Q(#MA/2A#3U,H5#$I*T-/4RA4,BDI+S(-
  3798. M.F-A;&-B(&QD>"!T,0T@;&1A('-I;BQX#2!S96,-(&QD>"!T,@T@<V)C('-I
  3799. M;BQX#2!S=&$@8C$R(#MB/2A324XH5#$I+5-)3BA4,BDI+S(-.F-A;&-C(&QD
  3800. M>"!S>0T@;&1A('-I;BQX#2 ^/CX@;75L,@T@<W1A(&,Q,R [8SU324XH4UDI
  3801. M#3IC86QC9"!S96,-(&QD>"!T. T@;&1A(&-O<RQX#2!L9'@@=#<-('-B8R!C
  3802. M;W,L> T@<V5C#2!L9'@@=#4-('-B8R!C;W,L> T@8VQC#2!L9'@@=#8-(&%D
  3803. M8R!C;W,L>" [9$D]*$-/4RA4."DM0T]3*%0W*2M#3U,H5#8I+4-/4RA4-2DI
  3804. M+S(-(#X^/B!D:78R#2!C;&,-(&QD>"!T,PT@861C('-I;BQX#2!S96,-(&QD
  3805. M>"!T- T@<V)C('-I;BQX#2!S=&$@9#(Q(#MD/2A324XH5#,I+5-)3BA4-"DK
  3806. M9$DI+S(-.F-A;&-E('-E8PT@;&1X('0U#2!L9&$@<VEN+'@-(&QD>"!T-@T@
  3807. M<V)C('-I;BQX#2!S96,-(&QD>"!T-PT@<V)C('-I;BQX#2!S96,-(&QD>"!T
  3808. M. T@<V)C('-I;BQX(#ME23TH4TE.*%0U*2U324XH5#8I+5-)3BA4-RDM4TE.
  3809. M*%0X*2DO,@T@/CX^(&1I=C(-(&-L8PT@;&1X('0S#2!A9&,@8V]S+'@-(&-L
  3810. M8PT@;&1X('0T#2!A9&,@8V]S+'@-('-T82!E,C(@.V4]*$-/4RA4,RDK0T]3
  3811. M*%0T*2ME22DO,@TZ8V%L8V8@;&1X('0Y#2!L9&$@<VEN+'@-('-E8PT@;&1X
  3812. M('0Q, T@<V)C('-I;BQX#2!S=&$@9C(S(#MF/2A324XH5#DI+5-)3BA4,3 I
  3813. M*2\R#3IC86QC9R!L9'@@=#8-(&QD82!S:6XL> T@<V5C#2!L9'@@=#@-('-B
  3814. M8R!S:6XL> T@<V5C#2!L9'@@=#<-('-B8R!S:6XL> T@<V5C#2!L9'@@=#4-
  3815. M('-B8R!S:6XL>" [9TD]*%-)3BA4-BDM4TE.*%0X*2U324XH5#<I+5-)3BA4
  3816. M-2DI+S(-(#X^/B!D:78R#2!C;&,-(&QD>"!T- T@861C(&-O<RQX#2!S96,-
  3817. M(&QD>"!T,PT@<V)C(&-O<RQX#2!S=&$@9S,Q(#MG/2A#3U,H5#0I+4-/4RA4
  3818. M,RDK9TDI+S(-(#X^/B!D96)U9V$L9S,Q#2 ^/CX@9&5B=6<L)T<G#3IC86QC
  3819. M:"!C;&,-(&QD>"!T-@T@;&1A(&-O<RQX#2!L9'@@=#<-(&%D8R!C;W,L> T@
  3820. M<V5C#2!L9'@@=#4-('-B8R!C;W,L> T@<V5C#2!L9'@@=#@-('-B8R!C;W,L
  3821. M>" [:$D]*$-/4RA4-BDK0T]3*%0W*2U#3U,H5#4I+4-/4RA4."DI+S(-(#X^
  3822. M/B!D:78R#2!C;&,-(&QD>"!T,PT@861C('-I;BQX#2!C;&,-(&QD>"!T- T@
  3823. M861C('-I;BQX#2!S=&$@:#,R(#MH/2A324XH5#,I*U-)3BA4-"DK:$DI+S(-
  3824. M.G=H97<@8VQC#2!L9'@@=#D-(&QD82!C;W,L> T@;&1X('0Q, T@861C(&-O
  3825. M<RQX#2!S=&$@:3,S(#MI/2A#3U,H5#DI*T-/4RA4,3 I*2\R#0TJ*J!I5"=3
  3826. MH$%,3*!$3U=.2$E,3*!&4D]-H$A%4D4N#0TJ*J!R3U1!5$4LH%!23TI%0U0L
  3827. MH$%.1*!35$]21:!42$6@4$])3E13#61O=VYH:6QL(&QD82!A,3$@.W1(25.@
  3828. M25.@1T545$E.1Z!43Z!"1:!!H%)%04R@34534PT@<W1A('1A#2!L9&$@8C$R
  3829. M(#MT2$6@4D5!4T].H%1(25.@25.@1$].10T@<W1A('1B(#M)4Z!43Z!-04M%
  3830. MH%1(1:!#3T1%H$&@3$E45$Q%#2!L9&$@8S$S(#M%05-)15*@5$^@4D5!1* H
  3831. M04Y$H$1%0E5'(2D-('-T82!T8PT@;&1A(&0R,2 [=$A%4T6@05)%H$%,3*!4
  3832. M14U03U)!4EF@3$]#051)3TY3#2!S=&$@=&0@.W53142@0EF@5$A%H%!23TI%
  3833. M0U1)3TZ@4U5"4D]55$E.12X-(&QD82!E,C(-('-T82!T92 [;U1(15)725-%
  3834. M+*!42$521:!73U5,1*!"1:!%24=(5 T@;&1A(&8R,R [3$].1Z!23U5424Y%
  3835. M4Z!(15)%+@T@<W1A('1F#2!L9&$@9S,Q(#MB552@252@5T]53$2@0D6@4TE'
  3836. M3DE&24-!3E1,6:!&05-415(-('-T82!T9PT@;&1A(&@S,@T@<W1A('1H#2!L
  3837. M9&$@:3,S#2!S=&$@=&D-#2J@8:!.14%4H$U!0U)/#6YE9R!M86,@(#MC2$%.
  3838. M1T6@5$A%H%-)1TZ@3T:@0:!45T\G4Z!#3TU03$5-14Y4#2!C;&,-(&QD82!=
  3839. M,2 [3E5-0D52+@T@96]R(",D9F8-(&%D8R C)# Q#2 \/#P-#2J@<#$]6S&@
  3840. M,: Q70T@:G-R('!R;VIE8W0@.W5.4D],3*!42$E3H%=(3TQ%H%1(24Y'#2!L
  3841. M9'@@='@Q(#LH4T]24EF@04)/552@5$A%4T6@5%=/H$Q)3D53*0T@;&1Y('1Y
  3842. M,2 [*%-%1:!P<F]J96-TH$9/4J!214%33TZ@5TA9*0T@<W1X(' Q>" [9D]2
  3843. MH$&@4%)%5%19H$))1Z!34$5%1*!)3D-214%312$-('-T>2!P,7D-*J!P,CU;
  3844. M,: M,: Q70T@/CX^(&YE9RQB,3(@.V-(04Y'1:!42$531:!%3$5-14Y44PT@
  3845. M<W1A('1B#2 ^/CX@;F5G+&4R,B [<TE.0T6@6:!)4Z!.3U>@+3$-('-T82!T
  3846. M90T@/CX^(&YE9RQH,S(-('-T82!T: T@:G-R('!R;VIE8W0-(&QD>"!T>#$-
  3847. M(&QD>2!T>3$-('-T>"!P,G@-('-T>2!P,GD-*J!P,SU;+3&@+3&@,5T-(#X^
  3848. M/B!N96<L83$Q#2!S=&$@=&$-(#X^/B!N96<L9#(Q#2!S=&$@=&0-(#X^/B!N
  3849. M96<L9S,Q#2!S=&$@=&<-(&IS<B!P<F]J96-T#2!L9'@@='@Q#2!L9'D@='DQ
  3850. M#2!S='@@<#-X#2!S='D@<#-Y#2J@<#0]6RTQH#&@,5T-(&QD82!B,3(-('-T
  3851. M82!T8@T@;&1A(&4R,@T@<W1A('1E#2!L9&$@:#,R#2!S=&$@=&@-(&IS<B!P
  3852. M<F]J96-T#2!L9'@@='@Q#2!L9'D@='DQ#2!S='@@<#1X#2!S='D@<#1Y#2J@
  3853. M<#@]6RTQH#&@+3%=#2 ^/CX@;F5G+&,Q,PT@<W1A('1C#2 ^/CX@;F5G+&8R
  3854. M,PT@<W1A('1F#2 ^/CX@;F5G+&DS,PT@<W1A('1I#2!J<W(@<')O:F5C= T@
  3855. M;&1X('1X,0T@;&1Y('1Y,0T@<W1X(' X> T@<W1Y(' X>0TJH' W/5LM,: M
  3856. M,: M,5T-(#X^/B!N96<L8C$R#2!S=&$@=&(-(#X^/B!N96<L93(R#2!S=&$@
  3857. M=&4-(#X^/B!N96<L:#,R#2!S=&$@=&@-(&IS<B!P<F]J96-T#2!L9'@@='@Q
  3858. M#2!L9'D@='DQ#2!S='@@<#=X#2!S='D@<#=Y#2J@<#8]6S&@+3&@+3%=#2!L
  3859. M9&$@83$Q#2!S=&$@=&$-(&QD82!D,C$-('-T82!T9 T@;&1A(&<S,0T@<W1A
  3860. M('1G#2!J<W(@<')O:F5C= T@;&1X('1X,0T@;&1Y('1Y,0T@<W1X(' V> T@
  3861. M<W1Y(' V>0TJH' U/5LQH#&@+3%=#2!L9&$@8C$R#2!S=&$@=&(-(&QD82!E
  3862. M,C(-('-T82!T90T@;&1A(&@S,@T@<W1A('1H#2!J<W(@<')O:F5C= T@;&1X
  3863. M('1X,0T@;&1Y('1Y,0T@<W1X(' U> T@<W1Y(' U>0T-*BHJ*J!C3$5!4J!"
  3864. M549&15(-#2 ^/CX@<V5T8G5F#6-L<F)U9B!L9&$@(R0P," [<%)%5%19H%-4
  3865. M4D%)1TA41D]25T%21"P-(&QD>" C)# X(#MIH%1(24Y+#2!L9'D@(R0P, TZ
  3866. M;&]O<"!S=&$@*&)U9F9E<BDL>0T@:6YY#2!B;F4@.FQO;W -(&EN8R!B=69F
  3867. M97(K,0T@9&5X#2!B;F4@.FQO;W -(&QD82!B=69F97(K,0T-*BHJ*J!F24Y!
  3868. M3$Q9+*!$4D%7H%1(1:!,24Y%4RX-#2!L9&$@<#%X(#M;,: QH#%=#2!S=&$@
  3869. M='@Q#2!L9&$@<#%Y#2!S=&$@='DQ#2!L9&$@<#)X(#M;,: M,: Q70T@<W1A
  3870. M('1X,@T@;&1A(' R>0T@<W1A('1Y,@T@:G-R(&1R87<@.V9)4E-4H$Q)3D4-
  3871. M#2!L9&$@<#-X(#M;+3&@+3&@,5T-('-T82!T>#$-(&QD82!P,WD-('-T82!T
  3872. M>3$-(&IS<B!D<F%W(#MS14-/3D2@3$E.10T-(&QD82!P-'@@.ULM,: QH#%=
  3873. M#2!S=&$@='@R#2!L9&$@<#1Y#2!S=&$@='DR#2!J<W(@9')A=R [=$A)4D2@
  3874. M3$E.10T-(&QD82!P,7@@.ULQH#&@,5T-('-T82!T>#$-(&QD82!P,7D-('-T
  3875. M82!T>3$-(&IS<B!D<F%W(#MF3U525$B@3$E.12Z@H&].1:!&04-%H$1/3D4N
  3876. M#0T@;&1A(' U>" [6S&@,: M,5T-('-T82!T>#(-(&QD82!P-7D-('-T82!T
  3877. M>3(-(&IS<B!D<F%W(#MF259%#0T@;&1A(' V>" [6S&@+3&@+3%=#2!S=&$@
  3878. M='@Q#2!L9&$@<#9Y#2!S=&$@='DQ#2!J<W(@9')A=R [<TE8#0T@;&1A(' R
  3879. M>" [6S&@+3&@,5T-('-T82!T>#(-(&QD82!P,GD-('-T82!T>3(-(&IS<B!D
  3880. M<F%W(#MS159%3@T-(&QD82!P-W@@.ULM,: M,: M,5T-('-T82!T>#(-(&QD
  3881. M82!P-WD-('-T82!T>3(-(&IS<B!D<F%W(#ME24=(5 T-(&QD82!P,W@@.ULM
  3882. M,: M,: Q70T@<W1A('1X,0T@;&1A(' S>0T@<W1A('1Y,0T@:G-R(&1R87<@
  3883. M.VY)3D4-#2!L9&$@<#AX(#M;+3&@,: M,5T-('-T82!T>#$-(&QD82!P.'D-
  3884. M('-T82!T>3$-(&IS<B!D<F%W(#MT14X-#2!L9&$@<#1X(#M;+3&@,: Q70T@
  3885. M<W1A('1X,@T@;&1A(' T>0T@<W1A('1Y,@T@:G-R(&1R87<@.V5,159%3@T-
  3886. M(&QD82!P-7@@.ULQH#&@+3%=#2!S=&$@='@R#2!L9&$@<#5Y#2!S=&$@='DR
  3887. M#2!J<W(@9')A=R [=%=%3%9%(0T-*BHJ*J!S5T%0H$)51D9%4E,-#7-W87!B
  3888. M=68@;&1A('9M8W-B#2!E;W(@(R0P,B [<%)%5%19H%1224-+62R@14@_#2!S
  3889. M=&$@=FUC<V(-(&QD82 C)# X#2!E;W(@>G1E;7 @.UI414U0/4A)1TB@0EE4
  3890. M1:!*55-4H$9,25!3#2!S=&$@>G1E;7 @.T)%5%=%14Z@)#,PH$%.1* D,S@-
  3891. M#2!J;7 @;6%I;B [85)/54Y$H$%.1*!!4D]53D2@5T6@1T\N+BX-#0TJ+2TM
  3892. M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+0TJH'1(25.@4U5"4D]55$E.
  3893. M1:!#04Q#54Q!5$53H%1(1:!04D]*14-424].H$]&H'B@04Y$H'D-#7!R;VIE
  3894. M8W0@8VQC#2!L9&$@=&<-(&%D8R!T: T@8VQC#2!A9&,@=&D@.W1(25.@25.@
  3895. M4D]4051%1*!Z#2!C;&,-(&%D8R C,3(X(#MW1:!!4D6@1T])3D>@5$^@5$%+
  3896. M1: Q,C@K6@TJH#X^/J!D96)U9V$L875X#2J@/CX^H&1E8G5G+"=!)PT@=&%X
  3897. M(" [;D]7H$E4H$E3H%)%0419H$9/4J!)3D1%6$E.1PT@;&1A('ID:78L>" [
  3898. M=$%"3$6@3T:@+40O6@T@<W1A(&%U>" [=$A)4Z!)4Z!&3U*@5$A%H%!23TI%
  3899. M0U1)3TX-('-T82!R96T@.VU53%1)4$Q9H$-!3J!#3$]"0D52H&%U> T-(&-L
  3900. M8PT@;&1A('1A#2!A9&,@=&(-(&-L8PT@861C('1C#2!S=&$@86-C(#MT2$E3
  3901. MH$E3H%)/5$%4142@6 T@:G-R('-M=6QT(#MS24=.142@355,5$E03%F@86-C
  3902. M*F%U>"\R7F]F9G-E= T@8VQC#2!L9&$@86-C#3IC;VYT,2!A9&,@(S8T(#MO
  3903. M1D93152@5$A%H$-/3U)$24Y!5$4-*J!S146@0D5,3U>@1D]2H%1(1:!214%3
  3904. M3TZ@5TA9H%1(25,-*J!.15A4H$E.4U1254-424].H$E3H$-/34U%3E1%1*!/
  3905. M550-*J!T87B@H#MN3U>@>*!)4Z!8(0T@<W1A('1X,0T@8VQC(" [9$^@5$A%
  3906. MH%=(3TQ%H%1(24Y'H$%'04E.H$9/4J!Y#2!L9&$@<F5M#2!S=&$@875X#2!L
  3907. M9&$@=&0-(&%D8R!T90T@8VQC#2!A9&,@=&8-('-T82!A8V,@.W1(25.@25.@
  3908. M4D]4051%1*!9#2!J<W(@<VUU;'0@.W-)1TY%1*!-54Q425!,6:!A8V,J875X
  3909. M+S)>;V9F<V5T#2!C;&,-(&QD82!A8V,-.F-O;G0R(&%D8R C-C0@.V]&1E-%
  3910. M5*!42$6@0T]/4D1)3D%410TJH&9/4J!33TU%H$-/35!,151%3%F@54Y+3D]7
  3911. M3J!214%33TZ@5$^@344-*J!42$6@24Y35%)50U1)3TZ@0D5,3U>@1$]%4TXG
  3912. M5*!73U)++J"@<T]-14A/5PTJH%1(1:!R='.@25.@34]$249924Y'H'B@04Y$
  3913. MH'D_/S\-*J!T87F@H#MS5$]21:!)3J!Y#2!S=&$@='DQ#2!R=',@(#MIH$A/
  3914. M4$6@5$^@2$5#2Z!42$E3H%=/4DM3+@T-*BTM+2TM+2TM+2TM+2TM+2TM+2TM
  3915. M+2TM+2TM+2TM+2T-*J!S;75L=#J@."U"252@4TE'3D5$H"A33U)4+4]&*:!-
  3916. M54Q425!,60TJ#2J@86-C*F%U>"\R7F]F9G-E=* M/J!;86-C+*!E>'1=H* Q
  3917. M-BU"252@4D5354Q4H*!,3RQ(20TJ#2J@;D]41:!42$%4H%1(25.@4D]55$E.
  3918. M1:!$259)1$53H%1(1:!%3D2@4D5354Q4H$)9H#)>;V9F<V5T#0TJH'E54"R@
  3919. M04Y/5$A%4J!-04-23RX-9&EV;V9F(&UA8R @.V1)5DE$1:!"6:!42$6@1DQ/
  3920. M052@3T9&4T54#2!L=7 @;V9F<V5T(#MR15!%052@3T9&4T54H%1)3453#2!L
  3921. M<W(@(#MAH$-/3E1!24Y3H$A)1TB@0EE410T@<F]R(&%C8R [86-CH$E3H$Q/
  3922. M5Z!"651%#2 M+5X-(#P\/ T-#7-M=6QT(&-L8PT@;&1A(&%C8R [9DE24U0L
  3923. MH$E3H%1(1:!215-53%2@4$]3251)5D6@3U*@3D5'051)5D4_#2!E;W(@875X
  3924. M#2!B;6D@.FYE9PT-(&QD82!A8V,@.W1(15F@05)%H$5)5$A%4J!"3U1(H$Y%
  3925. M1T%4259%H$]2#2!B<&P@.F-O;G0Q(#M"3U1(H%!/4TE4259%#2!E;W(@(R1F
  3926. M9B [:4Z@5$A)4Z!#05-%+*!-04M%H%1(14T-(&%D8R C)# Q(#M"3U1(H%!/
  3927. M4TE4259%(0T@<W1A(&%C8PT@/CX^(&YE9RQA=7@@.VQ)5%1,1:!-04-23Z!5
  3928. M4T5$H$5!4DQ)15(N#3IC;VYT,2!L9&$@(S P(#MM54Q425!,6:!42$6@5%=/
  3929. MH$Y534)%4E,-(&QD>2 C)# Y#5UL;V]P(&QS<B @.W)%042@5$A%H$%25$E#
  3930. M3$6@1D]2H$1%5$%)3%,N#2!R;W(@86-C#2!B8V,@.FUU;'0Q(#MO4J!&24=5
  3931. M4D6@252@3U54H%E/55)314Q&(0T@8VQC#2!A9&,@875X#3IM=6QT,2!D97D-
  3932. M(&)N92!=;&]O< T@/CX^(&1I=F]F9B [<D5-3U9%H%1(25.@3$E.1:!&3U*@
  3933. M0:!'14Y%4D%,H$U53%1)4$Q9#2!S=&$@97AT#2!R=',-#3IN96<@;&1A(&%C
  3934. M8R [;TY%H$]&H%1(1:!45T^@25.@3D5'051)5D4-(&)M:2 Z8V]N=#(-(#X^
  3935. M/B!N96<L875X(#MO5$A%4E=)4T6@250G4Z!A=7@-(&IM<" Z8V]N=#,-.F-O
  3936. M;G0R(&5O<B C)&9F(#MT04M%H%173R=3H$-/35!,14U%3E0-(&%D8R C)# Q
  3937. M#2!S=&$@86-C#3IC;VYT,R!L9&$@(S P(#MM54Q425!,60T@;&1Y(",D,#D-
  3938. M76QO;W R(&QS<@T@<F]R(&%C8PT@8F-C(#IM=6QT,@T@8VQC#2!A9&,@875X
  3939. M#3IM=6QT,B!D97D-(&)N92!=;&]O<#(-(#X^/B!D:79O9F8@.V%'04E.+*!$
  3940. M259)1$6@0EF@5$A%H$]&1E-%5 T@<W1A(&5X= T@;&1A(&%C8PT@8G!L(#IO
  3941. M:R [<T]-151(24Y'H$E3H%)%04Q,6:!74D].1Z!)1J!42$E3H$E3H$Y%1T%4
  3942. M259%+@T@:G-R(&-H;VME#3IO:R!E;W(@(R1F9B [;U1(15))4T4LH$5615)9
  3943. M5$A)3D>@4D5,159!3E2@4TA/54Q$#2!A9&,@(R0P,2 [0D6@0T]-4$Q%5$5,
  3944. M6:!)3J!42$6@3$]7H$)95$4N#2!S=&$@86-C#2!R=',@(#MIH$A/4$4N+BX-
  3945. M#2HM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM#2J@9T5.15)!3*!1
  3946. M54535$E/3D%"3$4M5D%,546@15)23U*@4%)/0T5$55)%#0UC:&]K92!L9'@@
  3947. M(S P#3IL;V]P(&QD82 Z8W1E>'0L> T@8F5Q(#ID;VYE#2!J<W(@8VAR;W5T
  3948. M#2!I;G@-(&IM<" Z;&]O< TZ9&]N92!R=',-.F-T97AT(&AE>" P9" [8W(-
  3949. M('1X=" G4T]-151(24Y'H$-(3TM%1* Z*"<-(&AE>" P9# P#0TJ+2TM+2TM
  3950. M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+0TJH&1205=)3B>@0:!,24Y%+J"@
  3951. M8:!&04A.H$Q!2$XN#0TJ*BJ@<T]-1:!54T5&54R@34%#4D]3#0UP;&]T<'@@
  3952. M;6%C(" [4$Q/5*!!H%!/24Y4H$E.H%@-('!H82 @.W531:!42$E3H$].1:!%
  3953. M5D526:!424U%#2!L9&$@8FET<"QX(#MXH$E3H$E.0U)%05-%1 T@8G!L(&,Q
  3954. M#2!E;W(@8G5F9F5R#2!S=&$@8G5F9F5R#2!B;6D@8S(-(&EN8R!B=69F97(K
  3955. M,0UC,B!L9&$@(R4Q,# P,# P, UC,2!O<F$@*&)U9F9E<BDL>0T@<W1A("AB
  3956. M=69F97(I+'D-('!L82 @.VY%142@5$^@4T%61:!A(0T@/#P\#0UP;&]T<'D@
  3957. M;6%C(" [<$Q/5*!!H%!/24Y4H$E.H%DZH%-)35!,15*@04Y$H$Y%0T534T%2
  3958. M62$-('!H82 @.W531:!42$E3H$].1:!72$5.H%E/5:!*55-4H$E.0U)%05-%
  3959. MH'D-(&QD82!B:71P+'@@.T)55*!XH$1/15-.)U2@0TA!3D=%#2!O<F$@*&)U
  3960. M9F9E<BDL>0T@<W1A("AB=69F97(I+'D-('!L80T@/#P\#0UC:6YI="!M86,@
  3961. M(#MM04-23Z!43Z!)3DE424%,25I%H%1(1:!#3U5.5$52#2!L9&$@73$@.T18
  3962. MH$]2H$19#2!L<W(-(&5O<B C)&9F(#LH;D]4H%173R=3H$-/35!,14U%3E0I
  3963. M#2!A9&,@(R0P,2 [8: ]H#(U-BU$6"\RH$]2H#(U-BU$62\R#2 \/#P@(#MT
  3964. M2$6@1%@O,J!-04M%4Z!!H$Y)0T52H$Q/3TM)3D>@3$E.10T->'-T97 @;6%C
  3965. M(" [;4%#4D^@5$^@5$%+1:!!H%-415"@24Z@> UX;&]O<"!I;G@-(&%D8R!D
  3966. M>0T@8F-C(&PQ#2J@9$^@5T6@55-%H&EN>:!/4J!D97F@2$5213\-(&EF(&DL
  3967. M73$@.VE&H%1(1:!&25)35*!#2$%204-415*@25.@04Z@)VDG#2!I;GD-(&5L
  3968. M<V4-(&1E>0T@9FEN#2!S8F,@9'@-;#$@/CX^('!L;W1P>" [84Q705E3H%1!
  3969. M2T6@0:!35$50H$E.H'@-(&-P>"!X,@T@8FYE('AL;V]P#2 \/#P-#7ES=&5P
  3970. M(&UA8R @.W-!346@5$A)3D<LH$)55*!&3U*@>0UY;&]O<"!I9B!I+%TQ#2!I
  3971. M;GD-(&5L<V4-(&1E>0T@8VQC(" [=D526:!)35!/4E1!3E0A#2!F:6X-(&%D
  3972. M8R!D> T@8F-C(&PR#2!I;G@@(#MA3%=!65.@24Y#4D5!4T6@> T@<V)C(&1Y
  3973. M#2 ^/CX@<&QO='!X#2!J;7 @;#,-;#(@/CX^('!L;W1P>2 [=T6@3TY,6:!)
  3974. M3D-214%3142@>0UL,R!C<'D@>3(-(&)N92!Y;&]O< T@/#P\#0TJ*BHJH&E.
  3975. M251)04R@3$E.1:!315154 T-9')A=R ^/CX@;6]V92QT>#$[>#$@(#MM3U9%
  3976. MH%-4549&H$E.5$^@6D523Z!004=%#2 ^/CX@;6]V92QT>#([>#(@(#MW2$52
  3977. M1:!)5*!#04Z@0D6@34]$249)140-(#X^/B!M;W9E+'1Y,3MY,0T@/CX^(&UO
  3978. M=F4L='DR.WDR#2 ^/CX@<V5T8G5F(#MN3U>@5T6@0T%.H$-,3T)"15*@5$A%
  3979. MH$)51D9%4@T-('-E8R @.VU!2T6@4U521:!8,3Q8,@T@;&1A('@R#2!S8F,@
  3980. M>#$-(&)C<R Z8V]N= T@;&1A('DR(#MI1J!.3U0LH%-705"@<#&@04Y$H' R
  3981. M#2!L9'D@>3$-('-T82!Y,0T@<W1Y('DR#2!L9&$@>#$-(&QD>2!X,@T@<W1Y
  3982. M('@Q#2!S=&$@>#(-#2!S8F,@>#$@.VY/5Z!A/418#3IC;VYT('-T82!D> T@
  3983. M;&1X('@Q(#MP552@6#&@24Y43Z!X+*!.3U>@5T6@0T%.H%1205-(H'@Q#0UC
  3984. M;VQU;6X@;&1A('@Q(#MF24Y$H%1(1:!&25)35*!#3TQ534Z@1D]2H'@-(&QS
  3985. M<B @.RAT2$E3H$-!3J!"1:!-041%H$U50TB@1D%35$52(2D-(&QS<B @.W1(
  3986. M15)%H$%21:!8,2\XH#$R.*!"651%H$),3T-+4PT@;'-R(" [=TA)0TB@345!
  3987. M3E.@6#$O,3:@,C4VH$)95$6@0DQ/0TM3#2!L<W(-(&)C8R Z979E;B [=TE4
  3988. M2*!!H%!/4U-)0DQ%H$585%)!H#$R.*!"651%H$),3T-+#2!L9'D@(R0X," [
  3989. M24:@4T\LH%-%5*!42$6@2$E'2*!"250-('-T>2!B=69F97(-(&-L8PTZ979E
  3990. M;B!A9&,@8G5F9F5R*S$@.V%$1*!)3J!42$6@3E5-0D52H$]&H#(U-J!"651%
  3991. MH$),3T-+4PT@<W1A(&)U9F9E<BLQ(#MA3D2@4U1/4D6@250A#0T@<V5C#2!L
  3992. M9&$@>3(@.V-!3$-53$%41:!$60T@<V)C('DQ#2!B8W,@.F-O;G0R(#MI4Z!9
  3993. M,CY9,3\-(&QD82!Y,2 [;U1(15)725-%H$19/5DQ+5DR#2!S8F,@>3(-.F-O
  3994. M;G0R('-T82!D>0T@8VUP(&1X(#MW2$\G4Z!"24='15(ZH$19H$]2H$18/PT@
  3995. M8F-S('-T97!I;GD@.VE&H$19+*!71:!.145$H%1/H%1!2T6@0DE'H%-415!3
  3996. MH$E.H%D-#7-T97!I;G@@;&1Y('DQ(#MXH$E3H$%,4D5!1%F@4T54H%1/H%@Q
  3997. M#2!L9&$@8FET<"QX(#MP3$]4H%1(1:!&25)35*!03TE.5 T@;W)A("AB=69F
  3998. M97(I+'D-('-T82 H8G5F9F5R*2QY#2 ^/CX@8VEN:70L9'@@.VE.251)04Q)
  3999. M6D6@5$A%H$-/54Y415(-(&-P>2!Y,@T@8F-S('AD96-Y(#MD3Z!71:!35$50
  4000. MH$9/4E=!4D13H$]2H$)!0TM705)$4Z!)3J!Y/PT->&EN8WD@/CX^('AS=&5P
  4001. M+&EN>0T@<G1S#0UX9&5C>2 ^/CX@>'-T97 L9&5Y#2!R=',-#7-T97!I;GD@
  4002. M;&1Y('DQ(#MW14Q,+*!!H$Q)5%1,1:!215!%5$E424].H$Y%5D52H$A54E2@
  4003. M04Y93TY%#2!L9&$@8FET<"QX#2!O<F$@*&)U9F9E<BDL>0T@<W1A("AB=69F
  4004. M97(I+'D-(#X^/B!C:6YI="QD>0T@8W!Y('DR#2!B8W,@>61E8WD-#7EI;F-Y
  4005. M(#X^/B!Y<W1E<"QI;GD-(')T<PT->61E8WD@/CX^('ES=&5P+&1E>0T@<G1S
  4006. M#0T-*BTM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2T-*J!C3$5!3J!5
  4007. M4 T-8VQE86YU<"!L9&$@=FUC<V(@.W-7251#2*!#2$%2H%)/3:!"04-+H$E.
  4008. M#2!A;F0@(R4Q,3$Q,#$P,2 [1$5&055,5 T@<W1A('9M8W-B#0T@<G1S(" [
  4009. M0EE%(0T-*BTM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2T-*J!S3TU%
  4010. MH%9!4DE!0DQ%4PT-='@Q(&1S(#$-='DQ(&1S(#$-='@R(&1S(#$-='DR(&1S
  4011. M(#$-<#%X(&1S(#$@.W1(15-%H$%21:!414U03U)!4EF@4U1/4D%'10UP,7D@
  4012. M9',@,2 [=5-%1*!)3J!03$]45$E.1Z!42$6@4%)/2D5#5$E/3@UP,G@@9',@
  4013. M,0UP,GD@9',@,2 [=$A%6:!!4D6@2$521:!33Z!42$%4H%=%#7 S>"!D<R Q
  4014. M(#M$3TXG5*!(059%H%1/H%)%0T%,0U5,051%H%1(14TN#7 S>2!D<R Q#7 T
  4015. M>"!D<R Q(#MT2$59H$U!2T6@3$E&1:!%05-9+@UP-'D@9',@,0UP-7@@9',@
  4016. M,2 [=TA9H$%21:!93U6@3$]/2TE.1Z!!5*!-1:!,24M%H%1(050_#7 U>2!D
  4017. M<R Q(#MD3TXG5*!93U6@5%)54U2@344_#7 V>"!D<R Q#7 V>2!D<R Q(#MH
  4018. M059)3D>@04Y/5$A%4J!#2$E,1*!705-.)U2@35F@241%02X-<#=X(&1S(#$-
  4019. M<#=Y(&1S(#$-<#AX(&1S(#$-<#AY(&1S(#$-9'-X(&1S(#$@.V1S>*!)4Z!4
  4020. M2$6@24Y#4D5-14Y4H$9/4J!23U1!5$E.1Z!!4D]53D2@6 UD<WD@9',@,2 [
  4021. M<TE-24Q!4J!&3U*@9'-Y+*!D<WH-9'-Z(&1S(#$-<W@@9',@,2 [=$A%4T6@
  4022. M05)%H%1(1:!!0U1504R@04Y'3$53H$E.H%B@6:!!3D2@6@US>2!D<R Q#7-Z
  4023. M(&1S(#$-=#$@9',@,2 [=$A%4T6@05)%H%53142@24Z@5$A%H%)/5$%424].
  4024. M#70R(&1S(#$-=#,@9',@,2 [<T5%H%1(1:!!4E1)0TQ%H$9/4J!-3U)%H$1%
  4025. M5$%)3%,-=#0@9',@,0UT-2!D<R Q#70V(&1S(#$-=#<@9',@,0UT."!D<R Q
  4026. M#70Y(&1S(#$-=#$P(&1S(#$-83$Q(&1S(#$@.W1(15-%H$%21:!42$6@14Q%
  4027. M345.5%.@3T:@5$A%H%)/5$%424].H$U!5%))6 UB,3(@9',@,2 [>'EZ#6,Q
  4028. M,R!D<R Q#60R,2!D<R Q(#MT2$6@3E5-0D52H$1%3D]415.@*%)/5RQ#3TQ5
  4029. M34XI#64R,B!D<R Q#68R,R!D<R Q#6<S,2!D<R Q#6@S,B!D<R Q#6DS,R!D
  4030. M<R Q#71A(&1S(#$@.W1(15-%H$%21:!414U03U)!4EF@3$]#051)3TY3#71B
  4031. M(&1S(#$@.T9/4J!54T6@0EF@5$A%H%!23TI%0U1)3TZ@4D]55$E.10UT8R!D
  4032. M<R Q#71D(&1S(#$-=&4@9',@,0UT9B!D<R Q#71G(&1S(#$-=&@@9',@,0UT
  4033. M:2!D<R Q#0TJ+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+0TJH'-%
  4034. M5*!54*!"252@5$%"3$4-#2!D<R!>(#MC3$5!4J!43Z!%3D2@3T:@4$%'10T@
  4035. M(" [<T^@5$A!5*!404),15.@4U1!4E2@3TZ@0:!004=%H$)/54Y$05)9#6)I
  4036. M=' @;'5P(#$V(#LQ,CB@94Y44DE%4Z!&3U*@> T@9&9B("4Q,# P,# P, T@
  4037. M9&9B("4P,3 P,# P, T@9&9B("4P,#$P,# P, T@9&9B("4P,# Q,# P, T@
  4038. M9&9B("4P,# P,3 P, T@9&9B("4P,# P,#$P, T@9&9B("4P,# P,# Q, T@
  4039. M9&9B("4P,# P,# P,0T@+2U>#7-I;B @(#MT04),1:!/1J!324Y%4RR@,3(P
  4040. MH$)95$53#6-O<R!E<74@<VEN*S$R." [=$%"3$6@3T:@0T]324Y%4PT@(" [
  4041. M8D]42*!/1J!42$531:!44DE'H%1!0DQ%4Z!!4D4-(" @.T-54E)%3E1,6:!3
  4042. M152@55"@1E)/3:!B87-I8PUZ9&EV(&5Q=2!C;W,K,3(X(#MD259)4TE/3J!4
  4043. M04),10T                                                     
  4044. #    
  4045.  
  4046. end
  4047.  
  4048. =============================================================================
  4049. DESIGN OF A 'REAL' OPERATING SYSTEM FOR THE 128: PART I
  4050. by Craig Bruce  <csbruce@ccnga.uwaterloo.ca>
  4051.  
  4052. 0. PREFACE
  4053.  
  4054. I originally planned to write this entire article all in one go, but its
  4055. size, complexity, and scope of required design decisions have forced me to
  4056. split this article into two pieces.  (Not to mention my own poor time
  4057. management in writing this article).  This part gives an introduction to what
  4058. I am talking about and discusses, at an abstract level, how the system will
  4059. work.  The next part will dive into all of the nuts and bolts of the
  4060. low-level design.
  4061.  
  4062. Also, this article may be a bit to weird for some people to grasp.  Please
  4063. bear with me.  This article is as much a scratchpad for my rough ideas about
  4064. the kind of system I want to build as it is an explanatory article.  You may
  4065. need a Master's degree in software systems to understand some of the things I
  4066. talk about.  This article makes references to the ACE operating system, which
  4067. is available via anonymous FTP from "ccnga.uwaterloo.ca".  ACE is a
  4068. uni-tasking OS that has a Unix-like flavor.  (Yeah, yeah, yeah, I'm still
  4069. working on the next release...).
  4070.  
  4071. One more note about the article: it is written in the present tense ("is")
  4072. rather than the future tense ("will"), since the present tense is easier to
  4073. read and understand.  The system, however, does not presently exist and the
  4074. design may change in many ways if the system ever is made to exist.
  4075.  
  4076. 1. INTRODUCTION
  4077.  
  4078. The full title of this article should be "Design of a Multitasking Distributed
  4079. Microkernel Operating System for the Good Old '128".  For purposes of
  4080. discussion, we will call the new operating system "BOS".  A "multitasking"
  4081. operating system (OS) is one that is able to execute more than one "process"
  4082. "concurrently".  A Process is an instance of a running program.
  4083. "Concurrently" means that the programs appear to be running at the same time,
  4084. although in reality they are not, because there is only "one" processor in the
  4085. 128 and it can only do one thing at a time.
  4086.  
  4087. A "distributed" OS is one that runs on a collection of independent computers
  4088. that are connected by a network.  Unlike a "network" OS, a distributed OS
  4089. makes all of the independent computers look like ONE big computer.  In
  4090. general, a distributed system, as compared to a centralized one (like MS-DOS
  4091. or Unix), gives you "a higher performance/price ratio ('more bang for the
  4092. buck'), potentially increased reliability and availability because of partial
  4093. failure modes (if protocols are implemented correctly), shared resources,
  4094. incremental growth and online extensibility, and [a closer modelling of] the
  4095. fact that some applications are inherently distributed."  This is quoted from
  4096. my Ph.D. thesis about distributed systems of powerful workstations.  To us, a
  4097. distributed system means increased modularity and ease of construction,
  4098. sharing devices like disk drives and resources like memory between multiple
  4099. computers, and the true parallelism of running different processes on
  4100. multiple computers at the same time.  Not to mention "coolness".
  4101.  
  4102. A "microkernel" OS is one that has the smallest kernel possible by pushing
  4103. higher-level functionality (such as the file system) into the domain of user
  4104. processes.  The kernel ends up being small, fast, and easy to construct
  4105. (relative to a monolithic kernel).
  4106.  
  4107. So why would we want our OS to have the features of Multitasking,
  4108. Distributed, and Microkernel?  Because I'm designing it, and that's what
  4109. interests me.  The ease-of-construction thing is important too.  Another
  4110. important question is "can it be done?".  The answer is "yes."  And it will
  4111. be done, whenever I get around to it (one of these lifetimes).
  4112.  
  4113. 2. GENERAL DESIGN OVERVIEW
  4114.  
  4115. There are a number of high-level design decisions that must be made before
  4116. going into a detailed design.  This section discusses these decisions.
  4117.  
  4118. 2.1. SPECIAL C-128 FEATURES
  4119.  
  4120. The C-128 has a minumum set of special features that make it feasible to run
  4121. a multitasking operating system, as opposed to earlier machines like the
  4122. C-64.  The simplest special feature that the C128 has is *enough memory*.  The
  4123. 64K of the C64 just isn't enough.  The 128K of the C128 is just barely
  4124. enough. Expanded internal memory makes the proposition even easier.
  4125.  
  4126. The C-128 also has relocatable zero-page and stack-page pointers.  This
  4127. feature are absolutely essential and you could not make an effective
  4128. multitasking OS for any 6502 machine without it.  I wonder if Commodore
  4129. thought about this prospect when designing the MMU chip...
  4130.  
  4131. The last C-128 feature is *speed*.  The C128 has a 2 MHz clock speed when
  4132. used with the 80-column VDC display.  This is enough speed, when harnessed
  4133. properly, to make your applications zip along.  For an example of speed that
  4134. is not harnessed properly, see Microsloth Windoze.  The VDC display is also
  4135. very nice, too.  Only the VDC display should be supported by a "real" OS, not
  4136. the VIC display.
  4137.  
  4138. 2.2. NETWORK
  4139.  
  4140. The OS should be designed to run on a system of between 1 and N C-128's,
  4141. where N has a maximum of something like 8 or 16.  We'll choose 16 for our
  4142. software design.  The theory is that the style of operating system that we
  4143. are proposing makes the step between 1 and N C-128's a (relatively) easy one,
  4144. so why not go for it.  Also, if N were to become some number like 256 or
  4145. 65536, then we could start kicking some serious ass performance-wise, for
  4146. certain classes of computations.  Also, I happen to own two C-128's and I
  4147. have already constructed a parallel-port network (a Jedi's weapon!), so I
  4148. might as well use it.
  4149.  
  4150. The required network connects the user ports of C-128's into a bus.  I'm not
  4151. completely sure how to connect more than two C-128's to this bus (I'd
  4152. probably need some diodes or logic gates), so the initial version of this
  4153. network hardware will have a maximum of two hosts.  We will still be careful
  4154. to make the software of the system easily reconfigurable for any number of
  4155. hosts.
  4156.  
  4157. You will need two appropriate connectors and some 14-conductor ribbon cable
  4158. to build the network.  One of my connectors is a 44-conductor connector of
  4159. the type used with the VIC-20 expansion port that I sawed in half and the
  4160. cable is some old junk ribbon cable that was lying around that I removed some
  4161. of the conductors from.  Any old junk will do.  You're probably best off if
  4162. your cable is less than six feet long (2 metres).  The network is wired up as
  4163. follows:
  4164.  
  4165. C128-A  name/pin                                      pin/name  C128-B
  4166.          GND <A>+------------------------------------+<A> GND
  4167.         FLAG <B>+------------------------------------+<8> PC2 ***
  4168.          PB0 <C>+------------------------------------+<C> PB0
  4169.          PB1 <D>+------------------------------------+<D> PB1
  4170.          PB2 <E>+------------------------------------+<E> PB2
  4171.          PB3 <F>+------------------------------------+<F> PB3
  4172.          PB4 <H>+------------------------------------+<H> PB4
  4173.          PB5 <J>+------------------------------------+<J> PB5
  4174.          PB6 <K>+------------------------------------+<K> PB6
  4175.          PB7 <L>+------------------------------------+<L> PB7
  4176.          PA2 <M>+------------------------------------+<M> PA2
  4177.          GND <N>+------------------------------------+<N> GND
  4178.         CNT2 <6>+------------------------------------+<6> CNT2
  4179.          SP2 <7>+------------------------------------+<7> SP2
  4180.          PC2 <8>+------------------------------------+<B> FLAG ***
  4181.  
  4182. Here is the Commodore 128 User Port when looking at the back of the unit:
  4183.  
  4184.                         111
  4185.                123456789012    top
  4186.                ------------
  4187.                ABCDEFHJKLMN    bottom
  4188.  
  4189. This gives a parallel bus that can operate at a peak of about 80
  4190. kiloBYTES/sec with a shift-register serial bus thrown in that can operate at
  4191. a peak of about 21 kiloBYTES/sec.  Both communication channels are
  4192. uni-directional, so some media-access-control protocol will need to be
  4193. provided by software.  The price, in terms of hardware for using this
  4194. network, is that you can't use a modem that plugs into the user port at the
  4195. same time.  Of course, any serious user will have a modem that plugs into a
  4196. UART card anyway.
  4197.  
  4198. You can also write your own applications for this network, since programming
  4199. it is quite easy; the hardware takes care of all of the handshaking.  To
  4200. blast 256 bytes over the network from C128-A to C128-B, you would:
  4201.  
  4202. C128-A: sender                             C128-B: receiver
  4203. ==============                             ================
  4204.   lda #$FF   ;ddr-output                     lda #$00   ;ddr-input
  4205.   sta $DD03                                  sta $DD03
  4206.   ldy #0                                     ldy #0
  4207. - lda DATA,y ;get data                     - lda #$10   ;wait for data
  4208.   sta $DD01  ;send data                    - bit $DD0D
  4209.   lda #$10   ;wait for ack                   beq -
  4210. - bit $DD0D                                  lda $DD01  ;receive data/send ack
  4211.   beq -                                      sta DATA,y ;store data
  4212.   iny        ;next                           iny
  4213.   bne --                                     bne --
  4214.   rts                                        rts
  4215.  
  4216. These routines can even be tweaked a little more for higher performance.
  4217. Programming the shift register is analogous to the above.
  4218.  
  4219. There is probably no need to do error checking on the data transmitted over
  4220. the network since the cable should be about as reliable as any of the other
  4221. cables hanging out the back of your computer (and none of them have error
  4222. checking (except maybe your modem cable)).
  4223.  
  4224. 2.3. PROCESSES
  4225.  
  4226. A process is a user program that is in an active state of execution.  In
  4227. uni-tasking operating systems like ACE or the Commodore Kernal, there is only
  4228. one process in the entire system.  In a multi-tasking system, there are, duh,
  4229. multiple processes.  Each process executes as an independently running
  4230. program, in isolation, logically as if it were the only process in the
  4231. system.  Or, as if there were N 8502's available inside of the 128 and one of
  4232. them were used to run each program you have loaded.
  4233.  
  4234. In reality, there is only 1 CPU in the 128 (well, that we are interested in
  4235. using), so its time is divided up and given out in small chunks to execute so
  4236. many instructions of each program before moving onto the next one.  The act
  4237. of changing from executing one program to executing another is called
  4238. "context switching", and is a bit of a sticky business because there is only
  4239. one set of processor registers, so these must be saved and restored every
  4240. time we switch between processes.  Effectively, a process' complete "state"
  4241. must be restored and saved every time it is activated and deactivated
  4242. (respectively).  Since the 8502 has precious few internal registers, context
  4243. switching can be done quite efficiently (unlike with some RISC processors). 
  4244. The maximum period of time between context switches is called the "quantum"
  4245. time.  In our system, the quantum is 1/60 of a second.  It is more than just
  4246. a coincidence that this period is the same as the keyboard-scanning period. 
  4247. Depending on priorities and ready processes, a new or the same old process
  4248. may be selected for execution after the context switch of the 60-Hz
  4249. interrupt.
  4250.  
  4251. Splitting the time of one processor among N processes may sound like we're
  4252. simply making each one run N times slower, which may be unbearably slow, but
  4253. that is not generally the case.  One thing that a CPU spends a lot of its
  4254. time doing is *waiting*.  Executing instructions of a program requires the
  4255. full attention of the CPU, but waiting requires absolutely no CPU attention. 
  4256. As an example, your speedy computer spends a lot of its time waiting for its
  4257. slow-as-molasses-launching-into-orbit user to type a key.  If we were to put
  4258. the process that asks the OS for a keystroke into a state of suspended
  4259. animation, then the CPU time that process would have consumed in a
  4260. busy-waiting loop can be better spent on executing the other processes that
  4261. are "ready" to execute.  In practice, many processes spend a lot of their
  4262. time waiting, so "multi-programming" is a big win.
  4263.  
  4264. There are a number of things other than keystrokes that processes may wait
  4265. for in our envisioned system: modem characters, disk drive operations (if
  4266. they are custom-programmed correctly), mouse & joystick movements, real-time
  4267. delays, and interactions with other processes.  The OS provides facilities
  4268. for processes to communicate with one another when they cannot perform some
  4269. operation in isolation (i.e., when they become lonely).
  4270.  
  4271. A process has the following things: a program loaded into the internal memory
  4272. of the 128, its own zero page and processor stack page, and the global
  4273. variables of its program.  A process can also own "far" memory (below) and
  4274. various other resources of servers throughout the distributed system.  The
  4275. process is the unit of ownership, as well as execution.  Processes also have
  4276. priorities that determine how much execution time they are to be given
  4277. relative to other processes in the system.
  4278.  
  4279. Processes are allocated memory at the time of startup at a random location on
  4280. some random bank of internal memory on the 128.  The biggest challenge here
  4281. is to relocate the user program to execute at the chosen address.  The kernel
  4282. interface is available to programs on all internal banks of memory.
  4283.  
  4284. 2.4. APPLICATION PROGRAM INTERFACE
  4285.  
  4286. To take advantage of existing software, we would like our OS to provide an
  4287. application-program interface (API) that is identical to that of the
  4288. ACE-128/64 operating system.  In fact, this is the *real* reason why ACE was
  4289. developed -- as a stepping stone toward a real operating system.  The ACE
  4290. Programmer's Reference Guide, which describes the API, is available from
  4291. "ccnga.uwaterloo.ca".
  4292.  
  4293. Some useful software already exists for ACE, and ACE has a well-definied
  4294. interface and well-behaved programs.  The ACE interface may need to evolve a
  4295. little too.  The ultimate goal would be to have the same API for both systems
  4296. so you could run software with the more functional BOS if you have a C128 and
  4297. 80-column monitor, or you could use the less functional ACE if you didn't
  4298. have all this hardware.
  4299.  
  4300. The software wouldn't be "binary-identical" since the operating systems
  4301. provide quite different program environments and requirements, but the two
  4302. systems should be application-source-code compatible.
  4303.  
  4304. Because of the vast differences between a microkernel and a monolithic
  4305. kernel, all of the ACE system calls would be redirected to user-library calls
  4306. in BOS. This user library would then carry out the operations accessing
  4307. whatever system services are needed.
  4308.  
  4309. 2.5. MEMORY MANAGEMENT
  4310.  
  4311. The memory management of BOS is analogous to that of ACE.  There are two
  4312. different classes of memory: near and far.  Near memory is on the same bank
  4313. as a program and can be accessed directly by processor instructions.  Far
  4314. memory can only be accessed through the kernel by the special kernel calls
  4315. Fetch and Stash and must be specially allocated to a process by the operating
  4316. system. Note that near memory is considered a sub-class of far memory; the
  4317. far-memory primitives can be used to access near memory.
  4318.  
  4319. Only the basic memory-accessing code is provided by the kernel; higher-level
  4320. memory management, such as dynamic memory allocation and deallocation, is
  4321. handled by the Memory Server (below).
  4322.  
  4323. Unlike ACE, BOS provides the fundamental concept of "distributed memory". 
  4324. The Fetch and Stash primitives can also access the memory of a remote machine
  4325. in a completely user-transparent way.  Thus, a far-memory pointer can be
  4326. passed between processes on different machines, and the memory that the
  4327. pointer refers to can be read and written with equal programming by both
  4328. processes. This feature can be dangerous without a synchronization mechanism,
  4329. so this memory sharing is intended to be used only with the communication
  4330. mechanism.
  4331.  
  4332. There should not be an unacceptable overhead in accessing remote memory on
  4333. the 128 (like how there would be with bigger computers) because far-memory
  4334. fetching for local memory is quite expensive anyways (relative to near
  4335. memory), so an application will optimize its far memory accessing, and the
  4336. necessary interrupt handling on the remote machine can be done with very
  4337. little latency because of the "responsiveness" of the 6502 processor design.
  4338.  
  4339. 2.6. COMMUNICATION
  4340.  
  4341. In the type of system that is envisioned, processes are not strictly
  4342. independent and competitive; many must cooperate and comunicate to get work
  4343. done.  To facilitiate this interprocess communication (IPC), a particular
  4344. organization is chosen: the Remote Procedure Call (RPC) paradigm.  RPC is a
  4345. message-passing scheme that is used with the heavily hyped Client/Server
  4346. system architecture model.  It reflects the implicit operations that take
  4347. place when you call a local procedure (a subroutine): the call, the entry,
  4348. the processing, and the return.  The kernel provides three primitives for
  4349. RPC:
  4350.  
  4351. Send( processId, requestBuffer, reqLength, replyBuffer, maxRepLength ) : err;
  4352.  
  4353. Receive( ) : processId, requestBuffer, reqLength, replyBuffer, maxRepLength;
  4354.  
  4355. Reply( processId ) : err;
  4356.  
  4357. Send() is used to transmit a message to a remote process and get back a reply
  4358. message.  The sending process suspends its execution while it is waiting for
  4359. remote process to execute its request.  A message consists of an arbitrary
  4360. sequence of bytes whose meaning is completely defined by the user.  The
  4361. message contents are stored in a buffer (hunk of memory) before sending, and
  4362. a length is specified at the time of sending.  A buffer to receive the reply
  4363. message must also be allocated by the sender and specified at the time of
  4364. sending.  To save us from the overhead of copying message contents to and fro
  4365. unnecessarily, only pointers to the buffers are passed around and the far
  4366. memory primitives are used to access message contents.  This also works
  4367. across machine boundaries because of the distributed-memory mechanism
  4368. described above.
  4369.  
  4370. Receive() is used to receive a message transmitted by a remote process to the
  4371. current process.  The receiver blocks until another process does a
  4372. corresponding Send() operation, and then the request and reply buffer
  4373. pointers and lengths are returned.  The receiver is expected to fetch the
  4374. contents of the request message, process the request, prepare the reply
  4375. message in the far-memory reply buffer, and then execute the Reply()
  4376. primitive.  There are no restrictions on what the receiver can do between
  4377. receiving a message from a process and issuing the corresponding reply
  4378. message.  So, it could, for example, receive and process messages from other
  4379. processes until it gets what it needs, compute pi to 10_000 decimal places,
  4380. and then reply to the process that sent a message to it a long time ago.
  4381.  
  4382. Reply() is used to re-awaken a process that sent a message that was
  4383. Receive()d by the current process.  The current process is expected to have
  4384. set up the far-memory reply buffer in whatever way the sending process
  4385. requires prior to issuing the Reply().
  4386.  
  4387. The expected usage of buffers is for the sender to use near memory for the
  4388. request and reply buffers and access them as regular near memory to construct
  4389. and interpret request and reply messages.  The receiver will access the
  4390. buffers as far memory (which they may very well be since processes are
  4391. allowed to execute on different banks of internal memory and even on
  4392. different machines), and may wish to fetch parts of messages into near memory
  4393. for processing.  The use of far pointers makes it so that data is copied only
  4394. when necessary.
  4395.  
  4396. And that's it.  You only have this RPC mechanism for communicating with other
  4397. processes and for all I/O.  Well, that's not entirely true; the RPC stuff is
  4398. hidden behind the application program interface, which provides such facades
  4399. as the Open and Read system calls, and a very-low level interrupt
  4400. notification mechanism which a user process will not normally use.
  4401.  
  4402. 2.7. SYSTEM SERVERS
  4403.  
  4404. Since all that user program has for IPC and I/O is the RPC mechanism, a
  4405. number of system server processes must be set up to allow a user program to
  4406. do anything useful.  These special servers execute as if they were regular
  4407. user programs but provide service that is normally implemented directly into
  4408. the operating system kernel.  There are a number of advantages and
  4409. disadvantages to organizing a system in this way.  A big advantage is that it
  4410. is easier to build a modular system like this, and a big disadvantage is that
  4411. you lose some performance to the overhead of the IPC mechanism.
  4412.  
  4413. A useful implication of using servers rather than having user processes
  4414. execute inside of the kernel is mutual exclusion.  Servers effectively
  4415. serialize user requests.  I.e., user requests are serviced in order, strictly
  4416. one-at-a-time.  This is important because some of variables that need to be
  4417. manipulated in order to provide service must not be manipulated by multiple
  4418. processes simultaneously or you may get inconsistent results.  To provide
  4419. mutually exclusive access to shared variables in a monolithic system, either
  4420. ugly and problematic semaphores must be used, or more-restrictive, simpler
  4421. mechanisms like allowing only one user process to enter the kernel.
  4422.  
  4423. 2.7.1. PROCESS SERVER
  4424.  
  4425. This server is responsible for starting and terminating user processes.
  4426. Because of the way that the procedure is organized, the process server is
  4427. actually quite responsive dispite all of the work that must be done in order
  4428. to start up and terminate a user process.
  4429.  
  4430. The server is highly integrated with the kernel, and it is able to do things
  4431. that regular user processes cannot (like manipulate kernel data structures),
  4432. but it still functions as an independent entity, as a regular user process.
  4433. Its code is physically a part of the kernel for bootstrapping purposes, since
  4434. it can hardly be used to start itself.
  4435.  
  4436. When you wish to run a new program, a request message is sent to the process
  4437. server.  This message includes the filename of the program to run, the
  4438. arguments to the new program, environmental variables, and a synchronous/
  4439. asynchronous flag.  If you want to run a sub-process synchronously, the
  4440. process server does not reply to your request until the new process
  4441. terminates.  If you select asynchronous mode, the process server replies to
  4442. your request as soon as the new process is created.  Both of these modes are
  4443. quite useful in Unix (although Unix has a more complicated mechanism for
  4444. providing the service) (think "&" and no-"&" on command lines), so they are
  4445. provided here.
  4446.  
  4447. The process server allocates and initializes the kernel data structures
  4448. necessary for process management, and then starts the process running
  4449. bootstrapping code in the kernel.  Since this code is in the kernel, it is
  4450. known to be trustworthy.  The process then bootstraps itself by opening the
  4451. program file, reading the memory requirements, allocating sufficient memory,
  4452. reading in the program file, relocating the program for whatever memory
  4453. address it happened to load in at (bank relocation is no problem) and
  4454. far-calling the main routine (finally).  The return is set up on the stack to
  4455. kill the process.
  4456.  
  4457. Since the process bootstraps itself, the process server's involvement in the
  4458. process creation procedure is minimal, and the process server is ready to
  4459. process new requests with minimal delay (maximal responsiveness).  This
  4460. self-bootstrapping user process concept comes from my Master's Thesis.
  4461. Another advantage of having a process server is that you can start a process
  4462. running on any machine from any other machine in exactly the same way you
  4463. would start a process on the local machine; we have achieved transparentness,
  4464. Park.
  4465.  
  4466. The process server also takes care of process destruction (exit or kill) and
  4467. provides other less-significant services, like reading and setting the
  4468. current date and time.  The mechanism by which process destruction is done is
  4469. similar to the self-bootstrapping idea and is discussed, probably
  4470. inappropriately, in the next section.
  4471.  
  4472. The server is located by having a well-known address.  That is, the process
  4473. id is a constant and hard-coded into clients.  Well-known addresses are small
  4474. integer values, for each machine (a machine-id is encoded into process ids),
  4475. and these integers are indexes into a small look-up table with the actual
  4476. addresses for well-known addresses, so the process ids aren't pinned but can
  4477. be used as if they were pinned.
  4478.  
  4479. 2.7.2. MEMORY SERVER
  4480.  
  4481. The memory server handles the dynamic allocation and deallocation of far
  4482. memory.  The client specifies in the request message the exact types of
  4483. memory that it can use, and the server gets the memory, sets the ownership to
  4484. the process, and returns a pointer.  Deallocation of some of the memory owned
  4485. by a process is handled easily.
  4486.  
  4487. There is also a call that deallocates all memory owned by a certain user
  4488. process.  This call is normally only called by the process server*, since the
  4489. memory of the user program is be deallocated along with the rest of the
  4490. process' memory.  A record is kept internally for each process about what
  4491. types and banks (later) of memory it has used so that bulk deallocation can
  4492. be done efficiently when the process exits.
  4493.  
  4494. A client process can also ask that far memory be allocated on a remote
  4495. machine.  Remote memory is relatively slow to access, but it can be
  4496. convenient when you need LOTS of memory for a process.  The obvious way to
  4497. get at this remote memory is to simply send a message directly to the remote
  4498. memory server of the machine you want to allocate memory on, and this does
  4499. indeed work, so this is what we will do.  But, this doesn't record the fact
  4500. that you have allocated memory on a far machine by itself, and we don't want
  4501. to waste any effort in freeing all of the memory, both local and remote, that
  4502. a process owns when it terminates; i.e., we don't want to send deallocation
  4503. requests to all remote memory servers just to be sure.
  4504.  
  4505. There are a few alternatives for solving this problem, but I think this is a
  4506. good place for a quick-and-dirty hack.  Whenever a user process sends a
  4507. message to a memory server (both local or remote, for whatever reason),
  4508. through the memory servers' well-known addresses, the bit corresponding to
  4509. the machine number (0-15) in a special 16-bit field of the sender's process
  4510. control block is set.  Then, when the process terminates, the termination
  4511. procedure (next) peeks at this special field and sends free-all messages to
  4512. all remote memory servers that the process in question has interacted with.
  4513. This insures that all memory in the entire distributed system that is
  4514. allocated to a process is tidied up when the process terminates.  Like the
  4515. process server, the memory server is integrated with the kernel.
  4516.  
  4517. MORE PROCESS TERMINATION
  4518.  
  4519. Come to think of it, I should talk more about process termination.  The best
  4520. idea would probably be for a user process to terminate itself, in the same
  4521. way that it bootstraps itself.  A termination message is sent by a client
  4522. process that wants to kill someone to the process server.  It is a valid
  4523. situation for a process to commit suicide.  The termination message includes
  4524. the process id to be terminated and the exit code for the termination.
  4525.  
  4526. The process server then suspends the doomed process' execution and rigs the
  4527. process' context so that the next thing it executes is the process shutdown
  4528. code inside of the kernel.  This shutdown code closes all of the files that
  4529. the process has opened through the standard library calls (and other server-
  4530. resources held), deallocates all memory held by the process, maybe does some
  4531. other cleanup work, and then sends a special message to the process server to
  4532. remove the process control block.  The process server will only accept this
  4533. special message from the process that is terminating after the first phase of
  4534. the process shutdown has been completed, to insure a proper termination.  The
  4535. process control block is then deallocated and may be used again.  The process
  4536. server is the only process that is allowed to manipulate process control
  4537. blocks.
  4538.  
  4539. Come to think of it, there is a slight problem with process initialization:
  4540. getting a copy of the arguments and environmental variables for an
  4541. asynchronously started new process.  We don't want the sender to continue
  4542. before the new process has had a chance to make a copy of the arguments and
  4543. environment, so we will rig things so that it is the newly started process
  4544. that sends the reply message back to the parent process.  Another dirty hack.
  4545.  
  4546. 2.7.3. FILE SERVERS
  4547.  
  4548. Each disk drive in the system has a special server that provides an interface
  4549. for executing Open, Read, Write, Close, and a number of other common file
  4550. operations.  A big problem with distributed operating systems is resource
  4551. reclamation for processes that die.  There are a few ways to provide this,
  4552. and each has implications about the overall design of a server.
  4553.  
  4554. One possibility is to have "stateless servers".  In other words, each server
  4555. does not keep track of, for example, which files a process has open or the
  4556. current file positions.  Each time a read request comes in, the server opens
  4557. the file to be used, positions to the section of the file, performs the
  4558. operation, and closes the file again.  This sounds like a lot of work, but
  4559. some intelligent caching makes it work efficiently.  And if a user process
  4560. dies without closing all of its files, it doesn't matter since the files will
  4561. be closed anyway, logically at the completion of each operation.  But, this
  4562. approach doesn't really work well with Commodore-DOS, which we will be using
  4563. for devices for which we don't have a custom device driver, so we won't use
  4564. it.
  4565.  
  4566. Another possibility is to have "semi-state" or "acknowledgementless" servers
  4567. (my own invention).  Here, the server keeps track of, for example, which
  4568. files are open but doesn't keep the file position.  When a request comes in,
  4569. the already-opened file is positioned according to the request and the file
  4570. operation takes place.  If a client dies unexpectedly, the open file control
  4571. block (FCB) is left behind, but the FCB will be closed and reused after a
  4572. certain period of time.  If the client actually hasn't died, then the
  4573. situation will be detected (through details not explained here) and the file
  4574. will be reopened as if nothing has happened.  Other contingencies like a dead
  4575. process' name being reused are handled too.  And the model works well with an
  4576. unreliable communication service.  But, again, this doesn't model the
  4577. Commodore-DOS very well.
  4578.  
  4579. The final design considered is to have a registry of servers that that a
  4580. process has resources currently allocated on be associated with each process.
  4581. When a client makes an open request to the server (or some equivalent
  4582. resource-grabbing operation), the server checks to see if the client is
  4583. currently holding any other of the server's resources.  If so, then the
  4584. request is processes normally.  If not, then the server (or some agent on the
  4585. server's behalf) sends a message to the process server on the client's
  4586. machine telling the process server to record the fact that the client is (or
  4587. may be) holding some of the server's resources.  The process server records
  4588. the server's process id in the process control block of the client, and when
  4589. the client terminates, it will send a standard "release all of the resources
  4590. that I am (may be) holding on this server" to the server as part of the
  4591. client's shutdown procedure.  All of the client's open files will be closed,
  4592. etc.
  4593.  
  4594. In this "registry" design, servers can be completely "stateful", e.g., they
  4595. would contain both an open file entry and the file position information, and
  4596. files would always open and close when we intuitively expect them to.  It is
  4597. assumed that the communication mechanism is reliable, which it is here.  This
  4598. mechanism *does* model Commodore-DOS well.  In fact, this idea is so nice
  4599. that I may redesign the memory allocation recovery mechanism to use this. 
  4600. There is a slight possibility of a "race condition" in this mechanism, but
  4601. nothing bad can happen because of it.  (This is just a note to myself: make
  4602. it so that if a process is killed while it is receive- or reply-blocked, then
  4603. ignore the reply from the server if the process id is reused; damn, there's
  4604. still a potential problem; I'll have to figure it out later; also watch out
  4605. for a distributed deadlock on the PCB list).
  4606.  
  4607. So, our server supports the regular file operations and implements them in
  4608. pretty much the expected way, since it is a "stateful" server.  The main loop
  4609. of the server accepts a request, determines which type it is, extracts the
  4610. arguments, calls the appropriate local procedure, prepares the reply message,
  4611. replies, and goes back to the top of the loop.  Each opened file is
  4612. identified by a user process by a file control block number that has meaning
  4613. inside of the server, as per usual.  But, unlike with ACE, we need a special
  4614. "Dup" operation for passing open files to children.  Dup increments the
  4615. "reference count" of a FCB, and the reference count is decremented every time
  4616. a close operation takes place.  A file will only be "really" closed when the
  4617. reference count reaches zero.  Our system will not implement any security at
  4618. this time.
  4619.  
  4620. Because of the abstraction of sending formatted messages to a server,
  4621. different types of disk drives (Commodore-DOS, custom-floppy, ramdisk) are
  4622. all dealt with in exactly the same way.  As one slight extension, we have to
  4623. hack our devices (at least some of them) a little to be able to handle
  4624. "symbolic links" in order to integrate well with the Prefix Server which is
  4625. described next.
  4626.  
  4627. 2.7.4. PREFIX SERVER
  4628.  
  4629. The prefix server idea is stolen from the computer science literature about a
  4630. network operating system called "Sprite".  The prefix server simply provides a
  4631. pathname lookup service for the pathnames of different disk-file and device
  4632. servers.  This is needed to provide a single, global, unified pathname space
  4633. on a system of multiple distributed file servers.  It works a lot like the
  4634. "mount table" in Unix.  Its prefix table looks something like the following:
  4635.  
  4636. PREFIX      SERVER
  4637. ------      ------
  4638. /           <1:ramdisk>
  4639. /dev/tty0   <1:console>
  4640. /fd1        <2:floppy1571>
  4641.  
  4642. BTW, BOS uses Unix-style filenames rather than the Creative-Micro-Designs-
  4643. style filenames that ACE uses.
  4644.  
  4645. If an application is given an absolute pathname, it will consult the prefix
  4646. server to resolve it to the process-id of an actual server.  For example, the
  4647. pathname "/fd1/bob/fred" would resolve to server "<2:floppy1571>", relative
  4648. pathname "bob/fred".  Pathname "/" would resolve to server "<1:ramdisk>",
  4649. relative pathname "".
  4650.  
  4651. The user process would then contact the appropriate server with the relative
  4652. pathname.  A user process can assume that the prefix table will not change
  4653. while the system is running, so some intelligent caching can be done.  Also,
  4654. directory tokens are given out for executing a "change directory" operation,
  4655. and these server/token pairs can be used for quick relative pathname
  4656. searches.  A symbolic link mechanism is needed to insure that these relative
  4657. searches always follow through correctly.
  4658.  
  4659. 2.7.5. DEVICE SERVERS
  4660.  
  4661. Device servers are just another type of file server, except they control a
  4662. specific device other than a regular disk device, and they are likely to
  4663. support some custom operations and return error codes if some disk operations
  4664. are attempted.  The interface is identical to a file server for convenience.
  4665.  
  4666. 2.7.6. CONSOLE SERVER
  4667.  
  4668. Just a specific device server.  It handles window management and console
  4669. calls, like WinClear, WinPut, GetKey, and ConWrite, that are used in ACE.
  4670.  
  4671. 2.8. ASYNCHRONOUS EVENT HANDLING
  4672.  
  4673. As mentioned in the Process section above, there are many external events
  4674. that a process may have to wait for, including:  modem characters, disk drive
  4675. operations (if they are custom-programmed correctly), mouse & joystick
  4676. movements, and real-time delays.  There will be an AwaitEvent() kernel
  4677. primitive to allow a process to wait for one of these events to happen.
  4678. Normally, the only processes that wait for these events will be device
  4679. drivers.  The kernel will also have to do some low-level processing for of
  4680. some devices (like the modem and keyboard) to insure that things don't become
  4681. unnecessarily inefficient.
  4682.  
  4683. 3. KERNEL DESIGN
  4684.  
  4685. Next time.
  4686.  
  4687. 4. SYSTEM SERVER DESIGN
  4688.  
  4689. Next time.
  4690.  
  4691. 5. APPLICATION PROGRAM INTERFACE
  4692.  
  4693. Next time.
  4694.  
  4695. This is quite similar to the ACE-128/64 Programmer's Reference Guide, which
  4696. is available via anonymous FTP from "ccnga.uwaterloo.ca" in file
  4697. "/pub/cbm/os/ace/ace-r10-prg.doc".  Release #10 of ACE was the most current
  4698. at the time of writing this article.
  4699.  
  4700. 6. CONCLUSION
  4701.  
  4702. Next time.
  4703.  
  4704. Implementation: someday, maybe.
  4705.  
  4706. ==================================================================---END---===
  4707.  
  4708.