home *** CD-ROM | disk | FTP | other *** search
/ Brotikasten / BROTCD01.iso / texte / cbmhack3.txt < prev    next >
Text File  |  1995-08-20  |  127KB  |  3,160 lines

  1.  
  2.                    ########
  3.              ##################
  4.          ######            ######
  5.       #####
  6.     #####  ####  ####      ##      #####   ####  ####  ####  ####  ####   #####
  7.   #####    ##    ##      ####    ##   ##   ##  ###     ##    ####  ##   ##   ##
  8.  #####    ########     ##  ##   ##        #####       ##    ## ## ##   ##
  9. #####    ##    ##    ########  ##   ##   ##  ###     ##    ##  ####   ##   ##
  10. #####  ####  ####  ####  ####  #####   ####  ####  ####  ####  ####   ######
  11. #####                                                                    ##
  12.  ######            ######        Volume 1 - Issue 3
  13.    ##################              July 15, 1992
  14.        ########
  15.  
  16. =============================================================================
  17. Editor's Notes:
  18. by Craig Taylor (duck@pembvax1.pembroke.edu)
  19.  
  20.   Here's over 3000 lines of hacking articles & such... Sorry about the length
  21. as some of the articles ran a bit overboard.  Included within is a discussion of
  22. the KERNAL routines, an examination of Rasters, and a package of burst routines
  23. for use in your own programs. If you've got any ideas for articles etc that  
  24. you'd like to see or want to hear more on a certain topic feel free to email 
  25. me. 
  26.  
  27.   I'm pleased to introduce the Demo Corner where each month we'll report 
  28. how to achieve some of the graphic and sound effects that are present in 
  29. many demos that are wondered about.
  30.  
  31.   Note: The article concerning programming and usage of the 1351 mouse has
  32. been delayed until the next issue due to time and length constraints.
  33.  
  34.   This file is available via anonymous ftp at tybalt.caltech.edu under 
  35. pub/rknop/hacking.mag.  Back issues of C= Hacking are also located there.
  36.  
  37. **************** WARNINGS, UPDATES, BUG REPORTS, ETC... **********************
  38.  
  39.   OOPS - In the last issue of C= Hacking in Mark Lawrence's File Splitter a line
  40. inadvertantly got chopped off.  The following code should be fixed between the 
  41. comments that are listed:
  42.  
  43. [.
  44.   .
  45.    .] 
  46.    { Make EXTENSION a string representation of COUNT, to be added to the
  47.       OutFileName to make things a tad easier}
  48.  
  49.     OutFileName := Concat(NewFile,'.',Copy('00',1,3-Length(Extension)),
  50.                    Extension);   {**THIS IS THE STATEMENT...**}
  51.  
  52.     { Create filename based on which part we're up to }
  53. [.
  54.   .
  55.    .]
  56.  
  57. =============================================================================
  58. Note: Permission is granted to re-distribute this "net-magazine", in whole,
  59.   freely for non-profit use. However, please contact individual authors for
  60.   permission to publish or re-distribute articles seperately.
  61.  
  62.       *** AUTHORS LISTED BELOW RETAIN ALL RIGHTS TO THEIR ARTICLES ***
  63. =============================================================================
  64. In This Issue:
  65.  
  66. Learning ML - Part 3
  67.  
  68.   In this edition we take a look at reading and writing commands to the disk
  69. drive, including reading the disk directory and error channel. This article
  70. parallels the discussion of the C=128 and C=64 KERNAL jump tables of available
  71. routines. Written by Craig Taylor.
  72.  
  73. The Demo Corner: Missing Cycles
  74.  
  75.   Everybody knows that there are 63 cycles available to the C64 processor
  76. on each scan line, except for one which only provides 23 cycles. But what
  77. happens when we add sprites and why ? Written by Pasi 'Albert' Ojala.
  78.  
  79. KERNAL 64/128
  80.  
  81.   The C=128 and C=64 jump table points to many valuable system routines is
  82. discussed and examined in detail. Written by Craig Taylor.
  83.  
  84. 64K VDC RAM and an alternate GEOS128 Background Screen
  85.  
  86.   Standard GEOS only uses the first 16K of your VDC screen.  If you have 64K
  87. of VDC RAM, and want to write an 80-column only application, you can put some
  88. of the additional VDC RAM to use as a replacement for the standard GEOS
  89. background screen.  And, in the bargain, you get an additional 16K of
  90. application FrontRAM to use! Written by Robert Knop.
  91.  
  92. GeoPaint File Format
  93.  
  94.   Written by Bruce Vrieling, this article provides an in depth description of
  95. exactly how geoPaint stores its graphic images on disk. It examines the
  96. concept of VLIR files, how graphics data is laid out on screen (from both
  97. geoPaint and the VIC's perspective), and geoPaint's graphics compression
  98. techniques.
  99.  
  100. Rasters - What They Are and How to Use Them
  101.   
  102.   Written by Bruce Vrieling, this article provides an introduction to creating
  103. special on-screen effects using the technique of raster interrupts. The
  104. basics are examined, including what they are, and how to program them. This
  105. article should provide a good starting point for someone wanting to get
  106. their feet wet in raster programming.
  107.  
  108. Bursting Your 128: The Fastload Burst Command
  109.  
  110.   Written by Craig Bruce this article covers the Fastload burst command of the
  111. 1571 and 1581 disk drives.  The Fastload command operation and protocol are
  112. discussed and a package for using the Fastload command to read regular
  113. sequential files at binary program loading speeds is presented.  To demonstrate
  114. the package, a file word counting utility is implemented and the "commented"
  115. code is included.
  116.  
  117. ============================================================================
  118. Learning ML - Part 3
  119. by Craig Taylor (duck@pembvax1.pembroke.edu)
  120.  
  121.   Last time we used a routine at $FFD2 which would print out the character code
  122. contained within the accumalator.  That location will always print the character
  123. out regardless of VIC-20, C=64, C=128 and even PET because Commodore decided 
  124. to set up some locations in high memory that would perform routines that are
  125. commonly needed.  
  126.  
  127.   Take a look now at the KERNAL 64/128 article and glance over some of the 
  128. routines and their function / purpose. This article is meant to be a companion
  129. to that article so you may want to flip back and forth as the discussion 
  130. of the program listed below is discussed.
  131.  
  132.   Note that I've borrowed Craig Bruce's notation of having listings inside. To
  133. extract the source that follows enter the following command on a Unix system:
  134.  
  135. grep '^\.@...\!' Hack3 | sed 's/^.@...\!.//' | sed 's/.@...\!//' >dir.asm
  136.  
  137. .@001! ;
  138. .@002! ; Set up computer type for computer-dependant code / 
  139. .@003! ;    Only used in displaying # routine / start of assembly setting.
  140. .@004! ; BUDDY format.
  141. .@005! ;
  142. .@006! computer = 128             ; Define as either 64 or 128.
  143.  
  144.   For both c64 and c128 users the following code works.  Within the code is 
  145. conditional assembly which means it will work on either computer assuming that
  146. the computer is equal to either 128 or 64.
  147.  
  148. .@007! 
  149. .@008! .if computer-64            ;** if computer not c64 then
  150. .@009!       .org $1300          ;   and also make sure in BANK 15 when calling
  151. .@010!                           ;   these routines.
  152. .@011! .else                      ;** else if _is_ c64, then
  153. .@012!       .org $c000
  154. .@013! .ife                       ;** end of computer-dependant code.
  155.  
  156.   Because of this (the source is in BUDDY format) the C64 and C128 are set to 
  157. assemble at different memory locations. On the C64, $c000 is 49152. On the C128 
  158. it is at 4864. Note for the C128 it is necessary to do a BANK15 before executing
  159. the code.
  160.           
  161. .@014!       .mem                ; - assemble to memory.
  162.  
  163.   This tells the assembler to actually put the code into memory.
  164.  
  165. .@015!
  166. .@016! ;;-----------------------------------------------------------------------
  167. .@017! ;; KERNAL EQUATES
  168. .@018! ;;---------------------------------------------------------------------
  169. .@019! 
  170. .@020! setnam = $ffbd
  171. .@021! setlfs = $ffba
  172. .@022! open   = $ffc0
  173. .@023! close  = $ffc3
  174. .@024! chkin  = $ffc6
  175. .@025! chrin  = $ffcf
  176. .@026! bsout  = $ffd2
  177. .@027! clrch  = $ffcc
  178. .@028!
  179.  
  180.   These are the KERNAL routines we will actually be using. Their actual 
  181. use will be documented when we come across them within the code.  
  182.  
  183. .@029! ;;-----------------------------------------------------------------------
  184. .@030!
  185. .@031! temp   = 253
  186. .@032! charret = $0d
  187. .@033! space = $20
  188. .@034!
  189.  
  190.   Temp is set up to just be a temporary location in zero-page. Location 253 on
  191. both the C64 and C128 is unused.  Charret stands for the carriage return
  192. character and is the equivlent of a chr$(13). Space stands for the code for a 
  193. space (a chr$(32))
  194.  
  195. .@035! ;;---------------------------------------------------------------------
  196. .@036!
  197. .@037! start = *
  198. .@038!
  199. .@039!    jsr read'dir       ; Initial jump table -- Note: Will read error after
  200. .@040!    jmp read'err       ;     showing directory.
  201. .@041!
  202.  
  203.   You'll see code like this a lot -- Basically we're building what is known as a
  204. jump table. That way if we add more code to the directory or error routine we
  205. don't have to worry about our SYS call's changing. To read the directory just
  206. SYS base, to read the error channel just SYS base+3 (where BASE is 49152 on the
  207. C64, 4864 on the 128)... 
  208.  
  209.   Also the JSR JMP combination may seem a little strange but what we are doing
  210. is treating the directory routine as a subroutine and then JUMPING to the 
  211. error routine. Once we do that the RTS in read'err will return us back to basic.
  212.  
  213. .@042! ;;----------------------------------------------------------------------
  214. .@043!
  215. .@044! read'dir = *
  216. .@045! 
  217. .@046! ; Opens and reads directory as a basic program.
  218. .@047! ;==
  219. .@048! ; Basic programs are read in as follows:
  220. .@049! ;                  [Ptr to Next Line]:2 [Line #]:2 [Text]:.... [$00 byte]
  221. .@050! ;                  ^^^^^^^^^^^REPEATS^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  222. .@051! ; The end of a program is signifed by the $00 byte signifying end of text
  223. .@052! ;    and the ptr's also being = $00.
  224. .@053! ;==
  225.  
  226.   There are several ways to read the directory in machine language.  What we are
  227. doing here is taking advantage of the drive's ability to allow us to load the
  228. directory as a basic program -*except*- we aren't loading it per se. We're 
  229. gonna grab each byte as it comes from the drive and interpret it ourselves
  230. instead of putting it in memory as would normally be done.
  231.  
  232.   Basic programs are stored as the following: A 2 byte pointer, a 2 byte
  233. line #, the basic text, and a null terminator and then starting over
  234. from the 2 byte pointer.  The pointer we do not need, the line # is the number
  235. of blocks the file takes up and the TEXT is the program name and file type. We
  236. know when we're finished on the line by checking for a $00 byte.
  237.  
  238. .@054!                                ; Begin by opening up the 
  239. .@055!                                ; directory file ("$").
  240. .@056!        lda #$01                ;   length is 1        
  241. .@057!        ldx #<dir               ;   lo byte pointer to file name.
  242. .@058!        ldy #>dir               ;   hi byte pointer to file name.
  243. .@059!        jsr setnam              ; - call setnam
  244.  
  245.   Okay, first we need to simulate opening the directory as a program file.
  246. SETNAM sets up the filename for the open command.  In effect we are giving the 
  247. basic syntax of open file#,device#,channel#,"filename" in reverse.
  248.  
  249. .@060!        lda #$01                ;   file # 1
  250. .@061!        ldx #$08                ;   device # 8
  251. .@062!        ldy #$00                ;   channel # 0
  252. .@063!        jsr setlfs              ; - call setlfs
  253.  
  254.   Here we specify the device #, file #, channel # in preperation for the open.
  255.  
  256. .@064!        jsr open                ; - call open
  257.  
  258.   Open up the file. This is the routine that does the real work. SETNAM and
  259. SETLFS were preparatory routines for this.
  260.  
  261. .@065!  ;
  262. .@066!  ; read in the bytes and display (skipping line links etc)
  263. .@067!  ;
  264. .@068!        ldx #$01               ;   file #1
  265. .@069!        jsr chkin              ; - call chkin to set input file #.
  266.  
  267.   Now we need to specify the input file # and tell the computer that all further
  268. chrin's are to be from file #1. (By default, it would have read from the 
  269. keyboard unless we had this here).
  270.  
  271. .@070!        jsr chrin              ; - ignore starting address (2 bytes)
  272. .@071!        jsr chrin 
  273.  
  274.   Skip the starting address -- When reading the directory it is not relevant
  275. so read the bytes and discard them.
  276.  
  277. .@072!  skip  jsr chrin              ; - ignore pointer to next line (2 bytes)
  278.  
  279.   Now we skip the pointer for the next line. This is only used when loading
  280. basic programs to re-link the lines. When listing the directory they are not
  281. needed.
  282.  
  283. .@073!  bck1  jsr chrin
  284.  
  285.   This is still part of the routine that skips the pointer to the next line, yet
  286. it has a label used below that allows us to check for end of file more easily.
  287.  
  288. .@074!  line  jsr chrin              ; - get line # lo.
  289. .@075!        sta temp               ; - store lo of line # @ temp
  290. .@076!        jsr chrin              ; - get hi of line #
  291.  
  292.   Here we get the line # as the next 2 bytes in the file.
  293.  
  294. .@077! 
  295. .@078! .if computer-64               ; * if C128 then
  296.  
  297.   Unfortunately C= did not provide a nice routine in the KERNAL to display 
  298. numeric values - however - by exploring inside the operating system a way to 
  299. display numbers is there.  Note that the following may look confusing -- if it
  300. does just rest assured it will print out the line # correctly.
  301.   
  302. .@079!        sta $61
  303. .@080!        ldy temp
  304. .@081!        sty $60
  305. .@082!        lda #$00
  306. .@083!        sta $63
  307. .@084!        ldy temp                ;   store values for conversion.
  308. .@085!        jsr $ba07               ; - MONITOR routine: convert to BCD values
  309. .@086!        lda #$00
  310. .@087!        ldx #$08
  311. .@088!        ldy #$03
  312. .@089!        jsr $ba5d               ; - MONITOR routine: print BCD 
  313. .@090!                                ;values in decimal
  314.  
  315.   This is the C128 version which uses some of the MONITOR routines to display
  316. the numeric block size.
  317.  
  318. .@091! .else                          ; * else if c64
  319. .@092!        ldx temp 
  320. .@093!        jsr $bdcd               ; - print line # (w/in ROM routine).
  321. .@094! .ife                           ; * end of computer dependant code.
  322.  
  323.   This is the C64 code to display a numeric value (notice how much simplified it
  324. is over the C128)...
  325.  
  326. .@095!
  327. .@096!        lda #space
  328. .@097!        jsr bsout               ; - print space
  329.  
  330.   Let's print a space between the filename and the block size.
  331.  
  332. .@098!  gtasc jsr chrin               ; - start printing filename until 
  333. .@099!                                ;end of line.
  334. .@100!        beq chck                ;   (Zero signifies eol).
  335. .@101!        jsr bsout               ; - Print character
  336. .@102!        sec
  337. .@103!        bcs gtasc               ;   and jump back.
  338.  
  339.   Now we start getting a character (line #98), if zero we branch out of the loop
  340. (line #100), else we display the character (#101), and jump back (#102-03).
  341.  
  342. .@104!  chck  lda #charret            ; - Else we need to start the next line
  343. .@105!        jsr bsout               ;   Print a carriage return.
  344.  
  345.   Ah, we got to a null byte so that's the end of this line - display a car/ret.
  346.  
  347. .@106!        jsr chrin               ; - And get the next pointer
  348. .@107!        bne bck1                ;   If non-zero go, strip other ptr,
  349. .@108!                                ; and continue.
  350.  
  351.   This is where we branch back -- we are checking here for 2 null bytes on 
  352. input.  We get the first byte of the pointer and if it's non-zero then we know
  353. it's not the end of the directory so we jump back to discard the second byte at
  354. line #73.
  355.  
  356. .@109!        jsr chrin               ; - Else check 2nd byte of pointer
  357. .@110!        bne line                ;   as if both 0 then = end of directory.
  358.  
  359.   This is a continuation of the checking above. This time we're getting the 
  360. 2nd byte and checking for 0.  If it's not we jump back to get and display the
  361. line # etc. If it is 0 then that means we had $0000 for the next pointer which
  362. means that it's the end of the directory.
  363.  
  364. .@111!  ;
  365. .@112!  ;had 3 0's in a row so end of prog
  366. .@113!  ;now close the file.
  367. .@114!  ;
  368. .@115!        lda #$01                ;   file # to close
  369. .@116!        jsr close               ; - so close it
  370. .@117!        jsr clrch               ; - clear all channels
  371. .@118!        rts                     ; - and return to basic
  372. .@119!
  373.  
  374.   We then close the file by specifying the file # and calling close. We then 
  375. tell the computer to reset all the default input / output devices by calling
  376. clrch (remember we changed the default input channel??). And then we can return
  377. to where this routine was called from.
  378.  
  379. .@120! ; FILENAME string
  380. .@121! dir    .asc "$"
  381.  
  382.   This is the string that is pointed to by the SETNAM call. Note that a search
  383. pattern could be set by
  384.       line#121:       .asc "$hack*" 
  385. and by changing the length set in .A in the call in line #56.
  386.  
  387. .@122!
  388. .@123! ;;-----------------------------------------------------------------------
  389. .@124!
  390. .@125! read'err = *
  391. .@126! 
  392. .@127! ; This routine simply grabs bytes from a channel 15 it opens up until
  393. .@128! ;   a car/ret byte is found. Then it closes and returns.
  394. .@129! 
  395.  
  396.   Reading the error channel is much much more simpler than reading the 
  397. directory.  Basically we just open up the channel (specifying a null name) and
  398. repeatadly get bytes until a car/ret is found.
  399.  
  400. .@130! rderr  lda #$00                ;   length is 0
  401. .@131!        jsr setnam              ; - call setname
  402.  
  403.   Setup so we don't specify a name (length = 0).
  404.  
  405. .@132!        lda #$0f                ;   file # (15)
  406. .@133!        ldx #$08                ;   device # (08)
  407. .@134!        ldy #$0f                ;   channel # (15)
  408. .@135!        jsr setlfs              ; - set logical file #
  409.  
  410.   Do the equivlent of open 15,8,15.
  411.  
  412. .@136!        jsr open                ; - and open it.
  413.  
  414.   Open it.
  415.  
  416. .@137!  ;specify file as input
  417. .@138!        ldx #$0f                ;   file 15 is input
  418. .@139!        jsr chkin               ; - so specify it.
  419.  
  420.   Now set up file # 15 as input so we can start getting, displaying etc until
  421. a car/ret is found.
  422.  
  423. .@140!  ;now read in file
  424. .@141!  loop  jsr chrin               ; - read char
  425. .@142!        jsr bsout               ; - print char
  426. .@143!        cmp #charret            ;   is it return?
  427. .@144!        bne loop                ; - if not jmp back
  428.  
  429.   Read in and display the characters from the error channel until a char/ret is
  430. found.
  431.  
  432. .@145!  ;now close the file
  433. .@146!        lda #$0f                ;   file #
  434. .@147!        jsr close               ; - close the file
  435. .@148!        jsr clrch               ;   restore i/o
  436.  
  437.   And once it is, we close the file and restore the default i/o settings.
  438.  
  439. .@149!  ;now return to basic
  440. .@150!        rts
  441.  
  442.   And return to our caller, in this case - basic.
  443.  
  444. ============================================================================
  445. [ The Demo Corner is going to be a column where each month we'll be 
  446.   introduced to a new feature (some people call them bugs, we'll call them
  447.   features) of the Commodore 64 or 128 in the Video and Sound areas that 
  448.   have commonly been shown on demos but with no mention of how to accomplish
  449.   them. Note that readers may also want to take a look at the introduction
  450.   to Rasters elsewhere in this magazine.]
  451.  
  452. The Demo Corner: Missing Cycles
  453. by Pasi 'Albert' Ojala   (po87553@cs.tut.fi albert@cc.tut.fi)
  454.                           Written on  15-May-91  Translation 30-May-92
  455.  
  456.  
  457.                           Missing Cycles
  458.                           --------------
  459.        [all timings are in PAL, the principle applies to NTSC too]
  460.  
  461. Everybody knows that there are 63 cycles available to the C64 processor on
  462. each scan line, except for one which only provides 23 cycles (later referred
  463. to as a "bad" scan line). But what happens when we add sprites and why ?
  464.  
  465. In the C64, the VIC (video interface controller) has much more to do than
  466. just showing graphics on the screen. It also handles the memory refresh.
  467. On each scanline, it has to refresh five rows in the memory matrix and
  468. fetch fourty bytes of graphics data.
  469.  
  470. The VIC does all of this during the cycles (phase 1) that the processor is
  471. not using the memory.  These cycles, however, are not sufficient when the
  472. VIC also needs to access the character and color codes for the next row.
  473. The memory bus can't be used by the CPU and the VIC at the same time, so CPU
  474. access to the bus must be denied to allow the VIC to fetch its data.
  475. Fortunately, the VIC bus (12-bit wide) allows the character (8 bits) and
  476. color (4 bits) codes to be fetched at the same time.
  477.  
  478.  
  479. _Understanding how sprites work_
  480.  
  481. If there are sprites on the screen, the VIC needs even more cycles to fetch
  482. all of the graphics data. Scan lines are time divided so that there is
  483. enough time for all action during one line. On each line, the sprite
  484. image pointers are fetched during phase 1. If the sprite is to be displayed
  485. on that line, the three bytes of image data are fetched right after that.
  486. Out of these three fetches, two take place during phase 2 of the clock,
  487. so the processor will lose these. On average, two clock cycles are lost
  488. for each sprite that is displayed on that line.
  489.  
  490. But how is it possible for all eight sprites to only take 16-19 cycles
  491. (depending on the timing) when we have observed that one sprite requires
  492. three cycles? And why do sprites 0, 2, 4, 6 and 7 together take up as many
  493. cycles as all eight sprites ? The answer may be found in the way the VIC
  494. tells the CPU that it needs additional cycles.
  495.  
  496.  
  497. _The BA signal_
  498.  
  499. When the VIC wants to use the bus, the BA (Bus Available) signal goes
  500. inactive. This will happen three cycles before the bus must be released !
  501. During these three cycles, the CPU must complete all memory accesses or
  502. delay them until it has the bus again.
  503.  
  504. The CPU either completes the current instruction in the remaining cycles
  505. or sits and waits for the bus to become available again. It can't execute
  506. a new instruction as long as it doesn't have the bus. This is why cycles
  507. seem to be lost (besides those stolen directly for the sprites). Usually,
  508. all 8 sprites take 17 cycles while one sprite takes three cycles. However,
  509. the CPU may continue to execute an instruction if it does not use the bus.
  510.  
  511.  
  512. _Theory and speculation_
  513.  
  514. Let's suppose that all the sprites are enabled and on the same scan line.
  515. Then, the VIC steals 16 cycles (2 cycles for each sprite) for the memory
  516. fetches and 3 cycles as overhead for the BA signal, for a total of 19 cycles.
  517. However, it will be usually less because the CPU will use some of the cycles
  518. when the bus request is pending.
  519.  
  520. If we now disable sprite 4, no cycles are released for the CPU's use. This
  521. is because during the previous sprite 4 data fetch, the VIC already signals
  522. that it needs the bus for the sprite 5 data fetch and BA stays low (Refer
  523. to the timing chart). Thus, the CPU never sees BA go high during sprite 4
  524. and 2 cycles are still lost.
  525.  
  526. Accordingly, if we only turn off sprites 1, 3 and 5 we get no cycles back
  527. from the VIC. So in time-critical raster routines, always use sprites in
  528. order.
  529.  
  530.  
  531. _What can we do with this feature ?_
  532.  
  533. How can this be useful? A good use is for synchronization. Normally,
  534. before the CPU starts to execute the raster interrupt code, it's executing
  535. an instruction of undefined cycle-length. This execution time varies from
  536. two to seven cycles.
  537.  
  538. With a sprite, you can do the synchronization with a minimal effort using
  539. a DEC or INC instruction in the right place. If the processor is early,
  540. it has to wait for the bus, otherwise it will continue to execute cycles
  541. from the instruction.
  542.  
  543. I have never experimented with any other instruction than DEC/INC, but
  544. some others should work also. You need an instruction which has a cycle that
  545. do not need the bus to be available. e.g. INC $3fff will increase the
  546. value during the fifth cycle and do not need the bus for that.
  547.  
  548.  
  549. _A demo program_
  550.  
  551. The enclosed program includes a short raster color routine to demonstrate
  552. this strict timing and synchronization. The background color is changed
  553. 12 times on each line. The electron beam runs over eight pixels during
  554. one cycle, so the timing must be precise.
  555.  
  556. --------------------------------------------------------------------------
  557. _Table for PAL VIC timing for the Missing cycles_
  558.  
  559.  
  560. 012345678901234567890123456789012345678901234567890123456789012 cycles
  561.  
  562. Normal scan line, 0 sprites
  563. ggggggggggggggggggggggggggggggggggggggggrrrrr  p p p p p p p p  phi-1 VIC
  564.                                                                 phi-2 VIC
  565. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx phi-2 6510
  566. 63 cycles available
  567.  
  568. Normal scan line, 8 sprites
  569. ggggggggggggggggggggggggggggggggggggggggrrrrr  pspspspspspspsps phi-1 VIC
  570.                                                ssssssssssssssss phi-2 VIC
  571. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxXXX                 phi-2 6510
  572. 46-49 cycles available
  573.  
  574. Normal scan line, 4 sprites
  575. ggggggggggggggggggggggggggggggggggggggggrrrrr  psp psp psp psp  phi-1 VIC
  576.                                                ss  ss  ss  ss   phi-2 VIC
  577. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxXXX              xx phi-2 6510
  578. 48-51 cycles available
  579.  
  580. Bad scan line, 0 sprites
  581. ggggggggggggggggggggggggggggggggggggggggrrrrr  p p p p p p p p  phi-1 VIC
  582. cccccccccccccccccccccccccccccccccccccccc                        phi-2 VIC
  583.                                         xxxxxxxxxxxxxxxxxxxxxxx phi-2 6510
  584. 23 cycles available
  585.  
  586. Bad scan line, 8 sprites
  587. ggggggggggggggggggggggggggggggggggggggggrrrrr  pspspspspspspsps phi-1 VIC
  588. cccccccccccccccccccccccccccccccccccccccc       ssssssssssssssss phi-2 VIC
  589.                                         xxxxXXX                 phi-2 6510
  590. 4-7 cycles available
  591.  
  592.  
  593. g= grafix data fetch (character images or graphics data)
  594. r= refresh
  595. p= sprite image pointer fetch
  596. c= character and color CODE fetch during a bad scan line
  597. s= sprite data fetch
  598. x= processor executing instructions
  599. X= processor executing an instruction, bus request pending
  600.  
  601. Observe! The left edge of the chart is not the left edge of the screen nor
  602.      the left edge of the beam, but the sprite x-coordinate 0. If you
  603.      have opened the borders, you know what I mean. A sprite can be
  604.      moved left from the coordinate 0 by using x-values greater than 500.
  605.  ___________
  606. |  _______  |<-- Maximum sized video screen
  607. |||       | |
  608. |||       |<-- Normal C64 screen
  609. |||       | |
  610. |||_______| |
  611. ||          |
  612. ||__________|
  613.  ^ Sprite coordinate 0
  614.  
  615.  
  616. --------------------------------------------------------------------------
  617. Demonstration program for missing cycles
  618.  
  619.  
  620. COLOR0= $CE00  ; Place for color bar 0
  621. COLOR1= $CF00  ; Place for color bar 1
  622. RASTER= $FA    ; Line for the raster interrupt
  623. DUMMY= $CFFF   ; Timing variable
  624.  
  625. *= $C000
  626.         SEI             ; Disable interrupts
  627.         LDA #$7F        ; Disable timer interrupts
  628.         STA $DC0D
  629.         LDA #$01        ; Enable raster interrupts
  630.         STA $D01A
  631.         STA $D015       ; Enable Sprite 0
  632.         LDA #<IRQ       ; Init interrupt vector
  633.         STA $0314
  634.         LDA #>IRQ
  635.         STA $0315
  636.         LDA #$1B
  637.         STA $D011
  638.         LDA #RASTER     ; Set interrupt position (inc. 9th bit)
  639.         STA $D012
  640.         LDA #RASTER-20  ; Sprite will just reach the interrupt position
  641.         STA $D001       ;  when it is positioned 20 lines earlier
  642.  
  643.         LDX #51
  644.         LDY #0
  645.         STA $D017       ; No Y-enlargement
  646. LOOP0   LDA COL,X       ; Create color bars
  647.         PHA
  648.         AND #15
  649.         STA COLOR0,X
  650.         STA COLOR0+52,Y
  651.         STA COLOR0+104,X
  652.         STA COLOR0+156,Y
  653.         PLA
  654.         LSR
  655.         LSR
  656.         LSR
  657.         LSR
  658.         STA COLOR1,X
  659.         STA COLOR1+52,Y
  660.         STA COLOR1+104,X
  661.         STA COLOR1+156,Y
  662.         INY
  663.         DEX
  664.         BPL LOOP0
  665.         CLI             ; Enable interrupts
  666.         RTS             ; Return
  667.  
  668.  
  669. IRQ     NOP             ; Wait a bit
  670.         NOP
  671.         NOP
  672.         NOP
  673.         LDY #103        ; 104 lines of colors (some of them not visible)
  674.             ; Reduce for NTSC, 55 ?
  675.         INC DUMMY       ; Handles the synchronization with the help of the
  676.         DEC DUMMY       ;  sprite and the 6-clock instructions
  677.             ; Add a NOP for NTSC
  678.  
  679. FIRST   LDX COLOR0,Y    ; Do the color effects
  680. SECOND  LDA COLOR1,Y
  681.         STA $D020
  682.         STX $D020
  683.         STA $D020
  684.         STX $D020
  685.         STA $D020
  686.         STX $D020
  687.         STA $D020
  688.         STX $D020
  689.         STA $D020
  690.         STX $D020
  691.         STA $D020
  692.         STX $D020
  693.             ; Add a NOP for NTSC (one line = 65 cycles)
  694.         LDA #0          ; Throw away 2 cycles (total loop = 63 cycles)
  695.         DEY
  696.         BPL FIRST       ; Loop for 104 lines
  697.  
  698.         STA $D020
  699.         LDA #103        ; For subtraction
  700.         DEC FIRST+1     ; Move the bars
  701.         BPL OVER
  702.         STA FIRST+1
  703. OVER    SEC
  704.         SBC FIRST+1
  705.         STA SECOND+1
  706.  
  707.         LDA #1          ; Ack the raster interrupt
  708.         STA $D019
  709.         JMP $EA31       ; Jump to the standard irq handler
  710.  
  711. COL     BYT $09,$90,$09,$9B,$00,$99,$2B,$08,$90,$29,$8B,$08,$9C,$20,$89,$AB
  712.         BYT $08,$9C,$2F,$80,$A9,$FB,$08,$9C,$2F,$87,$A0,$F9,$7B,$18,$0C,$6F
  713.         BYT $07,$61,$40,$09,$6B,$48,$EC,$0F,$67,$41,$E1,$30,$09,$6B,$48,$EC
  714.         BYT $3F,$77,$11,$11
  715.                         ; Two color bars
  716.  
  717. --------------------------------------------------------------------------
  718. Basic loader for Missing cycles example program (PAL)
  719.  
  720. 1 S=49152
  721. 2 DEFFNH(C)=C-48+7*(C>64)
  722. 3 CH=0:READA$,A:PRINTA$:IFA$="END"THENPRINT"<clr>":SYS49152:END
  723. 4 FORF=0TO31:Q=FNH(ASC(MID$(A$,F*2+1)))*16+FNH(ASC(MID$(A$,F*2+2)))
  724. 5 CH=CH+Q:POKES,Q:S=S+1:NEXT:IFCH=ATHEN3
  725. 6 PRINT"CHECKSUM ERROR":END
  726. 100 DATA 78A97F8D0DDCA9018D1AD08D15D0A9578D1403A9C08D1503A91B8D11D0A9FA8D, 
  727. 3773
  728. 101 DATA 12D0A9E68D01D0A233A0008D17D0BDACC048290F9D00CE9934CE9D68CE999CCE, 
  729. 4157
  730. 102 DATA 
  731. 684A4A4A4A9D00CF9934CF9D68CF999CCFC8CA10D95860EAEAEAEAA067EEFFCF, 4878
  732. 103 DATA CEFFCFBE18CEB94FCF8D20D08E20D08D20D08E20D08D20D08E20D08D20D08E20, 
  733. 4403
  734. 104 DATA D08D20D08E20D08D20D08E20D0A9008810D18D20D0A967CE64C010038D64C038, 3923
  735. 105 DATA ED64C08D67C0EE19D04C31EA0990099B00992B0890298B089C2089AB089C2F80, 3483
  736. 106 DATA A9FB089C2F87A0F97B180C6F076140096B48EC0F6741E130096B48EC3F771111, 3133
  737. 200 DATA END,0
  738.  
  739. --------------------------------------------------------------------------
  740. Uuencoded C64 executable version (PAL)
  741.  
  742. begin 644 missing.64
  743. M`0@-"`$`4[(T.3$U,@`F"`(`EJ5(*$,ILD.K-#BJ-ZPH0[$V-"D`40@#`$-(?
  744. MLC`ZAT$D+$$ZF4$D.HM!)+(B14Y$(J>9(I,B.IXT.3$U,CJ``(@(!`"!1K(P/
  745. MI#,Q.E&RI4@HQBC**$$D+$:L,JHQ*2DIK#$VJJ5(*,8HRBA!)"Q&K#*J,BDI:
  746. M*0"I"`4`0TBR0TBJ43J74RQ1.E.R4ZHQ.H(ZBT-(LD&G,P#!"`8`F2)#2$5#F
  747. M2U-532!%4E)/4B(Z@``."60`@R`W.$$Y-T8X1#!$1$-!.3`Q.$0Q040P.$0QK
  748. M-40P03DU-SA$,30P,T$Y0S`X1#$U,#-!.3%".$0Q,40P03E&03A$+"`S-S<SA
  749. M`%L)90"#(#$R1#!!.44V.$0P,40P03(S,T$P,#`X1#$W1#!"1$%#0S`T.#(Y?
  750. M,$8Y1#`P0T4Y.3,T0T4Y1#8X0T4Y.3E#0T4L(#0Q-3<`J`EF`(,@-C@T031!4
  751. M-$$T03E$,#!#1CDY,S1#1CE$-CA#1CDY.4-#1D,X0T$Q,$0Y-3@V,$5!14%%>
  752. M045!03`V-T5%1D9#1BP@-#@W.`#U"6<`@R!#149&0T9"13$X0T5".31&0T8X^
  753. M1#(P1#`X13(P1#`X1#(P1#`X13(P1#`X1#(P1#`X13(P1#`X1#(P1#`X13(PH
  754. M+"`T-#`S`$(*:`"#($0P.$0R,$0P.$4R,$0P.$0R,$0P.$4R,$0P03DP,#@XV
  755. M,3!$,3A$,C!$,$$Y-C=#138T0S`Q,#`S.$0V-$,P,S@L(#,Y,C,`CPII`(,@^
  756. M140V-$,P.$0V-T,P144Q.40P-$,S,45!,#DY,#`Y.4(P,#DY,D(P.#DP,CDX[
  757. M0C`X.4,R,#@Y04(P.#E#,D8X,"P@,S0X,P#<"FH`@R!!.49",#@Y0S)&.#=!?
  758. M,$8Y-T(Q.#!#-D8P-S8Q-#`P.39"-#A%0S!&-C<T,44Q,S`P.39"-#A%0S-&V
  759. ;-S<Q,3$Q+"`S,3,S`.@*R`"#($5.1"PP````8
  760. ``
  761. end
  762. size 747
  763.  
  764. --------------------------------------------------------------------------
  765. Uuencoded C64 executable version (NTSC)
  766.  
  767. begin 644 missing.64
  768. M`0@-"`$`4[(T.3$U,@`F"`(`EJ5(*$,ILD.K-#BJ-ZPH0[$V-"D`40@#`$-(?
  769. MLC`ZAT$D+$$ZF4$D.HM!)+(B14Y$(J>9(I,B.IXT.3$U,CJ``(@(!`"!1K(P/
  770. MI#,Q.E&RI4@HQBC**$$D+$:L,JHQ*2DIK#$VJJ5(*,8HRBA!)"Q&K#*J,BDI:
  771. M*0"I"`4`0TBR0TBJ43J74RQ1.E.R4ZHQ.H(ZBT-(LD&G,P#!"`8`F2)#2$5#F
  772. M2U-532!%4E)/4B(Z@``."60`@R`W.$$Y-T8X1#!$1$-!.3`Q.$0Q040P.$0QK
  773. M-40P03DU-SA$,30P,T$Y0S`X1#$U,#-!.3%".$0Q,40P03E&03A$+"`S-S<SA
  774. M`%L)90"#(#$R1#!!.44V.$0P,40P03(S,T$P,#`X1#$W1#!"1$%%0S`T.#(YA
  775. M,$8Y1#`P0T4Y.3,T0T4Y1#8X0T4Y.3E#0T4L(#0Q-3D`J`EF`(,@-C@T031!6
  776. M-$$T03E$,#!#1CDY,S1#1CE$-CA#1CDY.4-#1D,X0T$Q,$0Y-3@V,$5!14%%>
  777. M045!03`S-T5%1D9#1BP@-#@S,`#U"6<`@R!#149&0T9%04)%,#!#14(Y,#!#4
  778. M1CA$,C!$,#A%,C!$,#A$,C!$,#A%,C!$,#A$,C!$,#A%,C!$,#A$,C!$,#A%$
  779. M+"`T-3`R`$(*:`"#(#(P1#`X1#(P1#`X13(P1#`X1#(P1#`X13(P1#!%04$Y.
  780. M,#`X.#$P1#`X1#(P1#!!.38W0T4V-4,P,3`P,SA$-C4L(#,Y-#(`CPII`(,@R
  781. M0S`S.$5$-C5#,#A$-CA#,$5%,3E$,#1#,S%%03`Y.3`P.3E",#`Y.3)",#@Y(
  782. M,#(Y.$(P.#E#,C`X.4%",#@Y0RP@,S4U.`#<"FH`@R`R1C@P03E&0C`X.4,R_
  783. M1C@W03!&.3=",3@P0S9&,#<V,30P,#DV0C0X14,P1C8W-#%%,3,P,#DV0C0XK
  784. M14,S1C<W+"`S,C<T`"<+:P"#(#$Q,3$P,#`P,#`P,#`P,#`P,#`P,#`P,#`PO
  785. M,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`L(#,T`#,+1
  786. ,;`"#($5.1"PP````"
  787. ``
  788. end
  789. size 822
  790.  
  791. ============================================================================
  792. Kernal 64 / 128 
  793. by Craig Taylor (duck@pembvax1.pembroke.edu)
  794.  
  795.                              +--------------+
  796.                              | Introduction |
  797.                              +--------------+
  798.  
  799.   When Commodore introduced the PET ages ago before the Vic-20 and Commodore 64,
  800. 128 they set in the highest memory locations a series of jumps to other routines
  801. so that users didn't need bother checking if any revisions had been made. They
  802. were assured that the address they were jumping to, would indeed, be the address
  803. that would print out a character or whatnot.
  804.  
  805.   The KERNAL has grown since Commodore first introduced it, the C=128 KERNAL has
  806. fifty-seven seperate routines which are available to programmers. These routines
  807. handle functions relating to the serial devices (the bulk of them), the screen
  808. and miscellanous system routines such as scanning the keyboard, updating and
  809. reading the system clock (TI$).
  810.  
  811.                           +-------------------+
  812.                           | Table of Routines |
  813.                           +-------------------+
  814.  
  815.   The following table lists the available routines, their function, address,
  816. their name, and registers affected upon exit. In addation, on the left of each
  817. line are the group that I have catagorized them under: Video(Vid), System(Sys),
  818. and Serial(Ser).
  819.  
  820. --------+---------+---------+---------------------------------------+-----------
  821.         |         |Registers|                                       |Group
  822. Address | NAME    | A X Y F | Descritption                          |Vid Sys Ser
  823. --------+---------+---------+---------------------------------------+-----------
  824. FF47/128|SPINSPOUT| *       | Initializes I/O for fast serial       |        ***
  825. FF4A/128| CLOSEALL| * * *   | Close all files on a device           |        ***
  826. FF4D/128| C64MODE |         | Switches to C=64 mode                 |    *** 
  827. FF50/128| DMACALL | * *     | Send DMA command to REU               |    ***
  828. FF53/128| BOOTCALL| * *   * | Attempts to run boot sector           |    *** ***
  829. FF56/128| PHOENIX | * * *   | Initalizes external/internal cartri.  |    ***
  830. FF59/128| LKUPLA  | * * * * | Looks up logical device #             |    *** ***
  831. FF5C/128| LKUPSA  | * * * * | Looks up for secondary address        |    *** ***
  832. FF5F/128| SWAPPER | * * *   | Switches betten 40 / 80 column screen |*** 
  833. FF62/128| DLCHAR  | * * *   | Initializes 80 column character set   |***
  834. FF65/128| PFKEY   | * * * * | Installs a function key definition    |    ***
  835. FF68/128| SETBNK  |         | Sets bank for any I/O operations      |    *** ***
  836. FF6B/128| GETCFG  | *       | Get MMU configuration for a given bank|    ***
  837. FF6E/128| JSRFAR  |         | Jumps to a subroutine in another bank |    ***
  838. FF71/128| JMPFAR  |         | Starts executing code in another bank |    ***
  839. FF74/128| INDFET  | * *   * | Execute a LDA(fetvec),Y from a bank   |    ***
  840. FF77/128| INDSTA  |   *   * | Stores a value indirectly in a bank   |    ***
  841. FF7A/128| INDCMP  |   *   * | Compares a value indirectly in a bank |    ***
  842. FF7D/128| PRIMM   |         | Outputs null-terminated string        |***     ***
  843. ////////|/////////|/////////|///////////////////////////////////////|///////////
  844. FF81    | CINT    | * * *   | Setup VIC,screen values, 8563...      |*** 
  845. FF84    | IOINIT  | * * *   | Initialize VIC,SID,8563,CIA for system|*** ***
  846. FF87    | RAMTAS  | * * *   | Initialize ram.                       |    ***
  847. FF8D    | VECTOR  | *   *   | Reads or Writes to Kernal RAM Vectors |    ***
  848. FF90    | SETMSG  |         | Sets Kernal Messages On/Off.          |    ***
  849. FF93    | SECND   | *       | Sends secondary address after LISTN   |    *** ***
  850. FF96    | TKSA    | *       | Sends secondary address after TALK    |    *** ***
  851. FF99    | MEMTOP  |   * *   | Read or set the top of system RAM.    |    ***
  852. FF9C    | MEMBOT  |   * *   | Read or set the bottom of system RAM. |    ***
  853. FF9F    | KEY     |         | Scans Keyboard                        |    ***
  854. FFA2    | SETMO   |         | -- Unimplemented Subroutine in All -- |   [N/A]
  855. FFA5    | ACPTR   | *       | Grabs byte from current talker        |    *** ***
  856. FFA8    | CIOUT   | *       | Output byte to current listener       |    *** ***
  857. FFAB    | UNTLK   | *       | Commands device to stop talking       |    *** ***
  858. FFAE    | UNLSN   | *       | Commands device to stop listening     |    *** ***
  859. FFB1    | LISTN   | *       | Commands device to begin listening    |    *** ***
  860. FFB4    | TALK    | *       | Commands device to begin talking      |    *** ***
  861. FFB7    | READSS  | *       | Returns I/O status byte               |        ***
  862. FFBA    | SETLFS  |         | Sets logical #, device #, secondary # |        ***
  863. FFBD    | SETNAM  |         | Sets pointer to filename.             |        ***
  864. FFC0    | OPEN    | * * * * | Opens up a logical file.              |        ***
  865. FFC3    | CLOSE   | * * * * | Closes a logical file.                |        ***
  866. FFC6    | CHKIN   | * * * * | Set input channel                     |        ***
  867. FFC9    | CHKOUT  | * * * * | Set output channel                    |        ***
  868. FFCC    | CLRCH   | * *     | Restore default channels              |        ***
  869. FFCF    | BASIN   | *     * | Input from channel                    |        ***
  870. FFD2    | BSOUT   | *     * | Output to channel (aka CHROUT)        |***     ***
  871. FFD5    | LOAD    | * * * * | Load data from file                   |        ***
  872. FFD8    | SAVE    | * * * * | Save data to file                     |        ***
  873. FFDB    | SETTIM  |         | Sets internal (TI$) clock             |    *** 
  874. FFDE    | RDTIM   | * * *   | Reads internal (TI$) clock            |    ***
  875. FFE1    | STOP    | * *     | Scans and check for STOP key          |    ***
  876. FFE4    | GETIN   | * * * * | Reads buffered data from file         |        ***
  877. FFE7    | CLALL   | * *     | Close all open files and channels     |        ***
  878. FFEA    | UDTIM   | * *     | Updates internal (TI$) clock          |    ***
  879. FFED    | SCRORG  | * * *   | Returns current window/screen size    |*** 
  880. FFF0    | PLOT    |   * * * | Read or set cursor position           |***
  881. FFF3    | IOBASE  |   * *   | Read base of I/O block                |    ***
  882. --------+---------+---------+---------------------------------------+-----------
  883.  
  884.                           
  885.                           +--------------------------+
  886.                           | The Routines Themselves. |
  887.                           +--------------------------+
  888.  
  889. A. Error handling
  890.  
  891.   For the routines in the KERNAL that return status codes (indicated by the FL
  892. status in the chart) the carry is set if there is an error.  Otherwise, the 
  893. carry returned is clear.  If the carry is set, the error code is returned in the
  894. accumalator:
  895.                                            +-----------------------------------+
  896.        .A |Meaning                         | NOTE: Some of the I/O routines    |
  897.       ----+------------------------------  |       indicate the error code via |
  898.         0 | Stop Key pressed               |       the READST routine when     |
  899.         1 | Too Many Open Files            |       setting the carry.          |
  900.         2 | File Already Open              +------------------------------------
  901.         3 | File Not Open
  902.         4 | File Not Found
  903.         5 | Device Not Present
  904.         6 | File Was Not Opened As Input
  905.         7 | File Was Not Opened As Output
  906.         8 | File Name Not Present
  907.         9 | Illegal Device Number
  908.        41 | File Read Error
  909.  
  910.  
  911. B. Device Numbers:
  912.  
  913.   The following table lists the "standard" device numbers used by the C= Kernal.
  914.  
  915.            +---------+----------------------------+
  916.            |Device # | Device Name                |
  917.            +---------+----------------------------+
  918.            |   0     | Keyboard (standard input)  |
  919.            |   1     | Cassette                   |
  920.            |   2     | RS-232                     |
  921.            |   3     | Screen   (standard output) |
  922.            |   4 - 30| Serial Bus Devices         |
  923.            |     4-7 | Printers        (typically)|
  924.            |     8-30| Disk Drives     (typically)|
  925.            +---------+----------------------------+
  926.  
  927. C. Routine Descriptions.
  928.  
  929.   Due to space limitations a fully-detailed, descriptive summary of the KERNAL
  930. routines is not feasible.  However, listed below is a description of what each
  931. routine does, expected parameters and any notes on C=128/C=64 differences as 
  932. well as notes to clarify any possibly confusing details.
  933.  
  934.  ---------------------------------------------------------------------------
  935.  
  936. Routine        : SPINSPOUT ** 128 ONLY **
  937.  Kernal Address: $FF47
  938.  Description   : Setup CIA for BURT protocol.
  939.  Registers In  : .C = 0 -> SPINP (input)
  940.                  .C = 1 -> SPOUT (output)
  941.  Registers Out : .A destroyed
  942.  Memory Changed: CIA, MMU.
  943.  
  944. Routine        : CLOSEALL ** 128 ONLY **
  945.  Kernal Address: $FF4A
  946.  Description   : Close all files on a device.
  947.  Registers In  : .A = device # (0-31)
  948.  Registers Out : .A, .X, .Y used.
  949.  Memory Changed: None.
  950.  
  951. Routine        : C64MODE ** 128 ONLY **
  952.  Kernal Address: $FF4D
  953.  Description   : Switches to C64 Mode
  954.  Registers In  : None.
  955.  Registers Out : None.
  956.  Memory Changed: -ALL- This routine initializes and calls the C64 cold start
  957.                  routine. There is no way to switch out of C64 mode once this
  958.                  routine is entered.
  959.  
  960. Routine        : DMACALL ** 128 ONLY **
  961.  Kernal Address: $FF50
  962.  Description   : Perform DMA command (for REU)
  963.  Registers In  : .X = Bank, .Y = DMA controller command
  964.                  NOTE: REU registers must have been previously setup.
  965.  Registers Out : .A, .X used
  966.  Memory Changed: Dependenant upon REU registers, REU command.
  967.  
  968. Routine        : BOOTCALL ** 128 ONLY **
  969.  Kernal Address: $FF53
  970.  Description   : Attempts to load and execute boot sector from a drive.
  971.  Registers In  : .A = drive # in ascii (usually '0' / $30)
  972.                  .X = device #
  973.  Registers Out : .A, .X, .Y used. .C = 1 if I/O error.
  974.  Memory Changed: As per boot sector. 
  975.  
  976. Routine        : PHOENIX ** 128 ONLY **
  977.  Kernal Address: $FF56
  978.  Description   : Initalizes external / internatal cartridges,check for disk boot
  979.  Registers In  : None.
  980.  Registers Out : .A, .X, .Y used.
  981.  Memory Changed: Calls any auto-start catridges that are installed on the system
  982.  
  983. Routine        : LKUPLA ** 128 ONLY **
  984.  Kernal Address: $FF59
  985.  Description   : Search file tables for a given logical device #.
  986.  Registers In  : .A = Logical Device #.
  987.  Registers Out : .C = 0 if found -> .A = Logical Device #, 
  988.                                     .X = Logical File #,
  989.                                     .Y = Logical Secondary #.
  990.                  .C =1 if not found.
  991.  Memory Changed: None.
  992.  
  993. Routine        : LKUPSA ** 128 ONLY **
  994.  Kernal Address: $FF5C
  995.  Description   : Search file tables for a given secondary address.
  996.  Registers In  : .Y = Secondary address to search for.
  997.  Registers Out : As LKUPLA (see LKUPLA).
  998.  Memory Changed: None.
  999.  
  1000. Routine        : SWAPPER ** 128 ONLY **
  1001.  Kernal Address: $FF5F
  1002.  Description   : Switches between 40 / 80 column screen.
  1003.  Registers In  : None.
  1004.  Registers Out : .A, .X, .Y destroyed.
  1005.  Memory Changed: Screen Editor Locations.
  1006.  
  1007. Routine        : DLCHAR ** 128 ONLY **
  1008.  Kernal Address: $FF62
  1009.  Description   : Initializes 80 column character set.
  1010.  Registers In  : None.
  1011.  Registers Out : .A, .X, .Y destroyed.
  1012.  Memory Changed: None.
  1013.  
  1014. Routine        : PFKEY ** 128 ONLY **
  1015.  Kernal Address: $FF65
  1016.  Description   : Installs a function key definition      
  1017.  Registers In  : .A = pointer to Z-P address (3 bytes : address lo/hi/bank.)
  1018.                  .Y = length, .X = key # (9 = Shift RUN/STOP, 10 = HELP).
  1019.  Registers Out : .C = 1 if No room, .C = 0 if successful.
  1020.                  .A, .X, .Y destroyed.
  1021.  Memory Changed: Function Key Table modified.
  1022.  
  1023. Routine        : SETBNK ** 128 ONLY **
  1024.  Kernal Address: $FF68
  1025.  Description   : Sets bank for any future I/O operations
  1026.  Registers In  : .A = Memory Bank, .X = Bank where filename is.
  1027.  Registers Out : None.
  1028.  Memory Changed: None.
  1029.  
  1030. Routine        : GETCFG ** 128 ONLY **
  1031.  Kernal Address: $FF6B
  1032.  Description   : Get MMU configuration for a given bank.
  1033.  Registers In  : None.
  1034.  Registers Out : None.
  1035.  Memory Changed: 
  1036.  
  1037. Routine        : JSRFAR ** 128 ONLY **
  1038.  Kernal Address: $FF6E
  1039.  Description   : Jumps to a subroutine in another bank.
  1040.  Registers In  : None. (See JMPFAR for mem locations IN)
  1041.  Registers Out : None. (See JMPFAR for mem locations OUT)
  1042.  
  1043. Routine        : JMPFAR ** 128 ONLY **
  1044.  Kernal Address: $FF71
  1045.  Description   : Starts executing code in another bank.  
  1046.  Registers In  : None.
  1047.    Memory In   :  $02 - Bank (0-15)
  1048.                   $03 - PC high
  1049.                   $04 - PC lo
  1050.                   $05 - .S (Processor status)
  1051.                   $06 - .A
  1052.                   $07 - .X
  1053.                   $08 - .Y
  1054.  Registers Out : None.
  1055.    Memory Out  : As memory in.
  1056.  
  1057. Routine        : INDFET ** 128 ONLY **
  1058.  Kernal Address: $FF74
  1059.  Description   : Execute a LDA(fetvec),Y from a bank.
  1060.  Registers In  : .A - pointer to Z-Page location holding address
  1061.                  .X - Bank (0-15), .Y - Index.
  1062.  Registers Out : .A = data, .X - destroyed.
  1063.  Memory Changed: None.
  1064.  
  1065. Routine        : INDSTA ** 128 ONLY **
  1066.  Kernal Address: $FF77
  1067.  Description   : Execute a STA(stavec),Y in a bank.
  1068.  Registers In  : .A - pointer to Z-Page location holding address
  1069.                  .X - Bank (0-15), .Y - Index.
  1070.  Registers Out : .X - Destroyed.
  1071.  Memory Changed: As per registers.
  1072.  
  1073. Routine        : INDCMP ** 128 ONLY **
  1074.  Kernal Address: $FF7A
  1075.  Description   : Executes a CMP(cmpvec),Y in a bank.
  1076.  Registers In  : .A = data, .X = Bank (0-15), .Y - Z-Page ptr.
  1077.  Registers Out : .X destroyed, Flags set accordingly.
  1078.  Memory Changed: None.
  1079.  
  1080. Routine        : PRIMM ** 128 ONLY **
  1081.  Kernal Address: $FF7D
  1082.  Description   : Prints null terminated string following JSR to current channel
  1083.  Registers In  : None.
  1084.  Registers Out : None.
  1085.  Memory Changed: Dependent upon current device. 
  1086.  Example       :
  1087.                [ . . . ]
  1088.                  JSR $FF7D         ; JSR to primm, / print following string.
  1089.                  .ASC "Hi World!"  ; String to print.
  1090.                  .BYT $00          ; IMPORTANT: Null Terminated.
  1091.                [ . . . ]
  1092.  
  1093.  ---------------------------------------------------------------------------
  1094.  
  1095. Routine        : CINT
  1096.  Kernal Address: $FF81
  1097.  Description   : Setup VIC, screen values, (128: 8563)...
  1098.  Registers In  : None.
  1099.  Registers Out : None.
  1100.  Memory Changed: Screen Editor Locations.
  1101.  
  1102. Routine        : IOINIT
  1103.  Kernal Address: $FF84
  1104.  Description   : Initializes pertinant display and i/o devices
  1105.  Registers In  : C64: None. | C128: $0A04/bit 7
  1106.                             |          0 - Full Setup.
  1107.                             |          1 - Partial Setup. (no 8563 char)
  1108.  Registers Out : .A, .X, .Y destroyed.
  1109.  Memory Changed: CIA's, VIC, 8502 port, (C128: also optionally 8563).
  1110.  Note          : This routine automatically distinguishes a PAL system from a
  1111.                  NTSC system and sets PALCNT accordingly for use in the 
  1112.                  time routines.
  1113.  
  1114. Routine        : RAMTAS
  1115.  Kernal Address: $FF87
  1116.  Description   : Clears Z-Page, Sets RS-232 buffers, top/bot Ram.
  1117.  Registers In  : None.
  1118.  Registers Out : .A, .X, .Y destroyed.
  1119.  Memory Changed: Z-Page, Rs-232 buffers, top/bot Ram ptrs
  1120.  
  1121. Routine        : VECTOR
  1122.  Kernal Address: $FF8D
  1123.  Description   : Copies / Stores KERNAL indirect RAM vectors.
  1124.  Registers In  : .C = 0 (Set KERNAL Vectors) | .C = 1 (Duplicate KERNAL vectors)
  1125.                  .XY = address of vectors    | .XY = address of user vectors
  1126.  Registers Out : .A, .Y destroyed            | .A, .Y destroyed.
  1127.  Memory Changed: KERNAL Vectors changed      | Vectors written to .XY
  1128.  Note          : This routine is rarely used, usually the vectors are directly
  1129.                  changed themselves. The vectors, in order, are :
  1130.  
  1131.                  C128: IRQ,BRK,NMI,OPEN,CLOSE,CHKIN,CHKOUT,CLRCH,BASIN,BSOUT
  1132.                        STOP,GETIN,CLALL,EXMON (monitor),LOAD,SAVE
  1133.                  C64 : IRQ,BRK,NMI,OPEN,CLOSE,CHKIN,CHKOUT,CLRCH,BASIN,BSOUT
  1134.                        STOP,GETIN,CLALL,USRCMD (not used),LOAD,SAVE
  1135.  
  1136. Routine        : SETMSG
  1137.  Kernal Address: $FF90
  1138.  Description   : Set control of KERNAL control and error messages.
  1139.  Registers In  : .A bit 7 = KERNAL Control Messages (1 = on)
  1140.                     bit 6 = KERNAL Error   Messages (1 = on)
  1141.  Registers Out : None.
  1142.  Note          : KERNAL Control messages are those defined as Loading, Found etc
  1143.                  ... KERNAL Error messages are I/O ERROR # messages which are
  1144.                  listed as follows:
  1145.  
  1146. Routine        : SECND
  1147.  Kernal Address: $FF93
  1148.  Description   : Sends secondary address to device after a LISTN
  1149.  Registers In  : .A = secondary address
  1150.  Registers Out : .A used.
  1151.  Memory Changed: None.
  1152.  Note          : Low level serial I/O - recommended use OPEN,CLOSE,CHROUT etc..
  1153.  
  1154. Routine        : TKSA
  1155.  Kernal Address: $FF96
  1156.  Description   : Sends secondary address to device after TALK
  1157.  Registers In  : .A = secondary address.
  1158.  Registers Out : .A used.
  1159.  Memory Changed: None.
  1160.  Note          : Low level serial I/O - recommended use OPEN,CLOSE,CHROUT etc..
  1161.  
  1162. Routine        : MEMTOP
  1163.  Kernal Address: $FF99
  1164.  Description   : Read or Set top of System Ram
  1165.  Registers In  : .C = 1 (Read MemTop)     | .C = 0 (Set MemTop)
  1166.                                           | .XY = top of memory
  1167.  Registers Out : .XY = top of memory      | None.
  1168.  Memory Changed: None.                    | Top of memory changed.
  1169.  Note          : On the C=128, this routine refers to the top of BANK 0 RAM, not
  1170.                  BANK 1 RAM.
  1171.  
  1172. Routine        : MEMBOT
  1173.  Kernal Address: $FF9C
  1174.  Description   : Read or Set bottom of System Ram
  1175.  Registers In  : .C = 1 (Read MemBot)     | .C = 0 (Set MemBot)
  1176.                                           | .XY = bottom of memory.
  1177.  Registers Out : .XY = bottom of memory   | None.
  1178.  Memory Changed: None.                    | Bottom of Memory changed.
  1179.  Note          : On the C=128, this routine refers to the bottom of BANK 0 RAM, 
  1180.                  not, BANK 1 RAM.
  1181.  
  1182. Routine        : KEY
  1183.  Kernal Address: $FF9F
  1184.  Description   : Scans Keyboard
  1185.  Registers In  : None.
  1186.  Registers Out : None.
  1187.  Memory Changed: Relevant System Keyboard Values
  1188.  
  1189. Routine        : SETMO
  1190.  Kernal Address: $FFA2
  1191.  Description   : This is a routine who's code never made it into any versions
  1192.                  of the KERNAL on the C64, Vic-20 and C128.  Thus it is of no
  1193.                  pratical use.
  1194.  
  1195. Routine        : ACPTR
  1196.  Kernal Address: $FFA5
  1197.  Description   : Get byte from current talker.
  1198.  Registers In  : None.
  1199.  Registers Out : .A = data byte.
  1200.  Memory Changed: None.
  1201.  Note          : Low level serial I/O - recommended use OPEN,CLOSE,CHROUT etc..
  1202.  
  1203. Routine        : CIOUT
  1204.  Kernal Address: $FFA8
  1205.  Description   : Output byte to current listener.
  1206.  Registers In  : .A = byte.
  1207.  Registers Out : .A used.
  1208.  Memory Changed: None.
  1209.  Note          : Low level serial I/O - recommended use OPEN,CLOSE,CHROUT etc..
  1210.  
  1211. Routine        : UNTLK
  1212.  Kernal Address: $FFAB
  1213.  Description   : Commands current TALK device to stop TALKING.
  1214.  Registers In  : None.
  1215.  Registers Out : .A used.
  1216.  Memory Changed: None.
  1217.  Note          : Low level serial I/O - recommended use OPEN,CLOSE,CHROUT etc..
  1218.  
  1219. Routine        : UNLSN
  1220.  Kernal Address: $FFAE
  1221.  Description   : Commands current listening device to stop listening.
  1222.  Registers In  : None.
  1223.  Registers Out : .A used.
  1224.  Memory Changed: None.
  1225.  Note          : Low level serial I/O - recommended use OPEN,CLOSE,CHROUT etc..
  1226.  
  1227. Routine        : LISTN
  1228.  Kernal Address: $FFB1
  1229.  Description   : Commands device to begin listening.
  1230.  Registers In  : .A = device #.
  1231.  Registers Out : .A used.
  1232.  Note          : Low level serial I/O - recommended use OPEN,CLOSE,CHROUT etc..
  1233.  
  1234. Routine        : TALK
  1235.  Kernal Address: $FFB4
  1236.  Description   : Commands device to begin talking.
  1237.  Registers In  : .A = device #.
  1238.  Registers Out : .A used.
  1239.  Memory Changed: None.
  1240.  Note          : Low level serial I/O - recommended use OPEN,CLOSE,CHROUT etc..
  1241.  
  1242. Routine        : READSS
  1243.  Kernal Address: $FFB7
  1244.  Description   : Return I/O status byte.
  1245.  Registers In  : None.
  1246.  Registers Out : .A = status byte. (see section on ERROR messages).
  1247.  Memory Changed: None.
  1248.  
  1249. Routine        : SETLFS
  1250.  Kernal Address: $FFBA
  1251.  Description   : Set logical file #, device #, secondary # for I/O.
  1252.  Registers In  : .A = logical file #, .X = device #, .Y = secondary #
  1253.  Registers Out : None.
  1254.  Memory Changed: None.
  1255.  
  1256. Routine        : SETNAM
  1257.  Kernal Address: $FFBD
  1258.  Description   : Sets pointer to filename in preperation for OPEN.
  1259.  Registers In  : .A = string length, .XY = string address.
  1260.  Registers Out : None.
  1261.  Memory Changed: None.
  1262.  Note          : To specify _no_ filename specify a length of 0.
  1263.  
  1264. Routine        : OPEN
  1265.  Kernal Address: $FFC0
  1266.  Description   : Open up file that has been setup by SETNAM,SETLFS
  1267.  Registers In  : None.
  1268.  Registers Out : .A = error code, .X,.Y destroyed.
  1269.                  .C = 1 if error.
  1270.  Memory Changed: None.
  1271.  
  1272. Routine        : CLOSE
  1273.  Kernal Address: $FFC3
  1274.  Description   : Close a logical file.
  1275.  Registers In  : .A = logical file #.
  1276.  Registers Out : .A = error code, .X,.Y destroyed.
  1277.                  .C = 1 if error
  1278.  Memory Changed: None.
  1279.  
  1280. Routine        : CHKIN
  1281.  Kernal Address: $FFC6
  1282.  Description   : Sets input channel.
  1283.  Registers In  : .X = logical file #.
  1284.  Registers Out : .A = error code, .X,.Y destroyed.
  1285.                  .C = 1 if error
  1286.  Memory Changed: None.
  1287.  
  1288. Routine        : CHKOUT
  1289.  Kernal Address: $FFC9
  1290.  Description   : Sets output channel.
  1291.  Registers In  : .X = logical file #.
  1292.  Registers Out : .A = error code, .X,.Y destroyed.
  1293.                  .C = 1 if error
  1294.  Memory Changed: None.
  1295.  
  1296. Routine        : CLRCH
  1297.  Kernal Address: $FFCC
  1298.  Description   : Restore default input and output channels.
  1299.  Registers In  : None.
  1300.  Registers Out : .A, .X used.
  1301.  Memory Changed: None.
  1302.  
  1303. Routine        : BASIN
  1304.  Kernal Address: $FFCF
  1305.  Description   : Read character from current input channel.
  1306.                  Cassette - Returned one character a time from cassette buffer.
  1307.                  Rs-232   - Return one character at a time, waiting until 
  1308.                             character is ready.
  1309.                  Serial   - Returned one character at time, waiting if nessc.
  1310.                  Screen   - Read from current cursor position.
  1311.                  Keyboard - Read characters as a string, then return them 
  1312.                             individually upon each call until all characters
  1313.                             have been passed ($0d is the EOL).
  1314.  Registers In  : None.
  1315.  Registers Out : .A = character or error code, .C = 1 if error.
  1316.  Memory Changed: None.
  1317.  
  1318. Routine        : BSOUT aka CHROUT
  1319.  Kernal Address: $FFD2
  1320.  Description   : Output byte to current channel
  1321.  Registers In  : .A = Byte
  1322.  Registers Out : .C = 1 if ERROR (examine READST)
  1323.  Memory Changed: Dependent upon current device.
  1324.  
  1325. Routine        : LOAD
  1326.  Kernal Address: $FFD5
  1327.  Description   : Loads file into memory (setup via SETLFS,SETNAM)..
  1328.  Registers In  : .A = 0 - Load, Non-0 = Verify
  1329.                  .XY = load address (if secondary address = 0)
  1330.  Registers Out : .A = error code .C = 1 if error.
  1331.                  .XY = ending address 
  1332.  Memory Changed: As per registers / data file.
  1333.  
  1334. Routine        : SAVE
  1335.  Kernal Address: $FFD8
  1336.  Description   : Save section of memory to a file.
  1337.  Registers In  : .A = Z-page ptr to start adress
  1338.                  .XY = end address
  1339.  Registers Out : .A = error code, .C = 1 if error.
  1340.                  .XY = used.
  1341.  Memory Changed: None.
  1342.  
  1343. Routine        : SETTIM
  1344.  Kernal Address: $FFDB
  1345.  Description   : Set internal clock (TI$).
  1346.  Registers In  : .AXY - Clock value in jiffies (1/60 secs).
  1347.  Registers Out : None.
  1348.  Memory Changed: Relevant system time locations set.
  1349.  
  1350. Routine        : RDTIM
  1351.  Kernal Address: $FFDE
  1352.  Description   : Reads internal clock (TI$)
  1353.  Registers In  : None.
  1354.  Registers Out : .AXY - Clock value in jiffies (1/60 secs).
  1355.  Memory Changed: None.
  1356.  
  1357. Routine        : STOP
  1358.  Kernal Address: FFE1
  1359.  Description   : Scans STOP key.
  1360.  Registers In  : None.
  1361.  Registers Out : .A = last keyboard row, .X = destroyed (if stop key)
  1362.  Memory Changed: None.
  1363.  Note          : The last keyboard row is as follows:
  1364.                  .A -> | 7   | 6   | 5   | 4   | 3   | 2   | 1  | 0
  1365.                   KEY: |STOP |Q    |C=   |SPACE|2    |CTRL |<-  |1
  1366.  
  1367. Routine       : GETIN
  1368.  Kernal Address: $FFE4
  1369.  Description   : Read buffered data from file.
  1370.                  Keyboard - Read from keyboard buffer, else return null ($00).
  1371.                  Rs-232   - Read from Rs-232 buffer, else null is returned.
  1372.                  Serial   - See BASIN
  1373.                  Cassette - See BASIN
  1374.                  Screen   - See BASIN
  1375.  Registers In  : None.
  1376.  Registers Out : .A = character, .C = 1 if error.
  1377.                  .XY = used.
  1378.  Memory Changed: None.
  1379.  
  1380. Routine       : CLALL
  1381.  Kernal Address: $FFE7
  1382.  Description   : Close all open files and channels.
  1383.  Registers In  : None.
  1384.  Registers Out : .AX used.
  1385.  Memory Changed: None.
  1386.  Note          : This routine does not _actually_ close the files, rather it
  1387.                  removes their prescense from the file tables held in memory.
  1388.                  It's recommended to use close to close files instead of using
  1389.                  this routine.
  1390.  
  1391.  
  1392. Routine        : UDTIME
  1393.  Kernal Address: $FFEA
  1394.  Description   : Update internal (TI$) clock by 1 jiffie (1/60 sec).
  1395.  Registers In  : None.
  1396.  Registers Out : .A,.X destroyed.
  1397.  Memory Changed: Relevant system time locations changed.
  1398.  
  1399. Routine        : SCRORG
  1400.  Kernal Address: $FFED
  1401.  Description   : Returns current window/screen size
  1402.  Registers In  : None.
  1403.  Registers Out : .X - Window Row Max
  1404.                  .Y - Window Col Max
  1405.                  .A - Screen Col Max (128 only, 64 unchanged)
  1406.  Memory Changed: None
  1407.  
  1408. Routine        : PLOT
  1409.  Kernal Address: $FFF0
  1410.  Description   : Read or set cursor position.
  1411.  Registers In  : .C = 1 (Read)        |      .C = 0 (Set)
  1412.                    None.              |        .X = Col
  1413.                                       |        .Y = Row
  1414.  Registers Out : .C = 1 (Read)        |      .C = 0 (Set) 
  1415.                    .X = Current Col   |         None.
  1416.                    .Y = Current Row   |
  1417.  Memory Changed:  None                |      Screen Editor Locations.
  1418.  
  1419. Routine        : IOBASE
  1420.  Kernal Address: $FFF3
  1421.  Description   : Returns base of I/O Block
  1422.  Registers In  : None.
  1423.  Registers Out : .XY = address of I/O block ($D000)
  1424.  Memory Changed: Screen Editor Locations.
  1425.  
  1426. ============================================================================
  1427. 64K VDC RAM and an alternate GEOS128 Background Screen
  1428. by Robert A. Knop Jr. (rknop@tybalt.caltech.edu, R.KNOP1 on GEnie)
  1429.  
  1430. I. Introduction
  1431.  
  1432. GEOS, both the 64 and 128 varieties, uses bitmapped screens for its output.
  1433. In 40 columns, this means 8K of system memory is set aside for the main
  1434. screen.  Then, in addition, GEOS also uses display buffering; in other words,
  1435. GEOS allocates a second 8K as a "background" (BG) screen that is used to keep
  1436. an intact copy of the foreground (FG) screen.  This can be very useful for a
  1437. number of reasons; one, it can be used as an undo buffer, as it is in
  1438. geoPaint.  When you have a delicate drawing, and then accidentally run the
  1439. eraser across it, the effects of the eraser are only written to the FG screen.
  1440. A click of the UNDO button brings the BG screen, with the pre-eraser version
  1441. of your painting, back to the fore.  Another use is for buffering the contents
  1442. of the screen when something like a dialog box or a menu is written over it.
  1443. When a dialog box is erased, and you see whatever had been underneatg it
  1444. magically reappear, the graphics underneath are being pulled from the BG
  1445. screen.
  1446.  
  1447. Applications have the option not to use the BG screen.  Change a couple of
  1448. vectors and flags, and you can use the 8K BG screen for application RAM.
  1449. (This is very convenient, since the BG screen is directly above the normal 22K
  1450. of application RAM in the GEOS memory map.)  Of course, the application then
  1451. has to provide some way of redrawing blocks of the screen hidden by menus and
  1452. dialog boxes.  geoWrite is an example of this; when you bring up, and exit
  1453. from, a dialog box in geoWrite, there is briefly a blank rectangle on the
  1454. screen before the text is redrawn on the screen.
  1455.  
  1456. Under GEOS128 in 80 columns, the bitmap screen is now twice as large: 640x200
  1457. instead of 320x200.  The FG screen, here 16K, occupies VDC memory.  The memory
  1458. used for both the 40 column FG and 40 column BG screen is used for the 80
  1459. column BG screen.
  1460.  
  1461. GEOS128 was written for, and runs on, 128's with only the usual 16K of VDC
  1462. RAM.  And, it uses basically all 16K of this RAM.  However, if you have 64K of
  1463. VDC RAM (as is the case with 128D's, and with flat 128's that have been
  1464. upgraded), you've got an additional 48K of VDC RAM that the GEOS system
  1465. doesn't touch.  So, why not use some of this RAM as a 80 column BG screen?
  1466. Then, if you are writing an 80-column only application, you get an extra 16K,
  1467. the 40-column BG screen at $6000 and the 40-column FG screen at $a000, in main
  1468. memory which your application can use however it sees fit.
  1469.  
  1470.  
  1471. II. Support Routines
  1472.  
  1473. Only a small number of routines actually need to be written to implement this
  1474. scheme; moreover, these routines are realatively straightforward.  After all,
  1475. we are simply copying memory from one part of VDC RAM to another.  The VDC's
  1476. block copy feature of the VDC is very helpful in this endeavor.  (See Craig
  1477. Taylor's article from last issue, or most any 128 programming guide.)  The
  1478. file vdc-bg.sfx, associated with this issue of the Hacking Mag, is a
  1479. self-extracting archive with a number of geoProgrammer source files (in
  1480. geoWrite 2.1 format) and a small dippy demonstration program.  The file VDC-BG
  1481. contains the following routines:
  1482.  
  1483. InitVDC       -- make sure your VDC knows it has 64K RAM
  1484. VDCImpLine    -- Imprint horizontal line from FG screen to BG screen
  1485. VDCRecLine    -- Recover horizontal line from BG screen to FG screen
  1486. VDCImpRect    -- Imprint rectangle from FG screen to BG screen
  1487. VDCRecRect    -- Recover rectangle from BG screen to FG screen
  1488.  
  1489. Each Imprint routine actually uses most of the same code as the corresponding
  1490. Recover routine; all that differs is the offset to the "source" and
  1491. "destination" screens in VDC RAM.  (The offset for the FG screen is $0000, and
  1492. for the BG screen is $4000.)  The routines take the same arguments as the
  1493. non-VDC Imprint and Recover routines as documented in the Hitchhiker's Guide.
  1494. (You will note, however, that for whatever reason the standard GEOS
  1495. ImprintLine and RecoverLine routines were only implemented for Apple GEOS.)
  1496. Briefly, these are:
  1497.  
  1498. Routine:     InitVDC
  1499.  
  1500. Pass:        Nothing
  1501.  
  1502. Return:      Nothing
  1503.  
  1504. Destroys:    a,x
  1505.  
  1506. Note:        This routine should be called at the very beginning of your
  1507.              program before you do any writing to the FG screen or the VDC.
  1508.  
  1509. ------------------------------------------------------------------------------
  1510.  
  1511.  
  1512. Routine:     VDCImpLine
  1513.              VDCRecLine
  1514.  
  1515. Pass:        r3   -- left edge of line to imprint/recover (word)
  1516.              r4   -- right edge of line to imprint/recover (word)
  1517.              r11L -- y coordinate of line to imprint/recover (byte)
  1518.  
  1519. Return:      r3, r4 -- processed through NormalizeX
  1520.  
  1521. Destroys:    a,x,y,r5-r8,r11
  1522.  
  1523. -------------------------------------------------------------------------------
  1524.  
  1525. Routine:     VDCImpRect
  1526.              VDCRecRect
  1527.  
  1528. Pass:        r3   -- x-coordinate of upper-left corner (word)
  1529.              r2L  -- y-coordinate of upper-left corner (byte)
  1530.              r4   -- x-coordinate of lower-right corner (word)
  1531.              r2H  -- y-coordinate of lower-right corner (byte)
  1532.  
  1533. Return:      r3,r4 -- processed through NormalizeX
  1534.  
  1535. Destroys:    a,x,y,r5-r8,r10L,r11
  1536.  
  1537. ------------------------------------------------------------------------------
  1538.  
  1539.  
  1540. To discuss the imprint and recover line routines, consider the ASCII diagram
  1541. of a portion of a line on the VDC screen.  A x indicates a pixel that is in
  1542. the line to be copied.  The I's indicate byte boundaries; the pixel below each
  1543. I is the msb of the corresponding byte in the VDC bitmap.  (Bytes increase
  1544. horizontally across the screen; there is no card structure found in the 80
  1545. column bitmap screen.)
  1546.  
  1547.            I       I       I       I
  1548.            ....xxxxxxxxxxxxxxxxxxxxxxxxx...
  1549.                 ^  \______________/  ^
  1550.              left          I         right
  1551.           residual     full bytes    residual
  1552.  
  1553. The line moving routine needs to figure the location in VDC RAM of the
  1554. leftmost full byte, the number of full bytes, and the location of the two
  1555. residual bytes; additionally, it builds a bit mask for the residual bytes,
  1556. with bits set corresponding to pixels to be copied.  This mask is used to
  1557. create the proper combination of data from the source and destination screens
  1558. in the two residual bytes.
  1559.  
  1560. Once it knows all this, all the line routines do is (1) submit a VDC block
  1561. copy to copy the full bytes, (2) read the left residual byte from the source,
  1562. mask out the appropriate pixels, and OR it with the appropriate pixels from
  1563. the destination, and write that one byte (3) repeat (2) for the right residual
  1564. byte.
  1565.  
  1566. The rectangle routines simply call the line copy routines repeatedly,
  1567. (r2H)-(r2L)+1 times.  (Note that while this is the most efficient way to do it
  1568. from a coding time point of view <grin>, really the rectangle routines only
  1569. need calculate the residual bit masks and the locations once.  Thereafter,
  1570. locations can be updated by adding 80 (the length of a VDC line) for each new
  1571. line.  The changes to the code to implement this are not difficult, and it
  1572. isn't clear why I didn't make them....)
  1573.  
  1574.  
  1575. III. Use of the Routines
  1576.  
  1577. In a word, you use these routines whenever you would have used the normal GEOS
  1578. imprint/recover routines.  There are a few other consierations, though.
  1579.  
  1580. First of all, you need to set the flag dispBufferOn to ST_WR_FORE.  The GEOS
  1581. system graphic routines think that the BG screen is in main memory, and thus
  1582. will not correctly use your new VDC BG screen.  This means, unfortunately,
  1583. that you can't just blithely go drawing graphics, assuming that they'll be
  1584. buffered for recall when needed.  However, it is not too much trouble to make
  1585. a call to VDCImpRect either right after you've made some graphic change, or
  1586. right before something potentially hazardous will happen (e.g. a call to
  1587. DoDlgBox).  For instance, you might have all of your main menus be Dynamic
  1588. Submenus which call VDCImpRect before opening the submenu.
  1589.  
  1590. Second, you should load recoverVector with VDCRecRect.  Since VDCRecRect takes
  1591. the same parameters as RecoverRectangle, it can substitute directly for it.
  1592. Once you set this vector, all menus and dialog boxes erased from the screen
  1593. automatically restore the destroyed region from your VDC BG screen.
  1594.  
  1595. Both of these are demonstrated in the test program included in vdc-bg.sfx.
  1596.  
  1597.  
  1598. IV. Another 32K
  1599.  
  1600. The alert reader will have noticed that the VDC BG screen only takes as much
  1601. memory as the VDC FG screen, i.e. 16K.  Thus, even with this scheme, there is
  1602. still another 32K of free memory in VDC RAM.  Quadruple buffering, anyone?
  1603.  
  1604. A more tantalizing prospect would be to implement a 640x400 interlaced screen
  1605. for GEOS128.  This presents a number of problems, however.  First, there is
  1606. that terrible flicker.  But, this can be made reasonable through the use of
  1607. polarizing filters (in layman's terms, "sunglasses") and appropriate color
  1608. choices.  More seriously, the GEOS kernal graphic routines all take byte
  1609. argum`>:s for Y coordinates.  So, all 400 vertical pixels cannot be addressed
  1610. with those routines.  Thus, sombody implementing a GEOS interlaced screen is
  1611. faced with re-writing all of the graphics routines.  (Something to do with the
  1612. 8K you've freed up at $a000, I suppose.)  Since each 640x400 graphic screen
  1613. would require 32K of memory for the bitmap, you could still have a VDC
  1614. Background screen.
  1615.  
  1616. [ Note: The code discussed within this article is available via anonymous 
  1617. FTP at tybalt.caltech.edu under the directory pub/rknop/hacking.mag as 
  1618. vdc-bg.sfx. This will dissolve into the GEOWRITE source files.]
  1619.  
  1620. ============================================================================
  1621.  
  1622. GeoPaint File Format
  1623. --------------------
  1624. by Bruce Vrieling (bvrieling@undergrad.math.waterloo.edu)
  1625.  
  1626. GeoPaint is an excellent graphics program written for the GEOS environment. Its
  1627. disk access is relatively quick, compared it to what a comparable program would
  1628. do on a non-GEOS equipped C64. Part of this accomplishment can be attributed to
  1629. the diskTurbo that is an integral part of GEOS. However, the special GeoPaint
  1630. file-saving scheme deserves some of the credit.
  1631.  
  1632.  
  1633. VLIR
  1634. ----
  1635.  
  1636. GeoPaint files are always stored in Variable Length Indexed Recording files. 
  1637. VLIR files offer advantages not available without GEOS. Generally speaking, VLIR
  1638. is the ultimate in RELATIVE files.
  1639.  
  1640. The format of a VLIR file is not that difficult to figure out. While in a 
  1641. regular C64 file, the two bytes directly following the FILETYPE byte in the 
  1642. directory would point to the data file following, VLIR files use these two bytes
  1643. to point to a VLIR HEADER BLOCK (don't confuse the VLIR HEADER block with the
  1644. INFO block). The first two bytes of this block are $00/FF, as the header block 
  1645. is a MAXIMUM of one block long. (This is why when you VALIDATE a GEOS disk from
  1646. C64 mode, GeoPaint pictures are lost. Only the header block is recognised as 
  1647. being part of the file. The rest of the picture gets deallocated in the BAM). 
  1648. The remaining 254 bytes in the block are divided into 127 2-byte pointers to 
  1649. tracks/sectors on the disk. These pointers point to the individual records of 
  1650. the VLIR file, which may be ANY number of blocks long. The VLIR track/sector 
  1651. pointers in the VLIR header block only point to the FIRST block of the chain. 
  1652. From then on, the sectors chain themselves together using the normal format ie.
  1653. the first two bytes of each block point to the following block.
  1654.  
  1655. A sample GeoPaint VLIR header might look like this:
  1656.  
  1657. 0000:00 FF 03 11 03 05 03 01 ........
  1658. 0008:04 03 00 FF 00 FF 00 FF ........
  1659. 0010:04 07 00 00 00 00 00 00 ........
  1660.  etc....
  1661.  
  1662. The first two bytes, $00/FF, tell the drive that this is the last (and only) 
  1663. block in this VLIR HEADER SECTION (will never be more than 1 block, as was 
  1664. mentioned earlier). The next pair of bytes, $03/11, points to the first VLIR 
  1665. record. The next two, $03/05, point to the second record.
  1666.  
  1667. You will notice that 5th record contains the values $00/FF. This means that for
  1668. this record, there is no picture data. We will get into exactly what the data 
  1669. held in the records mean in a minute. The $00/FF entries indicate an empty 
  1670. record. Finally, the 9th entry, $00/00 indicates the end of the GeoPaint file.
  1671. There is no more data beyond this point.
  1672.  
  1673. One note should be made. GeoPaint is not always consistent in its handling of 
  1674. the data in a header block. Sometimes, it will show quite a few $00/FF 
  1675. combinations before finally terminating with a $00/00. When reading the file, 
  1676. I always read the entire header, as I don't trust the end of file method 
  1677. mentioned above. Just remember that any track/sector link that does not contain
  1678. $00/FF or $00/00 is a valid record, with picture data.
  1679.  
  1680.  
  1681. Layout on Screen
  1682. ----------------
  1683.  
  1684. GEOS orients the data in a GeoPaint file slightly differently than in a 
  1685. PhotoScrap or an Icon. A photoscrap stores the bytes corrosponding to a screen
  1686. which looks like this:
  1687.  
  1688. 001 002 003 004 005 ....0012
  1689. 013 014 015 016 017 ....0024
  1690.  
  1691. Consecutive bytes are placed BESIDE each other. However, if you are at all
  1692. familiar with the layout of a C64 hi-res screen, you will know this is very 
  1693. different from the layout that the VIC chip sees data. GeoPaint uses a format 
  1694. identical to the VIC chip layout on screen.
  1695.  
  1696. GeoPaint pictures are stored in the following format:
  1697.  
  1698. 001 009 017 025 033 .....  313
  1699. 002 010 018 026 034 .....  314
  1700. 003 011 019 027 035 .....  315
  1701. 004 012 020 028 036 .....  316
  1702. 005 013 021 029 037 .....  317
  1703. 006 014 022 030 038 .....  318
  1704. 007 015 023 031 039 .....  319
  1705. 008 016 024 032 040 .....  320
  1706.  
  1707. 321 329 .....
  1708. 322 330 .....
  1709. 323 331 .....
  1710. 324 332 .....
  1711. 325 333 .....
  1712. 326 334 .....
  1713. 327 335 .....
  1714. 328 336 .....
  1715.  
  1716. As you can see, this is very different from the PhotoScrap format. Consecutive
  1717. bytes are NOT stored on the screen beside each other. Rather, they are stored
  1718. underneath each other into groups of 8 bytes. This makes moving the data from 
  1719. the disk onto the screen that much faster, as the decompacted bytes can just be
  1720. stored on the screen after each other. Of course, this makes porting GEOS pics
  1721. to the 128's VDC that much more difficult, as the VDC conforms to the 
  1722. PhotoScrap format.
  1723.  
  1724.  
  1725. Compression Method
  1726. ------------------
  1727.  
  1728. GEOS uses an excellent compression method to store files on disk. You may have
  1729. noticed that nearly empty pictures on disk consume very little disk space. This
  1730. can be credited to GeoPaint's smart compression techniques.
  1731.  
  1732. Basically, the format of the compression has one COMMAND byte followed by one 
  1733. or more DATA bytes. The COMMAND byte tells GEOS what to do with following DATA 
  1734. bytes. There are 4 commands for compression:
  1735.  
  1736. 1) If the COMMAND byte is less than 64, this indicates that there are 'COMMAND'
  1737.    many DATA bytes following that are to be taken as individual bytes. This is
  1738.    the least effective method of compression, as no compression takes place.
  1739.  
  1740. 2) If the COMMAND byte ranges from 65 to 127, then this is a special type of 
  1741.    compression. First of all, the next 8 bytes in the file are read in as DATA.
  1742.    This DATA is used to make an 8*8 'stamp'. Secondly, the amount of times to 
  1743.    'stamp' this 8*8 square is calculated (COMMAND AND 63). Then, the stamping 
  1744.    is done. 'Stamping' sounds more difficult that it really is. What it boils
  1745.    down to, is repeating the 8 byte DATA stamp 'COMMAND AND 63'
  1746.    times.
  1747.  
  1748. 3) If the COMMAND byte is 129 or greater, then the following DATA byte is
  1749.    repeated 'COMMAND AND 127' times. This is different from #1, as only 1 DATA
  1750.    byte is called in, and simply repeated. #1 called in 'COMMAND' many DATA 
  1751.    bytes.
  1752.  
  1753. 4) If the COMMAND byte is ZERO, we have reached the end of the VLIR record for
  1754.    the GeoPaint picture.
  1755.  
  1756. It should be noted that the COMMAND byte will NEVER be 64 or 128. If it is, 
  1757. there has been an error.
  1758.  
  1759.  
  1760. Format of Data After Decompacting
  1761. ---------------------------------
  1762.  
  1763. After the data has been decompacted, it remains to be placed on the screen. Each
  1764. VLIR record holds 16 scanlines of data, or 2 character lines (different ways of
  1765. looking at the same thing).
  1766.  
  1767. The format of the data is as follows:
  1768.  
  1769.      First, there is 640 bytes of picture data, comprising the first character
  1770.      line (8 scanlines). Remember, GeoPaint pictures are 640 pixels across. 640
  1771.      pixels works out to 80 bytes. A character line is 8 pixels deep, so 80*8 
  1772.      comes to 640 bytes.
  1773.  
  1774.      These bytes are followed by the 640 bytes for the second chacacter line 
  1775.      (next 8 scanlines). This is followed by 8 garbage bytes that accidentaly 
  1776.      worked themselves into the original GeoPaint design. They should be set to
  1777.      zero.
  1778.  
  1779.      Finally, two sets of 80 bytes of colour data follow. The first set 
  1780.      comprises the colour for the first line, the second 80 bytes for the second
  1781.      line. To wrap things up, the VLIR record is terminated by a zero byte.
  1782.  
  1783.      The next VLIR record will hold the data for the NEXT 16 scanlines, and so
  1784.      on.
  1785.  
  1786.  
  1787. Conclusion
  1788. ----------
  1789.  
  1790. That about wraps up this discussion on GeoPaint format for files. We've 
  1791. discussed the format of VLIR files on disk, layout of picture data on screen, 
  1792. compression methods used in GeoPaint files, and the format of the data once 
  1793. decompacted. I hope this information will come in handy for someone.
  1794.  
  1795. ==============================================================================
  1796. Rasters - What They Are and How to Use Them
  1797. by Bruce Vrieling - (bvrieling@undergrad.math.waterloo.edu)
  1798.  
  1799. Anyone who has fiddled around with interrupts on the Commodore 64 has 
  1800. undoubtedly heard at one time or another of the concept of rasters being 
  1801. mentioned. Rasters are the 'ultimate' achievement of interrupt programming, or
  1802. so they say. What is a raster? And how does one go about writing a program to 
  1803. use them?
  1804.  
  1805. Overview of what Interrupts are all about
  1806. -----------------------------------------
  1807.  
  1808. A raster is sort form for the concept of a 'raster interrupt'. Before
  1809. going into rasters, perhaps a brief review of interrupts is in order.
  1810.  
  1811. Interrupts are events generated by the CIA timer in the C64 to perform certain 
  1812. tasks. 60 times a second, the CIA chip signals an interrupt is due to be 
  1813. processed (ie. the interrupt timer timed out). This causes the 6510 CPU to stop
  1814. executing the current program, save the registers on the stack, and begin to 
  1815. execute the interrupt code. Some of the things which get done during an 
  1816. interrupt include the keyboard scan, and updating TI (the software clock). When
  1817. the interrupt code is finished, an RTI instruction is executed, which brings 
  1818. the interrupt's execution to a halt. The registers are retrieved from the stack,
  1819. and the current program in memory continues to execute once again. It will 
  1820. continue to do so until the next interrupt occurs, about 1/60 of a second later.
  1821.  
  1822. The above is what happens in a normal C64 (the C128 follows the same idea, but 
  1823. more events occur during a C128 interrupt). [Ed. Note: In addition, the C=128
  1824. generates its interrupts via a screen raster instead of the CIA chip.]
  1825.  
  1826. However, you can change the normal course of events, and cause some code of your
  1827. design to be added to the normal list of events which occur every interrupt. 
  1828. Some of the simple favourites include flashing the border 60 times per second.
  1829. (Note that we have not begun the topic of rasters yet; this has nothing to do
  1830. with rasters. That discussion begins at the next heading.)
  1831.  
  1832. How do you change the interrupt's normal course of action? It's rather simple.
  1833. The C64 contains an interrupt VECTOR at locations 788/9 which is 'jumped 
  1834. through' before the Kernal Rom gets a chance to execute its code. If you change
  1835. this vector to point to YOUR code, and make the end of your code point to the 
  1836. normal Kernal location (where the interrupt normally would have jumped to, 
  1837. $EA31), and you are careful not to step on anything, your code will be executed
  1838. 60 times per second.
  1839.  
  1840. An example is in order:
  1841.  
  1842. ; flasher
  1843. ;
  1844. ; this program causes the border to flash 60 times per second
  1845. ;
  1846. setup = *
  1847.  
  1848. sei                           ; disable interrupts
  1849. lda #<intcode                 ; get low byte of target routine
  1850. sta 788                       ; put into interrupt vector
  1851. lda #>intcode                 ; do the same with the high byte
  1852. sta 789
  1853. cli                           ; re-enable interrupts
  1854. rts                           ; return to caller
  1855.  
  1856. intcode = *
  1857.  
  1858. inc $d020                     ; change border colour
  1859. jmp $ea31                     ; exit back to rom
  1860.  
  1861.  
  1862. The above is an example of a very simple interrupt routine. If you were to 
  1863. assemble it with an assembler, and SYS to the SETUP routine, you would see your
  1864. border flash 60 times per second.
  1865.  
  1866. You will notice the SEI and CLI machine language instructions used above. They
  1867. are very important. We don't want an interrupt occurring in between the STA 788
  1868. and the STA 789 instructions.
  1869.  
  1870. Think what would happen if one did: 788 would have been modified, but 789 would
  1871. still be pointing to the high byte of the Kernal address. Result: the interrupt
  1872. would have jumped to heaven knows where. You can be virtually guaranteed that 
  1873. it would NOT be pointing to a valid piece of interrupt code. Your machine would
  1874. crash. The SEI instruction turns interrupts OFF, so that there is no danger of 
  1875. an interrupt occurring during execution of the following routine. The CLI turns
  1876. them back on. If you forget to turn them back on, and accidentally leave them 
  1877. off, your keyboard will freeze when you return to basic, and your machine will
  1878. seem to lock up.
  1879.  
  1880. The above was a very simple example. There are many useful things which can also
  1881. be done on an interrupt. I have seen code which played music in the background
  1882. of a running Basic program (it played the popular .MUS files). GEOS uses 
  1883. interrupts extensively to control the pointing of the mouse, and to trigger 
  1884. events. Interrupts are powerful beasts, and the following concept concerning 
  1885. raster interrupts specifically is a particularly useful animal for some people.
  1886.  
  1887.  
  1888. The Raster
  1889. ----------
  1890.  
  1891. A raster is a loosely used term. It refers to an interrupt that is triggered 
  1892. when the ray gun on the back of your monitor draws a certain line on the video
  1893. screen. There are many different sources which can cause an interrupt. You are 
  1894. not limited to what the CIA chip can do. Rasters depend on interrupts 
  1895. specifically generated by the VIDEO chip. You could make this interrupt change
  1896. the border colour of the screen below a certain screen line. When the screen 
  1897. line you specified gets redrawn, the interrupt goes off. Your code then quickly
  1898. changes some memory locations to create a different video mode or effect. You 
  1899. could cause the bottom half of the screen to gets it's character definitions 
  1900. from another, different character set. Or, you could make the top 3/4 of your 
  1901. screen exist in hi-res multi-colour graphics, and keep the bottom 1/4 of the 
  1902. screen in text mode.
  1903.  
  1904. Some facts about the video screen: it gets redrawn exactly 60 times per second.
  1905. It contains 200 scan lines on the normal 25*40 display, numbered 50 to 250 or 
  1906. thereabouts (note that there are more visible scan lines though: the top and 
  1907. bottom borders, for example). The actual re-drawing of the screen is 
  1908. synchronized to the electrical power coming into your house, 60 Hz. That's why
  1909. some programs behave differently when run on European machines. The power is 
  1910. delivered at 50 Hz over there.
  1911.  
  1912. Why do we have to worry about a video interrupt? If the screen gets redrawn 60
  1913. times per second, and regular interrupts also occur at 60 times per second, why
  1914. not simply put some code into the regular interrupt to do what we want with the
  1915. screen? Because the two types of interrupts are not in sync. Neither one of them
  1916. occurs EXACTLY 60 times per second, and the differences are enough to make it 
  1917. next to impossible to get coordinated activity of any kind happening on the 
  1918. screen. When we use the video interrupt, we KNOW we are at a certain line on the
  1919. screen, as being on that line is what caused the interrupt to happen in the
  1920. first place.
  1921.  
  1922. So, let's summarize. We know that regular interrupts occur 60 times per second.
  1923. We also know that the video screen gets re-drawn 60 times per second, and that
  1924. we can cause an interrupt to be generated when a certain line gets drawn on the
  1925. screen. One slight drawback to all of this is that BOTH types of interrupts
  1926. (regular and raster driven) travel through the SAME vector (ie. about 120 
  1927. interrupts per second, 60 of one, and 60 of the other). Your code will have to
  1928. check and see what the source of the interrupt was, and act accordingly. Or will
  1929. it?
  1930.  
  1931. The system needs an interrupt to occur 60 times per second to do housekeeping,
  1932. and uses the CIA clock to generate the interrupts. We want to interrupt every 
  1933. time a certain scan line is reached on the monitor, which will also just happen
  1934. to occur at 60 times per second. We also have to make sure that they don't 
  1935. interfere with each other. The regular interrupts should be sent to their Rom
  1936. destination, while our video interrupts should go to our code, and no where 
  1937. else.
  1938.  
  1939. If both are occurring at 60 times per second, why not do the job of the system
  1940. Rom, and our video code on the SAME interrupt? We know that the CIA chip is not
  1941. good for this; it is out of sync with the video image. Why not turn OFF the CIA
  1942. interrupt, enable the raster/video interrupt, and do both jobs on one interrupt?
  1943. Then we would have an interrupt signal that occurs 60 times per second, and is
  1944. in perfect sync with the video image.
  1945.  
  1946. That's exactly what we're going to do.
  1947.  
  1948. Astute reads will notice a slight flaw in the above logic. For simplification 
  1949. purposes, I didn't get into the fact that you will need TWO raster interrupts 
  1950. PER SCREEN to accomplish anything useful. Why two? Because any change to the 
  1951. video mode you put into effect 3/4 of the way down the screen will have to be 
  1952. undone at the TOP of the next screen update. If you decide to make the top 3/4 
  1953. of the screen a hi-res image, and the bottom 1/4 text, you need one interrupt 
  1954. 3/4 of the way down the screen to change from hi-res to text, but you need a 
  1955. SECOND one at the top of the screen to change back to hi-res from text.
  1956.  
  1957. So, we will now have 120 interrupts going off every second to accomplish our 
  1958. video desires, with 60 of them working a double shift, making sure the system 
  1959. interrupt code gets executed also. Remember that we are working with a specific
  1960. example. There is no reason why you couldn't split the screen into N different
  1961. video modes, and have (N+1)*60 interrupts going off per second. As long as you 
  1962. keep your code short (so your interrupts don't take too long, and have another 
  1963. interrupt occur before the current one is done - messy), it will work 
  1964. beautifully.
  1965.  
  1966. So far, this is all talk. Let's write a few short code segments to accomplish 
  1967. some of the feats we've just discussed.
  1968.  
  1969. The first we'll do is a re-hash of the one presented above. It flashes the 
  1970. border again. It does not do any mid-screen changes of video modes or anything 
  1971. fancy like that, so only 1 interrupt per screen is required (ie. 60 per second,
  1972. not 120 etc.). This program simply shows the same idea, but this time using 
  1973. video interrupts as the source rather than the CIA. You probably won't
  1974. notice a difference during execution.
  1975.  
  1976. ----------------------------------------------------------------------------
  1977. ; flasher - part II
  1978. ;
  1979. ; this program causes the border to flash 60 times per second
  1980. ; the source of the interrupts is the video chip
  1981. ;
  1982. setup = *
  1983.  
  1984. sei                           ; disable interrupts
  1985.  
  1986. lda #$7f                      ; turn off the cia interrupts
  1987. sta $dc0d
  1988.  
  1989. lda $d01a                     ; enable raster irq
  1990. ora #$01
  1991. sta $d01a
  1992.  
  1993. lda $d011                     ; clear high bit of raster line
  1994. and #$7f
  1995. sta $d011
  1996.  
  1997. lda #100                      ; line number to go off at
  1998. sta $d012                     ; low byte of raster line
  1999.  
  2000. lda #>intcode                 ; get low byte of target routine
  2001. sta 788                       ; put into interrupt vector
  2002. lda #<intcode                 ; do the same with the high byte
  2003. sta 789
  2004. cli                           ; re-enable interrupts
  2005. rts                           ; return to caller
  2006.  
  2007.  
  2008. intcode = *
  2009.  
  2010. inc $d020                     ; change border colour
  2011.  
  2012. lda $d019                     ; clear source of interrupts
  2013. sta $d019
  2014.  
  2015. lda #100                      ; reset line number to go off at
  2016. sta $d012
  2017.  
  2018. jmp $ea31                     ; exit back to rom
  2019. --------------------------------------------------------------------------
  2020.  
  2021. As you can tell, there's a wee bit more to this code than there was in the 
  2022. original. Execute it, and you'll notice that it looks pretty much the same as 
  2023. the results from the first program. But there's a difference: the interrupts 
  2024. are now being generated from the video chip, not the CIA. For this program, it 
  2025. didn't make much difference. However, for a more complicated program, it makes
  2026. a world of difference.
  2027.  
  2028. I'd better explain some of the code used above:
  2029.  
  2030.      lda #$7f
  2031.      sta $dc0d
  2032.  
  2033.      - This piece disables any interrupts caused by the CIA chip.
  2034.  
  2035.      lda $d01a
  2036.      ora #$01
  2037.      sta $d01a
  2038.  
  2039.      - Location $d01a controls which sources may cause an interrupt
  2040.        (other than the normal CIA). There are 4 different possible
  2041.        sources: rasters, sprite to sprite collision, sprite to
  2042.        background collision, and the light pen. Bit #0 is the raster
  2043.        bit, and this piece of code activates it.
  2044.  
  2045.      lda $d011
  2046.      and #$7f
  2047.      sta $d011
  2048.  
  2049.      - This code clears bit #7 of location $d011. This location is used
  2050.        for many different things. Bit #7 represents the highest bit of
  2051.        the raster line (see segment below for more on the raster line
  2052.        #). More than 256 raster line numbers are possible (some are off
  2053.        screen, and some represent the upper and lower border areas).
  2054.        This bit is the 9th bit. I set it to zero because all my code
  2055.        affects rasters only on the normal 25*40 line display, well
  2056.        within the 0-255 range. This decision was an arbitrary choice on
  2057.        my part, to make the code simpler.
  2058.  
  2059.      lda #100
  2060.      sta $d012
  2061.  
  2062.      - Location $d012 is the lower 8 bits of the raster line on which
  2063.        the interrupt is to be generated. The number 100 was another
  2064.        arbitrary choice. For changing border colours, the actual line
  2065.        number was not important. Later on, in the next example, it will
  2066.        become important.
  2067.  
  2068.      lda #>intcode
  2069.      ...
  2070.      rts
  2071.  
  2072.      - Re-vectors the interrupt code to the new code.
  2073.  
  2074.      inc $d020
  2075.  
  2076.      - Changes the border colour.
  2077.  
  2078.      lda $d019
  2079.      sta $d019
  2080.  
  2081.      - These lines clear the bit in the interrupt register which tells the
  2082.        source of the interrupt (in preperation for the next).
  2083.  
  2084.      lda #100
  2085.      sta $d012
  2086.  
  2087.      - This line resets the raster line to go off at line number 100
  2088.        again (same as above). It should be reset, so the next interrupt
  2089.        will know what line to occur on.
  2090.  
  2091.      jmp $ea31
  2092.  
  2093.      - Exit back to the Kernal Rom.
  2094.  
  2095.  
  2096. A Useful Example
  2097. ----------------
  2098.  
  2099. The following is an example of a more sophisticated piece of raster code. It 
  2100. makes the top half of the screen border white, and the bottom half black.
  2101.  
  2102. ---------------------------------------------------------------------------
  2103. setup = *
  2104.  
  2105. ; some equates
  2106.  
  2107. COLOUR1 = 0
  2108. COLOUR2 = 1
  2109. LINE1 = 20
  2110. LINE2 = 150
  2111.  
  2112. ; code starts
  2113.  
  2114. setup = *
  2115.  
  2116. sei                           ; disable interrupts
  2117.  
  2118. lda #$7f                      ; turn off the cia interrupts
  2119. sta $dc0d
  2120.  
  2121. lda $d01a                     ; enable raster irq
  2122. ora #$01
  2123. sta $d01a
  2124.  
  2125. lda $d011                     ; clear high bit of raster line
  2126. and #$7f
  2127. sta $d011
  2128.  
  2129. lda #LINE1                    ; line number to go off at
  2130. sta $d012                     ; low byte of raster line
  2131.  
  2132. lda #>intcode                 ; get low byte of target routine
  2133. sta 788                       ; put into interrupt vector
  2134. lda #<intcode                 ; do the same with the high byte
  2135. sta 789
  2136.  
  2137. cli                           ; re-enable interrupts
  2138. rts                           ; return to caller
  2139.  
  2140. intcode = *
  2141.  
  2142. lda modeflag                  ; determine whether to do top or
  2143.                               ; bottom of screen
  2144. beq mode1
  2145. jmp mode2
  2146.  
  2147. mode1 = *
  2148.  
  2149. lda #$01                      ; invert modeflag
  2150. sta modeflag
  2151.  
  2152. lda #COLOUR1                  ; set our colour
  2153. sta $d020
  2154.  
  2155. lda #LINE1                    ; setup line for NEXT interrupt
  2156. sta $d012                     ; (which will activate MODE2)
  2157.  
  2158. lda $d019
  2159. sta $d019
  2160.  
  2161. jmp $ea31                     ; MODE1 exits to Rom
  2162.  
  2163. mode2 = *
  2164.  
  2165. lda #$00                      ; invert modeflag
  2166. sta modeflag
  2167.  
  2168. lda #COLOUR2                  ; set our colour
  2169. sta $d020
  2170.  
  2171. lda #LINE2                    ; setup line for NEXT interrupt
  2172. sta $d012                     ; (which will activate MODE1)
  2173.  
  2174. lda $d019
  2175. sta $d019
  2176.  
  2177. pla                           ; we exit interrupt entirely.
  2178. tay                           ; since happening 120 times per
  2179. pla                           ; second, only 60 need to go to
  2180. tax                           ; hardware Rom. The other 60 simply
  2181. pla                           ; end
  2182. rti
  2183.  
  2184. modeflag .byte 0
  2185.  
  2186. ----------------------------------------------------------------------------
  2187.  
  2188. The above code, when executed, will result in the top half of your border being
  2189. white, and the bottom black. You may wish to fiddle with the equates (COLOUR1,
  2190. COLOUR2, LINE1, and LINE2) to get different effects.
  2191.  
  2192. I see some confused faces concerning why the above exit the interrupts the way 
  2193. they do. Remember, since we want a split screen effect, we have to have one 
  2194. interrupt occur at the TOP of the screen, to turn on the WHITE effect, and one 
  2195. midway down to turn on the BLACK effect. Two interrupts times 60 means 120
  2196. interrupts will be executed per second. The Rom only needs 60 per second to 
  2197. service the keyboard and its other stuff. So, we send 60 to the Rom (the 
  2198. interrupts which go through MODE1) by JMPing to $EA31, and the other 60 we 
  2199. trash. The PLA... RTI business is the proper way to bring an interrupt to an end
  2200. without going through the Rom. The RTI will ReTurn from Interrupt, and cause the
  2201. regular program to continue to execute.
  2202.  
  2203. That brings to an end this discussion on rasters. I hope the above examples 
  2204. have proved to be a valuable learning tool for you. With luck, they will 
  2205. motivate you to continue to experiment with rasters, and come up with some neat
  2206. effects.
  2207.  
  2208. If you have any questions, be sure to ask me about them.
  2209.  
  2210. ==============================================================================
  2211. BURSTING YOUR 128: THE FASTLOAD BURST COMMAND
  2212. by Craig Bruce <f2rx@jupiter.sun.csd.unb.ca>
  2213.  
  2214. 1. INTRODUCTION
  2215.  
  2216. This article discusses the well-unknown Fastload command of the 1571 and 1581
  2217. disk drive Burst Command Instruction Set.  If you look in the back of your '71
  2218. (or '81 I presume) disk drive manual, you will find that the information given
  2219. about the Fastload utility is not exactly abundant.
  2220.  
  2221. The Fastload command was intended to load program files into memory for
  2222. execution, but it can be used just as well for reading through sequential
  2223. files that would be much too large to load into a single bank of internal
  2224. memory.
  2225.  
  2226. To make use of the Fastload burst command, I implement a word counting utility
  2227. that will count the number of lines, words, and characters in a text file on a
  2228. 1571 or 1581 disk drive.  The advantage of using the Fastload command over
  2229. regular sequential file accessing through the kernel and DOS is that the
  2230. Fastload operates about 3.5 times faster on both drives.
  2231.  
  2232. 2. WORD COUNTING UTILITY
  2233.  
  2234. To use the word counting program, LOAD and RUN it like a regular BASIC
  2235. program.  It will ask you for the name of a file.  Enter the name if it is on
  2236. device number 8, or put a one character prefix and a ":" if it is on another
  2237. device.  A "b" means device 9, "c" device 10, etc.  The following are examples
  2238. of valid names:
  2239.  
  2240. . filename          "filename" on device 8
  2241. . b:filename        "filename" on device 9
  2242. . a:filename        "filename" on device 8
  2243.  
  2244. The file must be on either a 1571 or 1581 disk drive; the program will not
  2245. work with non-burst devices.  The program will work with either PRG or SEQ
  2246. files, since the Fastload command can be told not to worry about the file
  2247. type.
  2248.  
  2249. I use the same definition of a word as the Unix "wc" command uses: a sequence
  2250. of characters delimited by whitespace, where whitespace is defined to be
  2251. SPACE, TAB, and NEWLINE (Carriage Return) characters.  To get the line count,
  2252. I simply count the number of NEWLINEs.  If the last line of the file does not
  2253. end with a NEWLINE character, then the count will be one line short.  This is
  2254. the same as the Unix wc command too.  A proper text file should have its last
  2255. line end with a NEWLINE character.
  2256.  
  2257. On my JiffyDOS-ified 1571 and 1581, I am able to achieve a word counting speed
  2258. of 5,400 chars/sec and 6,670 chars/sec, respectively.  I am not sure how much
  2259. of a difference JiffyDOS makes, but I am not willing to rip out the ROMs to
  2260. check.  I tested using a 318K file.
  2261.  
  2262. 3. BURST READ LIBRARY
  2263.  
  2264. This section presents the burst reading library that you can incorporate into
  2265. your own programs and describes how the burst commands work.  The library has
  2266. three calls:
  2267.  
  2268. . burstOpen  ( .A=Device, .X=NameLen, burstBuf=Filename ) : <first block>
  2269. . burstRead  () : burstBuf, burstStatus, burstBufCount
  2270. . burstClose ()
  2271.  
  2272. I define three common storage variables for using this package: "burstBuf",
  2273. "burstStatus", and "burstBufCount".  "burstBuf" is a 256 byte area where the
  2274. data read in from the disk drive is stored before processing, and is located
  2275. at $0B00.  "burstStatus" is a zero-page location that keeps the status
  2276. returned from the burst command system.  This is needed by the user to detect
  2277. when the end of file has been encountered.  "burstBufCount" gives the number
  2278. of data bytes available in "burstBuf" after an open or read operation.  Its
  2279. value will be somewhere between 1 and 254.  A full sector contains 254 bytes
  2280. of data and two bytes of control information.
  2281.  
  2282. "burstStatus" and "burstBufCount" are defined to be at locations $FE and $FF,
  2283. respectively.  You are allowed to alter the values of the two variables and
  2284. the data buffer between calls, if you wish.  For reasons not completely
  2285. understood, interrupts must be disabled for the entire course of burst reading
  2286. a file.  I suspect this is because the IRQ service routine reads the interrupt
  2287. mask register of CIA#1, thus clearing the SerialDataReady flag that the burst
  2288. read routine waits for.  Anyway, the open routine does a SEI and the close
  2289. routine does a CLI, so you don't have to do this yourself.
  2290.  
  2291. If an error occurs during the exection of one of these routines, it will
  2292. return with the carry flag set and with the error code in the .A register
  2293. (same as the kernel (yes, I know that Commodore likes to call it the
  2294. "kernAl")).  Error codes 0 to 9 correspond to the standard kernel codes, error
  2295. code 10 means that the device is not a burst device, and error codes 16 to 31
  2296. correspond to the burst controller status codes 0-15.  If no error occurs, the
  2297. routines return with the carry flag clear, of course.
  2298.  
  2299. Only one file may be open at a time for Fastloading, since Fastload takes over
  2300. the disk drive and the entire serial bus.  Even regular files cannot be
  2301. accessed while a fastload is in progress.  Thus, Fastload is not suitable for
  2302. all file processing applications, but it works very well for reading a file
  2303. into memory (like for a text editor) and for summarization operations (like
  2304. word counting).  The burst library requires that the kernel and I/O space be
  2305. in context when it is called.
  2306.  
  2307. 3.1. BURST OPEN
  2308.  
  2309. The way that a burst command is given is to give a magical incantation over
  2310. the command channel to the disk drive.  You can either use the low-level
  2311. serial bus calls (LISTN, SECND, CIOUT, and UNLSN) or use the OPEN and CHROUT
  2312. calls.  I used the low level calls for a little extra zip.
  2313.  
  2314. The burst command format for Fastload is given in the back of your drive
  2315. manual:
  2316.  
  2317. .  BYTE \ bit: 7     6     5     4     3     2     1     0  | Value
  2318. . -------+--------+-----+-----+-----+-----+-----+-----+-----+-------
  2319. .   0    |     0  |  1  |  0  |  1  |  0  |  1  |  0  |  1  |  "U"
  2320. .   1    |     0  |  0  |  1  |  1  |  0  |  0  |  0  |  0  |  "0"
  2321. .   2    |     P  |  X  |  X  |  1  |  1  |  1  |  1  |  1  |  159
  2322. . 3 - ?? |                     <filename>                   |
  2323. . -------+--------------------------------------------------+-------
  2324.  
  2325. where "X" means "don't case" and "P" means "program".  If the P bit is '0'
  2326. then only program (PRG) files can be loaded, and if it is '1' then sequential
  2327. (SEQ) files can be loaded as well.  The package automatically sets this flag
  2328. for you.  Note that you don't have to do an Inquire Disk or Query Disk Format
  2329. in order to use this command like you have to do with the block reading and
  2330. writing commands.
  2331.  
  2332. If you want to try giving the incantation yourself, enter:
  2333.  
  2334. OPEN1,8,15,"U0"+CHR$(159)+"FILENAME"
  2335.  
  2336. (where "FILENAME" is the name of some file that exists on your disk) on your
  2337. 128 and your disk drive will spring to life and wait for you to read the file
  2338. data.  You can't read the data from BASIC, so to cancel the command:
  2339.  
  2340. CLOSE1
  2341.  
  2342. The "burstOpen" call of this package accepts the name of the file to be loaded
  2343. at the start of the "burstBuf" buffer, the length of the filename in the .X
  2344. register, and the device number to load the file from in the .A register.  The
  2345. burst command header and the filename are sent to the disk drive as described
  2346. above.
  2347.  
  2348. The open command also reads the first sector of the file, for two reasons.
  2349. First, the status byte returned for the first sector has special meaning.
  2350. Status code $02 means "file not found".  The package translates this into the
  2351. kernel error code.  Second, and most important, there is a bizarre feature
  2352. (read: "bug") in the Fastload command.  If the file to be read is only one
  2353. block long, then the number of bytes reported for the block length is two
  2354. bytes too short.  The following table gives the number of bytes reported and
  2355. the number of actual bytes in the sector:
  2356.  
  2357. . Actual   |    4    |    3    |    2    |    1    |    0    |
  2358. . ---------+---------+---------+---------+---------+---------+
  2359. . Reported |    2    |    1    |    0    |   255   |   255   |
  2360.  
  2361. This is where I ran into problems with Zed-128; the logic of my program
  2362. screwed up on a zero length.  I have corrected the problem here, though.  This
  2363. bug is bizarre because it only happens if the first sector is the only sector
  2364. in the file.  The reported length for all subsequent sectors is correct.  Note
  2365. also that 255 is reported for lengths of both 1 and 0.  This is because there
  2366. is no actual zero length for Commodore files.  If you OPEN1,8,2,"EMPTY" and
  2367. then immediately CLOSE1 you get a file with one carriage return character in
  2368. it.
  2369.  
  2370. The open routine calls the read routine to read a sector and if it was the
  2371. only sector of the file, the two additional bytes are burst-read and put into
  2372. the data buffer.  Note that incrementing the reported count of 255 twice gives
  2373. the correct count of 1.  Also interesting in this case is that when the
  2374. 1571/81 reports the 255, it actually transfers 255 bytes of data, all of which
  2375. are bogus.  It seems to me that they made the 1581 bug-compatible with the
  2376. 1571 in this respect.
  2377.  
  2378. The open routine also executes a SEI for reasons discussed above.  The
  2379. information returned by the open call is the same as what is returned for the
  2380. "burstRead" call discussed next.
  2381.  
  2382. 3.2. BURST READ
  2383.  
  2384. Once the Fastload command is started, the drive starts waiting to transfer the
  2385. data to you.  The transfer occurs sector by sector, with each sector preceeded
  2386. by a burst status byte.  The data is transferred using the shift register of
  2387. CIA#1 and the handshaking is done using the Slow Serial Clock line of CIA#2.
  2388. To receive a byte, you toggle the Slow Serial Clock line and wait for the
  2389. Shift Register Ready signal from CIA#1 and then read the data value from the
  2390. shift data register.
  2391.  
  2392. One of the clock registers in the CIA in the 1571/81 is used as the baud rate
  2393. generator for the serial line.  I think that it uses a delay of 4 microseconds
  2394. per bit, which gives a baud rate of 250,000 (31.25K/sec).  In my
  2395. experimentation, the maximum baud rate I have ever achieved in reality is
  2396. 200,000 (25K/sec).  I read in my 1571 Internals book that the 250,000 baud
  2397. rate cannot actually be achieved because of electrical problems that I don't
  2398. understand.  This is an important difference because the data comes flying off
  2399. the surface of the disk at around 30K/sec and if the serial bus were fast
  2400. enough, it could be transferred to the computer as it is being read.  Some
  2401. things would be so much more convenient if whomever created the universe had
  2402. thought to make light go just a little bit faster.
  2403.  
  2404. The burst handshaking protocol slows the maximum transfer rate down to about
  2405. 16K/sec.  Of course, the disk drive has more things to keep on top of than
  2406. just transferring data, so the actual burst throughput is lower than that:
  2407. about 5.4K/sec with my JiffyDOS-ified 1571 and about 7K/sec with a 1581.  Note
  2408. that you can probably increase your 1571's burst performance a bit by setting
  2409. it to use a sector interleave factor of 4, using the "U0>S"+CHR$(i) burst
  2410. command.  By default, a 1571 writes files with an interleave of 6.
  2411.  
  2412. All of the sectors before the last one will contain 254 bytes of data and the
  2413. last one will contain a specified number of bytes, from 1 to 254.  The status
  2414. code returned for the last sector is value $1F.  In this case, an additional
  2415. byte is sent before the data bytes that tells how many data bytes there will
  2416. be.  This is the value that is bugged for one-sector files as described in the
  2417. last section.  For those who like pictures, here are diagrams of the data
  2418. transferred for a sector:
  2419.  
  2420. .        REGULAR SECTOR                  LAST SECTOR OF FILE
  2421. .     +-------------------+             +--------------------+
  2422. .   0 | Burst Status Byte |           0 | Burst Status = $1F |
  2423. .     +-------------------+             +--------------------+
  2424. .   1 |                   |           1 |   Byte Count = N   |
  2425. . ... +  254 Data Bytes   |             +--------------------+
  2426. . 254 |                   |           2 |                    |
  2427. .     +-------------------+         ... |    N Data Bytes    |
  2428. .                                   N+1 |                    |
  2429. .                                       +--------------------+
  2430.  
  2431. If a sector returns a burst status code other than 0 (ok) or $1F (end), then
  2432. an error has occurred and the disk drive aborts the transfer, closes the burst
  2433. connection, and starts the drive light blinking.
  2434.  
  2435. The "burstRead" call of this package reads the data of the next sector of the
  2436. opened file into the "burstBuf" and returns the "burstStatus" and
  2437. "burstBufCount" (bytes read).  In the event of an error occuring, this routine
  2438. returns with the carry flag set and the translated burst error code in the .A
  2439. register (same as burstOpen).  When the last sector of the file has just been
  2440. read, this routine returns with a value of $1F in the "burstStatus" variable.
  2441.  
  2442. 3.3. BURST CLOSE
  2443.  
  2444. After reading the last data byte of the last sector of the file, the burst
  2445. connection and is closed automatically by the disk drive.  The "burstClose"
  2446. routine is not necessary for communication with the disk drive, but is
  2447. provided for completeness and to clear the interrupt disable bit (CLI) that
  2448. the open routine set to prevent interrupts while burst reading.
  2449.  
  2450. 3.4. PACKAGE USAGE
  2451.  
  2452. The following pseudo-code outlines how a user program is expected to use the
  2453. burst reading package:
  2454.  
  2455. .     jsr put_filename_into_burstBuf
  2456. .     ldx #filename_length
  2457. .     lda #device_number
  2458. .     jsr burstOpen
  2459. .     bcs reportError
  2460. . L1: jsr process_burstBuf_data
  2461. .     lda burstStatus
  2462. .     cmp #$1f
  2463. .     beq L2
  2464. .     jsr burstRead
  2465. .     bcc L1
  2466. .     jsr reportError
  2467. . L2: jsr burstClose
  2468.  
  2469. 4. IMPLEMENTATION
  2470.  
  2471. This section discusses the code that implements the word counting program.  It
  2472. is here in a special form; each code line is preceeded by a few special
  2473. characters and the line number.  The special characters are there to allow you
  2474. to easily extract the assembler code from the rest of this magazine (and all
  2475. of my ugly comments).  On a Unix system, all you have to do is execute the
  2476. following command line (substitute filenames as appropriate):
  2477.  
  2478. grep '^\.%...\!' Hack3 | sed 's/^.%...\!..//' | sed 's/.%...\!//' >wc.asm
  2479.  
  2480.                        
  2481. .%001!  ;Word Count utility using the burst command set's Fastload facility
  2482. .%002!  ;written 92/06/25 by Craig Bruce for C= Hacking Net Magazine
  2483. .%003!
  2484.  
  2485. The code is written for the Buddy assembler and here are a few setup
  2486. directives.
  2487.  
  2488. .%004!  .mem
  2489. .%005!  .bank 15
  2490. .%006!  .org $1c01
  2491. .%007!
  2492. .%008!  ;*** BASIC startup code
  2493. .%009!
  2494.  
  2495. This is what the "10 sys 7200" in BASIC looks like.  It is here so this
  2496. program can be executed with BASIC RUN command.
  2497.  
  2498. .%010!  .word $1c1c
  2499. .%011!  .word 10
  2500. .%012!  .byte $9e
  2501. .%013!  .asc  " 7200 : "
  2502. .%014!  .byte $8f
  2503. .%015!  .asc  " 6502 power!"
  2504. .%016!  .byte 0
  2505. .%017!  .word 0
  2506. .%018!  .word 0
  2507. .%019!
  2508. .%020!  jmp main
  2509. .%021!
  2510. .%022!  ;========== burst read library ==========
  2511. .%023!
  2512. .%024!  burstStatus = $fe
  2513. .%025!  burstBufCount = $ff
  2514. .%026!  burstBuf = $b00
  2515.  
  2516. "serialFlag" is used to determine whether a device is Fast or not, and the
  2517. "ioStatus" (a.k.a. "ST") is to tell if a device is present or not.
  2518.  
  2519. .%027!  serialFlag = $a1c
  2520. .%028!  ioStatus = $90
  2521.  
  2522. "ciaIcr" is the interrupt control register of CIA#1.  It is polled to wait for
  2523. data becoming available in the shift register ("ciaData").  "ciaSerialClk" is
  2524. the Slow serial bus clock line that is used for handshaking on the Fast bus.
  2525.  
  2526. .%029!  ciaIcr = $dc0d
  2527. .%030!  ciaSerialClk = $dd00
  2528. .%031!  ciaData = $dc0c
  2529. .%032!
  2530. .%033!  kernelListen = $ffb1
  2531. .%034!  kernelSecond = $ff93
  2532. .%035!  kernelCiout  = $ffa8
  2533. .%036!  kernelUnlsn  = $ffae
  2534. .%037!  kernelSpinp  = $ff47
  2535. .%038!
  2536.  
  2537. This is the error code value this package returns if it detects that a device
  2538. is not Fast.
  2539.  
  2540. .%039!  errNotBurstDevice = 10
  2541. .%040!
  2542. .%041!  burstFilenameLen = burstBufCount
  2543. .%042!
  2544. .%043!  burstOpen = * ;(.A=Device, burstBuf=Filename, .X=NameLen):<first block>
  2545.  
  2546. Set up for a burst open: clear the Fast flag and the device not present flag.
  2547.  
  2548. .%044!     stx burstFilenameLen
  2549. .%045!     pha
  2550. .%046!     lda serialFlag
  2551. .%047!     and #%10111111
  2552. .%048!     sta serialFlag
  2553. .%049!     lda #0
  2554. .%050!     sta ioStatus
  2555. .%051!     pla
  2556.  
  2557. Command the disk device to Listen.  Then check if the device is present or not
  2558. (bit 7 of ioStatus).  If not present, return the kernel error code.
  2559.  
  2560. .%052!     jsr kernelListen
  2561. .%053!     bit ioStatus
  2562. .%054!     bpl +
  2563. .%055!
  2564. .%056!     devNotPresent = *
  2565. .%057!     jsr kernelUnlsn
  2566. .%058!     lda #5
  2567. .%059!     sec
  2568. .%060!     rts
  2569. .%061!
  2570.  
  2571. Tell disk device to listen on the command channel (channel #15).
  2572.  
  2573. .%062!  +  lda #$6f
  2574. .%063!     jsr kernelSecond
  2575.  
  2576. Send the "U0"+CHR$(159) burst command header.
  2577.  
  2578. .%064!     lda #"u"
  2579. .%065!     jsr kernelCiout
  2580. .%066!     bit ioStatus
  2581. .%067!     bmi devNotPresent
  2582. .%068!     lda #"0"
  2583. .%069!     jsr kernelCiout
  2584. .%070!     lda #$9f
  2585. .%071!     jsr kernelCiout
  2586.  
  2587. Send the filename.
  2588.  
  2589. .%072!     ldy #0
  2590. .%073!  -  lda burstBuf,y
  2591. .%074!     jsr kernelCiout
  2592. .%075!     iny
  2593. .%076!     cpy burstFilenameLen
  2594. .%077!     bcc -
  2595.  
  2596. Finish sending the burst command and make sure the device is Fast.
  2597.  
  2598. .%078!     jsr kernelUnlsn
  2599. .%079!     lda serialFlag
  2600. .%080!     and #$40
  2601. .%081!     bne +
  2602. .%082!     sec
  2603. .%083!     lda #errNotBurstDevice
  2604. .%084!     rts
  2605. .%085!
  2606.  
  2607. Disable interrupts.
  2608.  
  2609. .%086!  +  sei
  2610.  
  2611. Prepare to receive data and signal the disk drive to start sending (by
  2612. toggling the slow serial Clock line).
  2613.  
  2614. .%087!     clc
  2615. .%088!     jsr kernelSpinp
  2616. .%089!     bit ciaIcr
  2617. .%090!     lda ciaSerialClk
  2618. .%091!     eor #$10
  2619. .%092!     sta ciaSerialClk
  2620.  
  2621. Read the first sector of the file.
  2622.  
  2623. .%093!     jsr burstRead
  2624.  
  2625. Check for errors.  Burst error code 2 (file not found) is translated to its
  2626. kernel equivalent.
  2627.  
  2628. .%094!     lda burstStatus
  2629. .%095!     cmp #2
  2630. .%096!     bcc +
  2631. .%097!     bne shortFile
  2632. .%098!     sec
  2633. .%099!     lda #4
  2634. .%100!  +  rts
  2635. .%101!
  2636.  
  2637. Check if this is a one-block file.
  2638.  
  2639. .%102!     shortFile = *
  2640. .%103!     cmp #$1f
  2641. .%104!     bne openError
  2642. .%105!     ldy burstBufCount
  2643. .%106!     ldx #2
  2644. .%107!
  2645.  
  2646. If so, we have to read the two bytes that the disk drive forgot to tell us
  2647. about.  For each byte, we wait for for the Shift Register Ready signal, toggle
  2648. the clock, and read the shift data register.  I can get away with reading the
  2649. data register after sending the acknowledge signal to the disk drive because I
  2650. am running with interrupts disabled and it could not possibly send the next
  2651. byte before I pick up the current one.  We wouldn't want any NMIs happening
  2652. while doing this, though.
  2653.  
  2654. .%108!     shortFileByte = *
  2655. .%109!     lda #$08
  2656. .%110!  -  bit ciaIcr
  2657. .%111!     beq -
  2658. .%112!     lda ciaSerialClk
  2659. .%113!     eor #$10
  2660. .%114!     sta ciaSerialClk
  2661. .%115!     lda ciaData
  2662. .%116!     sta burstBuf,y
  2663. .%117!     iny
  2664. .%118!     dex
  2665. .%119!     bne shortFileByte
  2666.  
  2667. Store the updated byte count and exit.
  2668.  
  2669. .%120!     sty burstBufCount
  2670. .%121!     clc
  2671. .%122!     rts
  2672. .%123!
  2673.  
  2674. In the event of a burst error, re-enable the interrupts since the user might
  2675. not call the burstClose routine.  Return the translated error code.
  2676.  
  2677. .%124!     openError = *
  2678. .%125!     cli
  2679. .%126!     sec
  2680. .%127!     ora #$10
  2681. .%128!     rts
  2682. .%129!
  2683.  
  2684. Read the next sector of the file.
  2685.  
  2686. .%130!  burstRead = * ;( ) : burstBuf, burstBufCount, burstStatus
  2687.  
  2688. Wait for the status byte to arrive.
  2689.  
  2690. .%131!     lda #8
  2691. .%132!  -  bit ciaIcr
  2692. .%133!     beq -
  2693.  
  2694. Toggle clock line for acknowledge.
  2695.  
  2696. .%134!     lda ciaSerialClk
  2697. .%135!     eor #$10
  2698. .%136!     sta ciaSerialClk
  2699.  
  2700. Get status byte and check.  If 2 or more and not $1F, then an error has
  2701. occurred.  If 0, then prepare to read 254 data bytes.
  2702.  
  2703. .%137!     lda ciaData
  2704. .%138!     sta burstStatus
  2705. .%139!     ldx #254
  2706. .%140!     cmp #2
  2707. .%141!     bcc actualRead
  2708. .%142!     cmp #$1f
  2709. .%143!     bne openError
  2710.  
  2711. If status byte is $1F, then get the next byte, which tells how many data bytes
  2712. are to follow.
  2713.  
  2714. .%144!     lda #8
  2715. .%145!  -  bit ciaIcr
  2716. .%146!     beq -
  2717. .%147!     ldx ciaData
  2718. .%148!     lda ciaSerialClk
  2719. .%149!     eor #$10
  2720. .%150!     sta ciaSerialClk
  2721. .%151!
  2722. .%152!     actualRead = *
  2723. .%153!     stx burstBufCount
  2724. .%154!     ldy #0
  2725. .%155!
  2726.  
  2727. Read the data bytes and put them into the burst buffer.  The clock line toggle
  2728. value is computed before receiving the data for a little extra zip.  I haven't
  2729. experimented with this, but you might be able to toggle the clock line before
  2730. receiving the data (however, probably not for the first byte).
  2731.  
  2732. .%156!     readByte = *
  2733. .%157!     lda ciaSerialClk
  2734. .%158!     eor #$10
  2735. .%159!     tax
  2736. .%160!     lda #8
  2737. .%161!  -  bit ciaIcr
  2738. .%162!     beq -
  2739. .%163!     stx ciaSerialClk
  2740. .%164!     lda ciaData
  2741. .%165!     sta burstBuf,y
  2742. .%166!     iny
  2743. .%167!     cpy burstBufCount
  2744. .%168!     bne readByte
  2745. .%169!  +  clc
  2746. .%170!     rts
  2747. .%171!
  2748.  
  2749. Close the burst package: simply CLI.
  2750.  
  2751. .%172!  burstClose = *
  2752. .%173!     cli
  2753. .%174!     clc
  2754. .%175!     rts
  2755. .%176!
  2756. .%177!  ;========== main program ==========
  2757. .%178!
  2758.  
  2759. This is the word counting application code.
  2760.  
  2761. .%179!  bkWC = $0e
  2762. .%180!  bkSelect = $ff00
  2763. .%181!  kernelChrin  = $ffcf
  2764. .%182!  kernelChrout = $ffd2
  2765. .%183!
  2766.  
  2767. The "wcInWord" is a boolean variable that tells whether the file scanner is
  2768. currently in a word or not.  The Lines, Words, and Bytes are 24-bit counters.
  2769.  
  2770. .%184!  wcInWord = 2 ;(1)
  2771. .%185!  wcLines = 3  ;(3)
  2772. .%186!  wcWords = 6  ;(3)
  2773. .%187!  wcBytes = 9  ;(3)
  2774. .%188!
  2775. .%189!  main = *
  2776.  
  2777. Put the kernel ROM and I/O space into context then initialize the counting
  2778. variables.
  2779.  
  2780. .%190!     lda #bkWC
  2781. .%191!     sta bkSelect
  2782. .%192!     jsr wcInit
  2783.  
  2784. Follow the burst reading procedure outline.
  2785.  
  2786. .%193!     jsr wcGetFilename
  2787. .%194!     jsr burstOpen
  2788. .%195!     bcc +
  2789. .%196!     jsr reportError
  2790. .%197!     rts
  2791. .%198!  /  jsr wcScanBuffer
  2792. .%199!     lda burstStatus
  2793. .%200!     cmp #$1f
  2794. .%201!     beq +
  2795. .%202!     jsr burstRead
  2796. .%203!     bcc -
  2797. .%204!     jsr reportError
  2798. .%205!  +  jsr burstClose
  2799.  
  2800. Report the numbers of lines, words, and characters and then exit.
  2801.  
  2802. .%206!     jsr wcReport
  2803. .%207!     rts
  2804. .%208!
  2805.  
  2806. Initialize the variables.
  2807.  
  2808. .%209!  wcInit = *
  2809. .%210!     lda #0
  2810. .%211!     ldx #8
  2811. .%212!  -  sta wcLines,x
  2812. .%213!     dex
  2813. .%214!     bpl -
  2814. .%215!     sta wcInWord
  2815. .%216!     rts
  2816. .%217!
  2817.  
  2818. Get the device and filename from the user.  Returns parameters suitable for
  2819. passing to burstOpen.
  2820.  
  2821. .%218!  wcGetFilename = * ;() : burstBuf=Filename, .A=Device, .X=FilenameLen
  2822.  
  2823. Display the prompt.
  2824.  
  2825. .%219!     ldx #0
  2826. .%220!  -  lda promptMsg,x
  2827. .%221!     beq +
  2828. .%222!     jsr kernelChrout
  2829. .%223!     inx
  2830. .%224!     bne -
  2831.  
  2832. Get the input line from the user.
  2833.  
  2834. .%225!  +  ldx #0
  2835. .%226!  -  jsr kernelChrin
  2836. .%227!     sta burstBuf,x
  2837. .%228!     cmp #13
  2838. .%229!     beq +
  2839. .%230!     inx
  2840. .%231!     bne -
  2841. .%232!  +  jsr kernelChrout
  2842.  
  2843. Extract the device number from the start of the input line.  If it is not
  2844. there, assume device number 8.
  2845.  
  2846. .%233!     lda #8
  2847. .%234!     cpx #2
  2848. .%235!     bcc filenameExit
  2849. .%236!     ldy burstBuf+1
  2850. .%237!     cpy #":"
  2851. .%238!     bne filenameExit
  2852. .%239!     sec
  2853. .%240!     lda burstBuf
  2854. .%241!     sbc #"a"-8
  2855. .%242!     tay
  2856.  
  2857. If a device name was present, then we have to move the rest of the filename
  2858. back over it now that we've extracted it.
  2859.  
  2860. .%243!     ldx #0
  2861. .%244!  -  lda burstBuf+2,x
  2862. .%245!     sta burstBuf,x
  2863. .%246!     cmp #13
  2864. .%247!     beq +
  2865. .%248!     inx
  2866. .%249!     bne -
  2867. .%250!  +  tya
  2868. .%251!     filenameExit = *
  2869. .%252!     rts
  2870. .%253!
  2871. .%254!     promptMsg = *
  2872. .%255!     .asc "enter filename in form filename, or a:filename, "
  2873. .%256!     .asc "or b:filename, ..."
  2874. .%257!     .byte 13
  2875. .%258!     .asc "where 'a' is for device 8, 'b' is for device 9, ..."
  2876. .%259!     .byte 13,0
  2877. .%260!
  2878.  
  2879. Scan the burst buffer after reading a sector into it.
  2880.  
  2881. .%261!  wcScanBuffer = *
  2882. .%262!     ldy #0
  2883. .%263!     cpy burstBufCount
  2884. .%264!     bne +
  2885. .%265!     rts
  2886. .%266!  +  ldx wcInWord
  2887. .%267!  -  lda burstBuf,y
  2888. .%268!  ;   jsr kernelChrout  ;uncomment this line to echo the data read
  2889. .%269!     cmp #13
  2890. .%270!     bne +
  2891.  
  2892. If the current character is a carriage return, then increment the line count.
  2893.  
  2894. .%271!     inc wcLines
  2895. .%272!     bne +
  2896. .%273!     inc wcLines+1
  2897. .%274!     bne +
  2898. .%275!     inc wcLines+2
  2899.  
  2900. If the character is a TAB, SPACE, or a RETURN, then it is a Delimiter;
  2901. otherwise, it is considered a Letter.
  2902.  
  2903. .%276!  +  cmp #33
  2904. .%277!     bcs isLetter
  2905. .%278!     cmp #" "
  2906. .%279!     beq isDelimiter
  2907. .%280!     cmp #13
  2908. .%281!     beq isDelimiter
  2909. .%282!     cmp #9
  2910. .%283!     beq isDelimiter
  2911. .%284!
  2912. .%285!     isLetter = *
  2913.  
  2914. If the character is a Letter and the previous one was a Delimiter, then
  2915. increment the word count.
  2916.  
  2917. .%286!     cpx #1
  2918. .%287!     beq scanCont
  2919. .%288!     ldx #1
  2920. .%289!     inc wcWords
  2921. .%290!     bne scanCont
  2922. .%291!     inc wcWords+1
  2923. .%292!     bne scanCont
  2924. .%293!     inc wcWords+2
  2925. .%294!     jmp scanCont
  2926. .%295!
  2927. .%296!     isDelimiter = *
  2928. .%297!     ldx #0
  2929. .%298!
  2930. .%299!     scanCont = *
  2931. .%300!     iny
  2932. .%301!     cpy burstBufCount
  2933. .%302!     bcc -
  2934.  
  2935. Add the number of bytes in the burst buffer to the total byte count for the
  2936. file.
  2937.  
  2938. .%303!     clc
  2939. .%304!     lda wcBytes
  2940. .%305!     adc burstBufCount
  2941. .%306!     sta wcBytes
  2942. .%307!     bcc +
  2943. .%308!     inc wcBytes+1
  2944. .%309!     bne +
  2945. .%310!     inc wcBytes+2
  2946. .%311!  +  stx wcInWord
  2947. .%312!     rts
  2948. .%313!
  2949.  
  2950. Report the number of lines, words, and bytes read.  Uses a "printf" type of
  2951. scheme.
  2952.  
  2953. .%314!  wcReport = *
  2954. .%315!     ldx #0
  2955. .%316!  -  lda reportMsg,x
  2956. .%317!     beq reportExit
  2957. .%318!     cmp #13
  2958. .%319!     bcs +
  2959. .%320!     stx 14
  2960. .%321!     tax
  2961. .%322!     lda 2,x
  2962. .%323!     sta 15
  2963. .%324!     lda 0,x
  2964. .%325!     ldy 1,x
  2965. .%326!     ldx 15
  2966. .%327!     jsr putnum
  2967. .%328!     ldx 14
  2968. .%329!     jmp reportCont
  2969. .%330!  +  jsr kernelChrout
  2970. .%331!     reportCont = *
  2971. .%332!     inx
  2972. .%333!     bne -
  2973. .%334!     reportExit = *
  2974. .%335!     rts
  2975. .%336!
  2976. .%337!     reportMsg = *
  2977. .%338!     .byte 13
  2978. .%339!     .asc "lines="
  2979. .%340!     .byte wcLines
  2980. .%341!     .asc ", words="
  2981. .%342!     .byte wcWords
  2982. .%343!     .asc ", chars="
  2983. .%344!     .byte wcBytes,27
  2984. .%345!     .asc "q"
  2985. .%346!     .byte 13,0
  2986. .%347!
  2987.  
  2988. Reports the error number given in the .A register.  Called after an error is
  2989. returned from a burst routine.
  2990.  
  2991. .%348!  reportError = * ;( .A=errNum )
  2992. .%349!     pha
  2993. .%350!     ldx #0
  2994. .%351!  -  lda errorMsg,x
  2995. .%352!     beq +
  2996. .%353!     jsr kernelChrout
  2997. .%354!     inx
  2998. .%355!     bne -
  2999. .%356!  +  pla
  3000. .%357!     ldy #0
  3001. .%358!     ldx #0
  3002. .%359!     jsr putnum
  3003. .%360!     lda #13
  3004. .%361!     jsr kernelChrout
  3005. .%362!     rts
  3006. .%363!
  3007. .%364!     errorMsg = *
  3008. .%365!     .asc "*** i/o error #"
  3009. .%366!     .byte 0
  3010. .%367!
  3011. .%368!  ;==========library==========
  3012. .%369!
  3013.  
  3014. Routine to print out the 24-bit number given in .AYX.
  3015.  
  3016. .%370!  libwork = $60
  3017. .%371!  itoaBin = libwork
  3018. .%372!  itoaBcd = libwork+3
  3019. .%373!  itoaFlag = libwork+7
  3020. .%374!
  3021. .%375!  putnum = *
  3022.  
  3023. Initialize binary and BCD (Binary Coded Decimal) representations of number.
  3024.  
  3025. .%376!     sta itoaBin+0
  3026. .%377!     sty itoaBin+1
  3027. .%378!     stx itoaBin+2
  3028. .%379!     ldx #3
  3029. .%380!     lda #0
  3030. .%381!  -  sta itoaBcd,x
  3031. .%382!     dex
  3032. .%383!     bpl -
  3033. .%384!     sta itoaFlag
  3034. .%385!     ldy #24
  3035. .%386!     sed
  3036. .%387!
  3037.  
  3038. Rotate each bit out of the binary number and then multiply the BCD number by
  3039. two and add the bit in.  Effectively, we are shifting the bits out of the
  3040. binary number and into the BCD representation of the number.
  3041.  
  3042. .%388!     itoaNextBit = *
  3043. .%389!     asl itoaBin+0
  3044. .%390!     rol itoaBin+1
  3045. .%391!     rol itoaBin+2
  3046. .%392!     ldx #3
  3047. .%393!  -  lda itoaBcd,x
  3048. .%394!     adc itoaBcd,x
  3049. .%395!     sta itoaBcd,x
  3050. .%396!     dex
  3051. .%397!     bpl -
  3052. .%398!     dey
  3053. .%399!     bne itoaNextBit
  3054. .%400!     cld
  3055.  
  3056. Take the BCD bytes and spit out the two digits they contain.
  3057.  
  3058. .%401!     ldx #0
  3059. .%402!     ldy #0
  3060. .%403!  -  lda itoaBcd,x
  3061. .%404!     jsr itoaPutHex
  3062. .%405!     inx
  3063. .%406!     cpx #4
  3064. .%407!     bcc -
  3065. .%408!     rts
  3066. .%409!
  3067. .%410!     itoaPutHex = *
  3068. .%411!     pha
  3069. .%412!     lsr
  3070. .%413!     lsr
  3071. .%414!     lsr
  3072. .%415!     lsr
  3073. .%416!     jsr itoaPutDigit
  3074. .%417!     pla
  3075. .%418!     and #$0f
  3076. .%419!
  3077.  
  3078. Print out the individual digits of the number.  If the current digit is zero
  3079. and all digits so far have been zero, then don't output anything, unless it is
  3080. the last digit of the number.
  3081.  
  3082. .%420!     itoaPutDigit = *
  3083. .%421!     cmp itoaFlag
  3084. .%422!     bne +
  3085. .%423!     cpy #7
  3086. .%424!     bcc itoaPutDigitExit
  3087. .%425!  +  ora #$30
  3088. .%426!     sta itoaFlag
  3089. .%427!     jsr kernelChrout
  3090. .%428!     itoaPutDigitExit = *
  3091. .%429!     iny
  3092. .%430!     rts
  3093.  
  3094. 5. UUENCODED PROGRAM
  3095.  
  3096. Here is the binary executable in uuencoded form.  The CRC32 of it is
  3097. 3676144922.  LOAD and RUN it like a regular BASIC program.
  3098.  
  3099. begin 640 wc
  3100. M`1P<'`H`GB`W,C`P(#H@CR`V-3`R(%!/5T52(0``````3!$=AO](K1P**;^-
  3101. M'`JI`(60:""Q_R20$`<@KO^I!3A@J6\@D_^I52"H_R20,.NI,""H_ZF?(*C_
  3102. MH`"Y``L@J/_(Q/^0]2"N_ZT<"BE`T`0XJ0I@>!@@1_\L#=RM`-U)$(T`W2"]
  3103. M'*7^R0*0!=`$.*D$8,D?T"&D_Z("J0@L#=SP^ZT`W4D0C0#=K0S<F0`+R,K0
  3104. MYX3_&&!8.`D08*D(+`W<\/NM`-U)$(T`W:T,W(7^HO[)`I`6R1_0W:D(+`W<
  3105. M\/NN#-RM`-U)$(T`W8;_H`"M`-U)$*JI""P-W/#[C@#=K0S<F0`+R,3_T.48
  3106. M8%@88*D.C0#_(#T=($D=(",<D`0@H!Y@(`4>I?[)'_`((+T<D/(@H!X@#AT@
  3107. M6QY@J0"B")4#RA#[A0)@H@"]C1WP!B#2_^C0]:(`(,__G0`+R0WP`^C0\R#2
  3108. MLZD(X`*0'JP!"\`ZT!<XK0`+Z3FHH@"]`@N=``O)#?`#Z-#SF&!%3E1%4B!&
  3109. M24Q%3D%-12!)3B!&3U)-($9)3$5.04U%+"!/4B!!.D9)3$5.04U%+"!/4B!"
  3110. M.D9)3$5.04U%+"`N+BX-5TA%4D4@)T$G($E3($9/4B!$159)0T4@."P@)T(G
  3111. M($E3($9/4B!$159)0T4@.2P@+BXN#0"@`,3_T`%@I@*Y``O)#=`*Y@/0!N8$
  3112. MT`+F!<DAL`S)(/`;R0WP%\D)\!/@`?`1H@'F!M`+Y@?0!^8(3$0>H@#(Q/^0
  3113. MQ1BE"67_A0F0!N8*T`+F"X8"8*(`O8(>\!_)#;`5A@ZJM0*%#[4`M`&F#R#,
  3114. M'J8.3'X>(-+_Z-#<8`U,24Y%4ST#+"!73U)$4ST&+"!#2$%24ST)&U$-`$BB
  3115. M`+V\'O`&(-+_Z-#U:*``H@`@S!ZI#2#2_V`J*BH@22]/($524D]2(",`A6"$
  3116. M889BH@.I`)5CRA#[A6>@&/@&8"9A)F*B`[5C=6.58\H0]XC0[-BB`*``M6,@
  3117. D!!_HX`20]F!(2DI*2B`/'V@I#\5GT`3`!Y`'"3"%9R#2_\A@````
  3118. `
  3119. end
  3120.  
  3121. 6. REFERENCES
  3122.  
  3123. [1] Commodore Business Machines, _Commodore_1571_Disk_Drive_User's_Guide_,
  3124.     CBM, 1985.
  3125.  
  3126. [2] Rainer Ellinger, _1571_Internals_, Abacus Software, June 1986.
  3127.  
  3128. ===============================================================================
  3129. Next Issue: (hopefully!)
  3130.  
  3131. Learning ML - Part 4
  3132.  
  3133.   In the next issue we'll embark on a project of making a space invaders style
  3134. game for the C=64/128 using the KERNAL routines we've learned.
  3135.  
  3136. The Demo Corner: FLI - more color to the screen
  3137.  
  3138.   All of us have heard complaints about the color constraints on C64.
  3139. FLI picture can have all of the 16 colors in one char position. What then
  3140. is this FLI and how it is done ?
  3141.  
  3142. The 1351 Mouse Demystified
  3143.  
  3144.   An indepth look at how the 1351 mouse operates and how to access it within
  3145. your own ML programs.  For Basic programmers, a driver for the 80 column screen
  3146. is also supplied. 
  3147.  
  3148. LITTLE RED READER: MS-DOS file reader for the 128 and 1571/81 drives.
  3149.  
  3150. This article will present a package that reads MS-DOS files and the root
  3151. directory of MS-DOS disks.  This package will use the dynamic memory allocation
  3152. package introduced in Hacking Issue #2 to allow large files to be read in.
  3153. The application-level code hasn't been finalized yet, but it will probably use
  3154. a menu-oriented full-screen display and will read and translate MS-DOS and
  3155. Commodore files. 
  3156. =============================================================================
  3157. END of Commodore Hacking Issue 3.
  3158. =============================================================================
  3159.  
  3160.